mtcli 3.8.0.dev8__tar.gz → 3.8.0.dev10__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/PKG-INFO +1 -1
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/database.py +1 -1
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/marketdata/tick_engine.py +4 -5
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/marketdata/tick_repository.py +5 -6
- mtcli-3.8.0.dev10/mtcli/migrations/007_deduplicate_ticks_and_add_unique_index.py +91 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/pyproject.toml +1 -1
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/LICENSE +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/README.md +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/__main__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/cli.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/cli_dev.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/commands/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/commands/bars.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/commands/conf.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/commands/doctor.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/commands/ticks.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/commands_dev/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/commands_dev/migrate.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/conecta.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/conf.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/config_registre.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/data/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/data/base.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/data/csv.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/data/mt5.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/domain/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/domain/timeframe.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/logger.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/marketdata/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/marketdata/tick_cache.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/migrations/001_initial_schema.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/migrations/002_ticks_time_msc.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/migrations/003_optimize_ticks_without_rowid.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/migrations/004_ticks_pk_time_msc.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/migrations/005_tick_price_compression.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/migrations/006_add_index_ticks_symbol_time.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/migrations/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/migrations/__main__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/migrations/runner.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/models/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/models/bar_model.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/models/bars_model.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/models/chart_model.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/models/conf_model.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/models/consecutive_bars_model.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/models/rates_model.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/models/signals_model.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/models/unconsecutive_bar_model.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/mt5_context.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugin.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugin_loader.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugin_manager.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/exemplo.py-dist +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/media_movel/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/media_movel/cli.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/media_movel/conf.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/media_movel/models/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/media_movel/models/model_media_movel.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/media_movel/tests/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/media_movel/tests/test_mm.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/media_movel/tests/test_model_media_movel.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/range_medio/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/range_medio/cli.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/range_medio/conf.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/range_medio/models/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/range_medio/models/average_range_model.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/range_medio/tests/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/range_medio/tests/test_rm.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/volume_medio/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/volume_medio/cli.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/volume_medio/conf.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/volume_medio/models/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/volume_medio/models/model_average_volume.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/volume_medio/tests/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/volume_medio/tests/test_vm.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/views/__init__.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/views/close_view.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/views/full_view.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/views/high_view.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/views/low_view.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/views/min_view.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/views/open_view.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/views/ranges_view.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/views/rates_view.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/views/vars_view.py +0 -0
- {mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/views/volumes_view.py +0 -0
|
@@ -41,7 +41,7 @@ def get_connection():
|
|
|
41
41
|
conn.execute("PRAGMA journal_mode=WAL")
|
|
42
42
|
conn.execute("PRAGMA synchronous=NORMAL")
|
|
43
43
|
conn.execute("PRAGMA temp_store=MEMORY")
|
|
44
|
-
conn.execute("PRAGMA mmap_size=
|
|
44
|
+
conn.execute("PRAGMA mmap_size=30000000000")
|
|
45
45
|
conn.execute("PRAGMA cache_size=-200000")
|
|
46
46
|
conn.execute("PRAGMA journal_size_limit=67108864")
|
|
47
47
|
conn.execute("PRAGMA read_uncommitted = TRUE")
|
|
@@ -20,9 +20,9 @@ from .tick_repository import TickRepository
|
|
|
20
20
|
|
|
21
21
|
class TickEngine:
|
|
22
22
|
|
|
23
|
-
POLL_INTERVAL = 0.
|
|
23
|
+
POLL_INTERVAL = 0.05
|
|
24
24
|
BATCH_SIZE = 1000
|
|
25
|
-
OVERLAP_MS =
|
|
25
|
+
OVERLAP_MS = 20
|
|
26
26
|
|
|
27
27
|
def __init__(self, symbols):
|
|
28
28
|
|
|
@@ -68,7 +68,6 @@ class TickEngine:
|
|
|
68
68
|
|
|
69
69
|
repo = self.repositories[symbol]
|
|
70
70
|
|
|
71
|
-
# sincroniza histórico
|
|
72
71
|
repo.sync(symbol)
|
|
73
72
|
|
|
74
73
|
last_msc = repo._get_last_tick_msc(symbol)
|
|
@@ -92,7 +91,7 @@ class TickEngine:
|
|
|
92
91
|
last_msc = last_positions[symbol]
|
|
93
92
|
|
|
94
93
|
start_dt = datetime.fromtimestamp(
|
|
95
|
-
(last_msc - self.OVERLAP_MS)
|
|
94
|
+
(last_msc - self.OVERLAP_MS) * 0.001
|
|
96
95
|
)
|
|
97
96
|
|
|
98
97
|
while True:
|
|
@@ -127,7 +126,7 @@ class TickEngine:
|
|
|
127
126
|
last_positions[symbol] = last_msc + 1
|
|
128
127
|
|
|
129
128
|
start_dt = datetime.fromtimestamp(
|
|
130
|
-
(last_msc - self.OVERLAP_MS)
|
|
129
|
+
(last_msc - self.OVERLAP_MS) * 0.001
|
|
131
130
|
)
|
|
132
131
|
|
|
133
132
|
if len(ticks) < self.BATCH_SIZE:
|
|
@@ -45,7 +45,7 @@ class TickRepository:
|
|
|
45
45
|
last_msc = self._get_last_tick_msc(symbol)
|
|
46
46
|
|
|
47
47
|
if last_msc:
|
|
48
|
-
start = datetime.fromtimestamp((last_msc + 1)
|
|
48
|
+
start = datetime.fromtimestamp((last_msc + 1) * 0.001)
|
|
49
49
|
else:
|
|
50
50
|
start = end - timedelta(days=days_back)
|
|
51
51
|
|
|
@@ -99,7 +99,7 @@ class TickRepository:
|
|
|
99
99
|
|
|
100
100
|
scale = self.PRICE_SCALE
|
|
101
101
|
|
|
102
|
-
data =
|
|
102
|
+
data = (
|
|
103
103
|
(
|
|
104
104
|
symbol,
|
|
105
105
|
int(t["time_msc"]),
|
|
@@ -110,11 +110,11 @@ class TickRepository:
|
|
|
110
110
|
int(t["flags"]),
|
|
111
111
|
)
|
|
112
112
|
for t in ticks
|
|
113
|
-
|
|
113
|
+
)
|
|
114
114
|
|
|
115
115
|
cursor.executemany(
|
|
116
116
|
"""
|
|
117
|
-
INSERT INTO ticks(
|
|
117
|
+
INSERT OR IGNORE INTO ticks(
|
|
118
118
|
symbol,
|
|
119
119
|
time_msc,
|
|
120
120
|
bid,
|
|
@@ -124,12 +124,11 @@ class TickRepository:
|
|
|
124
124
|
flags
|
|
125
125
|
)
|
|
126
126
|
VALUES (?,?,?,?,?,?,?)
|
|
127
|
-
ON CONFLICT(symbol,time_msc) DO NOTHING
|
|
128
127
|
""",
|
|
129
128
|
data,
|
|
130
129
|
)
|
|
131
130
|
|
|
132
|
-
return
|
|
131
|
+
return cursor.rowcount
|
|
133
132
|
|
|
134
133
|
# ==========================================================
|
|
135
134
|
# CONSULTAS
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Migration 007
|
|
3
|
+
|
|
4
|
+
Objetivo
|
|
5
|
+
--------
|
|
6
|
+
|
|
7
|
+
1. Remover registros duplicados da tabela `ticks`
|
|
8
|
+
2. Criar índice UNIQUE para evitar duplicação futura
|
|
9
|
+
|
|
10
|
+
Critério de unicidade adotado:
|
|
11
|
+
|
|
12
|
+
(symbol, time_msc)
|
|
13
|
+
|
|
14
|
+
Estratégia
|
|
15
|
+
----------
|
|
16
|
+
|
|
17
|
+
1. Criar tabela temporária com SELECT DISTINCT
|
|
18
|
+
2. Copiar dados únicos
|
|
19
|
+
3. Substituir tabela original
|
|
20
|
+
4. Criar índice UNIQUE
|
|
21
|
+
|
|
22
|
+
Essa estratégia é muito mais rápida do que DELETE em tabelas grandes.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from sqlite3 import Connection
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def upgrade(conn: Connection) -> None:
|
|
29
|
+
cursor = conn.cursor()
|
|
30
|
+
|
|
31
|
+
# ---------------------------------------------------------
|
|
32
|
+
# 1 - criar nova tabela sem duplicados
|
|
33
|
+
# ---------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
cursor.execute(
|
|
36
|
+
"""
|
|
37
|
+
CREATE TABLE IF NOT EXISTS ticks_new AS
|
|
38
|
+
SELECT DISTINCT *
|
|
39
|
+
FROM ticks
|
|
40
|
+
"""
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# ---------------------------------------------------------
|
|
44
|
+
# 2 - remover tabela antiga
|
|
45
|
+
# ---------------------------------------------------------
|
|
46
|
+
|
|
47
|
+
cursor.execute("DROP TABLE ticks")
|
|
48
|
+
|
|
49
|
+
# ---------------------------------------------------------
|
|
50
|
+
# 3 - renomear tabela nova
|
|
51
|
+
# ---------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
cursor.execute("ALTER TABLE ticks_new RENAME TO ticks")
|
|
54
|
+
|
|
55
|
+
# ---------------------------------------------------------
|
|
56
|
+
# 4 - recriar índice de performance existente
|
|
57
|
+
# ---------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
cursor.execute(
|
|
60
|
+
"""
|
|
61
|
+
CREATE INDEX IF NOT EXISTS idx_ticks_symbol_time
|
|
62
|
+
ON ticks(symbol, time_msc)
|
|
63
|
+
"""
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# ---------------------------------------------------------
|
|
67
|
+
# 5 - criar índice UNIQUE
|
|
68
|
+
# ---------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
cursor.execute(
|
|
71
|
+
"""
|
|
72
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_ticks_unique
|
|
73
|
+
ON ticks(symbol, time_msc)
|
|
74
|
+
"""
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
conn.commit()
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def downgrade(conn: Connection) -> None:
|
|
81
|
+
cursor = conn.cursor()
|
|
82
|
+
|
|
83
|
+
# Remove índice UNIQUE caso exista rollback
|
|
84
|
+
|
|
85
|
+
cursor.execute(
|
|
86
|
+
"""
|
|
87
|
+
DROP INDEX IF EXISTS idx_ticks_unique
|
|
88
|
+
"""
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
conn.commit()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/media_movel/models/model_media_movel.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/media_movel/tests/test_model_media_movel.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/range_medio/models/average_range_model.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mtcli-3.8.0.dev8 → mtcli-3.8.0.dev10}/mtcli/plugins/volume_medio/models/model_average_volume.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|