mt5cli 1.1.3__tar.gz → 1.1.5__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.
- {mt5cli-1.1.3 → mt5cli-1.1.5}/AGENTS.md +1 -1
- {mt5cli-1.1.3 → mt5cli-1.1.5}/PKG-INFO +33 -33
- {mt5cli-1.1.3 → mt5cli-1.1.5}/README.md +31 -31
- {mt5cli-1.1.3 → mt5cli-1.1.5}/docs/api/history.md +32 -1
- {mt5cli-1.1.3 → mt5cli-1.1.5}/docs/api/public-contract.md +7 -2
- {mt5cli-1.1.3 → mt5cli-1.1.5}/docs/api/sdk.md +2 -2
- {mt5cli-1.1.3 → mt5cli-1.1.5}/docs/api/trading.md +40 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/docs/index.md +18 -18
- {mt5cli-1.1.3 → mt5cli-1.1.5}/mt5cli/__init__.py +2 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/mt5cli/cli.py +42 -7
- {mt5cli-1.1.3 → mt5cli-1.1.5}/mt5cli/contract.py +1 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/mt5cli/history.py +116 -10
- {mt5cli-1.1.3 → mt5cli-1.1.5}/mt5cli/schemas.py +15 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/mt5cli/sdk.py +27 -7
- {mt5cli-1.1.3 → mt5cli-1.1.5}/mt5cli/trading.py +126 -2
- {mt5cli-1.1.3 → mt5cli-1.1.5}/mt5cli/utils.py +1 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/pyproject.toml +2 -2
- {mt5cli-1.1.3 → mt5cli-1.1.5}/tests/test_cli.py +173 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/tests/test_contracts.py +69 -57
- {mt5cli-1.1.3 → mt5cli-1.1.5}/tests/test_history.py +265 -4
- {mt5cli-1.1.3 → mt5cli-1.1.5}/tests/test_sdk.py +101 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/tests/test_trading.py +344 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/tests/test_utils.py +1 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/uv.lock +5 -5
- {mt5cli-1.1.3 → mt5cli-1.1.5}/.agents/skills/local-qa/SKILL.md +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/.agents/skills/local-qa/scripts/qa.sh +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/.agents/skills/mt5cli/SKILL.md +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/.agents/skills/pr-feedback-triage/SKILL.md +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/.claude/agents/codex.md +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/.claude/settings.json +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/.github/FUNDING.yml +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/.github/dependabot.yml +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/.github/renovate.json +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/.github/workflows/ci.yml +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/.github/workflows/claude.yml +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/.github/workflows/opencode.yml +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/.github/workflows/release.yml +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/.gitignore +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/CLAUDE.md +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/LICENSE +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/docs/api/cli.md +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/docs/api/client.md +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/docs/api/converters.md +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/docs/api/exceptions.md +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/docs/api/grafana.md +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/docs/api/index.md +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/docs/api/schemas.md +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/docs/api/telemetry.md +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/docs/api/utils.md +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/examples/grafana/README.md +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/examples/grafana/compose.yml +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/examples/grafana/dashboards/mt5cli-market.json +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/examples/grafana/dashboards/mt5cli-overview.json +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/examples/grafana/dashboards/mt5cli-trades.json +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/examples/grafana/provisioning/dashboards/mt5cli.yml +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/examples/grafana/provisioning/datasources/mt5cli-sqlite.yml +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/mkdocs.yml +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/mt5cli/__main__.py +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/mt5cli/client.py +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/mt5cli/converters.py +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/mt5cli/exceptions.py +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/mt5cli/grafana.py +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/mt5cli/retry.py +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/mt5cli/telemetry.py +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/tests/__init__.py +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/tests/conftest.py +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/tests/test_examples.py +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/tests/test_grafana.py +0 -0
- {mt5cli-1.1.3 → mt5cli-1.1.5}/tests/test_telemetry.py +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Project Structure & Module Organization
|
|
4
4
|
|
|
5
|
-
`mt5cli/` contains the package source. Important modules include `cli.py` for the Typer command-line app, `client.py` and `sdk.py` for public MT5 client/session APIs, `history.py` for SQLite history collection, `
|
|
5
|
+
`mt5cli/` contains the package source. Important modules include `cli.py` for the Typer command-line app, `client.py` and `sdk.py` for public MT5 client/session APIs, `history.py` for SQLite history collection, `trading.py` for trading helpers, `grafana.py` for Grafana schema support, `telemetry.py` for observability, `utils.py` and `converters.py` for export behavior, and `schemas.py` for normalized dataset contracts. `tests/` holds pytest coverage for CLI behavior, SDK contracts, trading helpers, history, and utilities. `docs/` and `mkdocs.yml` define the MkDocs site and API reference. `skills/mt5cli/SKILL.md` documents the mt5cli agent skill.
|
|
6
6
|
|
|
7
7
|
## Build, Test, and Development Commands
|
|
8
8
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mt5cli
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.5
|
|
4
4
|
Summary: Generic MT5 data and execution infrastructure for Python applications
|
|
5
5
|
Project-URL: Repository, https://github.com/dceoy/mt5cli.git
|
|
6
6
|
Author-email: dceoy <dceoy@users.noreply.github.com>
|
|
@@ -18,7 +18,7 @@ Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
|
18
18
|
Requires-Python: <3.14,>=3.11
|
|
19
19
|
Requires-Dist: click>=8.1.0
|
|
20
20
|
Requires-Dist: pandas>=2.2.2
|
|
21
|
-
Requires-Dist: pdmt5>=1.1.
|
|
21
|
+
Requires-Dist: pdmt5>=1.1.1
|
|
22
22
|
Requires-Dist: pydantic>=2.13.4
|
|
23
23
|
Requires-Dist: typer>=0.15.0
|
|
24
24
|
Provides-Extra: otel
|
|
@@ -189,37 +189,37 @@ python -m mt5cli -o account.csv account-info
|
|
|
189
189
|
|
|
190
190
|
## Commands
|
|
191
191
|
|
|
192
|
-
| Command | Description
|
|
193
|
-
| ---------------------- |
|
|
194
|
-
| `rates-from` | Export rates from a start date
|
|
195
|
-
| `rates-from-pos` | Export rates from a start position
|
|
196
|
-
| `latest-rates` | Export latest rates from a start position
|
|
197
|
-
| `rates-range` | Export rates for a date range
|
|
198
|
-
| `ticks-from` | Export ticks from a start date
|
|
199
|
-
| `ticks-range` | Export ticks for a date range
|
|
200
|
-
| `ticks-recent` | Export ticks from a recent trailing window
|
|
201
|
-
| `account-info` | Export account information
|
|
202
|
-
| `terminal-info` | Export terminal information
|
|
203
|
-
| `version` | Export MetaTrader 5 version information
|
|
204
|
-
| `last-error` | Export the last error information
|
|
205
|
-
| `symbols` | Export symbol list
|
|
206
|
-
| `symbol-info` | Export symbol details
|
|
207
|
-
| `symbol-info-tick` | Export the last tick for a symbol
|
|
208
|
-
| `minimum-margins` | Export minimum-volume buy and sell margin requirements
|
|
209
|
-
| `market-book` | Export market depth (order book)
|
|
210
|
-
| `orders` | Export active orders
|
|
211
|
-
| `positions` | Export open positions
|
|
212
|
-
| `history-orders` | Export historical orders
|
|
213
|
-
| `history-deals` | Export historical deals
|
|
214
|
-
| `recent-history-deals` | Export historical deals from a recent trailing window
|
|
215
|
-
| `mt5-summary` | Export terminal/account status summary
|
|
216
|
-
| `order-check` | Check funds sufficiency for a trade request
|
|
217
|
-
| `order-send` | Send a raw trade request to the trade server (`--yes` required; expert path)
|
|
218
|
-
| `close-positions` | Close open positions by `--symbol` or `--ticket` (`--yes` required for live; `--dry-run` available; optional `--deviation` / `--comment` / `--magic`) |
|
|
219
|
-
| `collect-history` | Collect rates, history-orders, and history-deals for one or more symbols into a single SQLite database (ticks opt-in via `--dataset ticks`)
|
|
220
|
-
| `history-gaps` | Export a SQLite-only one-row-per-gap report from managed rate compatibility views without connecting to MT5
|
|
221
|
-
| `grafana-schema` | Create or refresh Grafana-ready views and indexes in an existing SQLite database (idempotent, no MT5 connection)
|
|
222
|
-
| `snapshot` | Snapshot current account, position, order, and terminal state into SQLite for live Grafana dashboards
|
|
192
|
+
| Command | Description |
|
|
193
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
194
|
+
| `rates-from` | Export rates from a start date |
|
|
195
|
+
| `rates-from-pos` | Export rates from a start position |
|
|
196
|
+
| `latest-rates` | Export latest rates from a start position |
|
|
197
|
+
| `rates-range` | Export rates for a date range |
|
|
198
|
+
| `ticks-from` | Export ticks from a start date |
|
|
199
|
+
| `ticks-range` | Export ticks for a date range |
|
|
200
|
+
| `ticks-recent` | Export ticks from a recent trailing window |
|
|
201
|
+
| `account-info` | Export account information |
|
|
202
|
+
| `terminal-info` | Export terminal information |
|
|
203
|
+
| `version` | Export MetaTrader 5 version information |
|
|
204
|
+
| `last-error` | Export the last error information |
|
|
205
|
+
| `symbols` | Export symbol list |
|
|
206
|
+
| `symbol-info` | Export symbol details |
|
|
207
|
+
| `symbol-info-tick` | Export the last tick for a symbol |
|
|
208
|
+
| `minimum-margins` | Export minimum-volume buy and sell margin requirements |
|
|
209
|
+
| `market-book` | Export market depth (order book) |
|
|
210
|
+
| `orders` | Export active orders |
|
|
211
|
+
| `positions` | Export open positions |
|
|
212
|
+
| `history-orders` | Export historical orders |
|
|
213
|
+
| `history-deals` | Export historical deals |
|
|
214
|
+
| `recent-history-deals` | Export historical deals from a recent trailing window |
|
|
215
|
+
| `mt5-summary` | Export terminal/account status summary |
|
|
216
|
+
| `order-check` | Check funds sufficiency for a trade request |
|
|
217
|
+
| `order-send` | Send a raw trade request to the trade server (`--yes` required; expert path) |
|
|
218
|
+
| `close-positions` | Close open positions by `--symbol` or `--ticket` (`--yes` required for live; `--dry-run` available; optional `--filling-mode` / `--deviation` / `--comment` / `--magic`) |
|
|
219
|
+
| `collect-history` | Collect rates, history-orders, and history-deals for one or more symbols into a single SQLite database (ticks opt-in via `--dataset ticks`) |
|
|
220
|
+
| `history-gaps` | Export a SQLite-only one-row-per-gap report from managed rate compatibility views without connecting to MT5 |
|
|
221
|
+
| `grafana-schema` | Create or refresh Grafana-ready views and indexes in an existing SQLite database (idempotent, no MT5 connection) |
|
|
222
|
+
| `snapshot` | Snapshot current account, position, order, and terminal state into SQLite for live Grafana dashboards |
|
|
223
223
|
|
|
224
224
|
Use `order-check` to validate a request payload before running `order-send --yes`.
|
|
225
225
|
`close-positions` is the safer high-level alternative that builds correct close
|
|
@@ -158,37 +158,37 @@ python -m mt5cli -o account.csv account-info
|
|
|
158
158
|
|
|
159
159
|
## Commands
|
|
160
160
|
|
|
161
|
-
| Command | Description
|
|
162
|
-
| ---------------------- |
|
|
163
|
-
| `rates-from` | Export rates from a start date
|
|
164
|
-
| `rates-from-pos` | Export rates from a start position
|
|
165
|
-
| `latest-rates` | Export latest rates from a start position
|
|
166
|
-
| `rates-range` | Export rates for a date range
|
|
167
|
-
| `ticks-from` | Export ticks from a start date
|
|
168
|
-
| `ticks-range` | Export ticks for a date range
|
|
169
|
-
| `ticks-recent` | Export ticks from a recent trailing window
|
|
170
|
-
| `account-info` | Export account information
|
|
171
|
-
| `terminal-info` | Export terminal information
|
|
172
|
-
| `version` | Export MetaTrader 5 version information
|
|
173
|
-
| `last-error` | Export the last error information
|
|
174
|
-
| `symbols` | Export symbol list
|
|
175
|
-
| `symbol-info` | Export symbol details
|
|
176
|
-
| `symbol-info-tick` | Export the last tick for a symbol
|
|
177
|
-
| `minimum-margins` | Export minimum-volume buy and sell margin requirements
|
|
178
|
-
| `market-book` | Export market depth (order book)
|
|
179
|
-
| `orders` | Export active orders
|
|
180
|
-
| `positions` | Export open positions
|
|
181
|
-
| `history-orders` | Export historical orders
|
|
182
|
-
| `history-deals` | Export historical deals
|
|
183
|
-
| `recent-history-deals` | Export historical deals from a recent trailing window
|
|
184
|
-
| `mt5-summary` | Export terminal/account status summary
|
|
185
|
-
| `order-check` | Check funds sufficiency for a trade request
|
|
186
|
-
| `order-send` | Send a raw trade request to the trade server (`--yes` required; expert path)
|
|
187
|
-
| `close-positions` | Close open positions by `--symbol` or `--ticket` (`--yes` required for live; `--dry-run` available; optional `--deviation` / `--comment` / `--magic`) |
|
|
188
|
-
| `collect-history` | Collect rates, history-orders, and history-deals for one or more symbols into a single SQLite database (ticks opt-in via `--dataset ticks`)
|
|
189
|
-
| `history-gaps` | Export a SQLite-only one-row-per-gap report from managed rate compatibility views without connecting to MT5
|
|
190
|
-
| `grafana-schema` | Create or refresh Grafana-ready views and indexes in an existing SQLite database (idempotent, no MT5 connection)
|
|
191
|
-
| `snapshot` | Snapshot current account, position, order, and terminal state into SQLite for live Grafana dashboards
|
|
161
|
+
| Command | Description |
|
|
162
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
163
|
+
| `rates-from` | Export rates from a start date |
|
|
164
|
+
| `rates-from-pos` | Export rates from a start position |
|
|
165
|
+
| `latest-rates` | Export latest rates from a start position |
|
|
166
|
+
| `rates-range` | Export rates for a date range |
|
|
167
|
+
| `ticks-from` | Export ticks from a start date |
|
|
168
|
+
| `ticks-range` | Export ticks for a date range |
|
|
169
|
+
| `ticks-recent` | Export ticks from a recent trailing window |
|
|
170
|
+
| `account-info` | Export account information |
|
|
171
|
+
| `terminal-info` | Export terminal information |
|
|
172
|
+
| `version` | Export MetaTrader 5 version information |
|
|
173
|
+
| `last-error` | Export the last error information |
|
|
174
|
+
| `symbols` | Export symbol list |
|
|
175
|
+
| `symbol-info` | Export symbol details |
|
|
176
|
+
| `symbol-info-tick` | Export the last tick for a symbol |
|
|
177
|
+
| `minimum-margins` | Export minimum-volume buy and sell margin requirements |
|
|
178
|
+
| `market-book` | Export market depth (order book) |
|
|
179
|
+
| `orders` | Export active orders |
|
|
180
|
+
| `positions` | Export open positions |
|
|
181
|
+
| `history-orders` | Export historical orders |
|
|
182
|
+
| `history-deals` | Export historical deals |
|
|
183
|
+
| `recent-history-deals` | Export historical deals from a recent trailing window |
|
|
184
|
+
| `mt5-summary` | Export terminal/account status summary |
|
|
185
|
+
| `order-check` | Check funds sufficiency for a trade request |
|
|
186
|
+
| `order-send` | Send a raw trade request to the trade server (`--yes` required; expert path) |
|
|
187
|
+
| `close-positions` | Close open positions by `--symbol` or `--ticket` (`--yes` required for live; `--dry-run` available; optional `--filling-mode` / `--deviation` / `--comment` / `--magic`) |
|
|
188
|
+
| `collect-history` | Collect rates, history-orders, and history-deals for one or more symbols into a single SQLite database (ticks opt-in via `--dataset ticks`) |
|
|
189
|
+
| `history-gaps` | Export a SQLite-only one-row-per-gap report from managed rate compatibility views without connecting to MT5 |
|
|
190
|
+
| `grafana-schema` | Create or refresh Grafana-ready views and indexes in an existing SQLite database (idempotent, no MT5 connection) |
|
|
191
|
+
| `snapshot` | Snapshot current account, position, order, and terminal state into SQLite for live Grafana dashboards |
|
|
192
192
|
|
|
193
193
|
Use `order-check` to validate a request payload before running `order-send --yes`.
|
|
194
194
|
`close-positions` is the safer high-level alternative that builds correct close
|
|
@@ -20,6 +20,21 @@ append using dataset-specific keys (for example `ticket` on history tables, or
|
|
|
20
20
|
Optional views are created when `--with-views` is set and the `history-deals` dataset
|
|
21
21
|
was written.
|
|
22
22
|
|
|
23
|
+
`ticks` and `symbols` are opt-in datasets (pass `--dataset ticks` /
|
|
24
|
+
`--dataset symbols`); they are excluded from the default `rates`,
|
|
25
|
+
`history-orders`, `history-deals` selection. Unlike the other datasets,
|
|
26
|
+
`symbols` is not a time-windowed history table: each collection or update
|
|
27
|
+
writes one row per requested symbol, timestamped with the collection's
|
|
28
|
+
`date_to` (one-shot `collect-history`) or the update's end time (incremental
|
|
29
|
+
`update_history`). It snapshots broker-reported symbol metadata (`point`,
|
|
30
|
+
`digits`, `trade_contract_size`, `volume_min`, `volume_max`, `volume_step`,
|
|
31
|
+
`trade_tick_size`, `trade_tick_value`, `currency_profit`) so downstream
|
|
32
|
+
consumers can convert `rates.spread` (points) into a relative spread without a
|
|
33
|
+
live terminal connection. Metadata is only valid for the account/broker that
|
|
34
|
+
produced the snapshot. When a symbol's `point` is missing or zero, the row is
|
|
35
|
+
still written with NULL metadata and a warning is logged — a bad symbol never
|
|
36
|
+
aborts the rest of the sync.
|
|
37
|
+
|
|
23
38
|
### Entity-relationship diagram
|
|
24
39
|
|
|
25
40
|
Sample layout for a full collection with `--with-views`:
|
|
@@ -79,6 +94,20 @@ erDiagram
|
|
|
79
94
|
REAL fee
|
|
80
95
|
}
|
|
81
96
|
|
|
97
|
+
symbols {
|
|
98
|
+
TEXT symbol "dedup key"
|
|
99
|
+
TEXT time "dedup key, snapshot moment"
|
|
100
|
+
REAL point
|
|
101
|
+
INTEGER digits
|
|
102
|
+
REAL trade_contract_size
|
|
103
|
+
REAL volume_min
|
|
104
|
+
REAL volume_max
|
|
105
|
+
REAL volume_step
|
|
106
|
+
REAL trade_tick_size
|
|
107
|
+
REAL trade_tick_value
|
|
108
|
+
TEXT currency_profit
|
|
109
|
+
}
|
|
110
|
+
|
|
82
111
|
cash_events {
|
|
83
112
|
INTEGER ticket
|
|
84
113
|
TEXT symbol
|
|
@@ -106,6 +135,7 @@ erDiagram
|
|
|
106
135
|
rates ||--o{ history_deals : "symbol (logical)"
|
|
107
136
|
ticks ||--o{ history_deals : "symbol (logical)"
|
|
108
137
|
history_orders ||--o{ history_deals : "order ~ ticket (logical)"
|
|
138
|
+
symbols ||--o{ rates : "symbol (logical)"
|
|
109
139
|
history_deals ||--|| cash_events : "VIEW: type NOT IN (0,1)"
|
|
110
140
|
history_deals ||--o{ positions_reconstructed : "VIEW: GROUP BY position_id"
|
|
111
141
|
```
|
|
@@ -118,6 +148,7 @@ erDiagram
|
|
|
118
148
|
| `ticks` | table | `copy_ticks_range` | Indexed on `(symbol, time)` when columns exist. |
|
|
119
149
|
| `history_orders` | table | `history_orders_get` | Fetched per `--symbol`, then concatenated. |
|
|
120
150
|
| `history_deals` | table | `history_deals_get` | Fetched per `--symbol`, then concatenated. Indexed on `(position_id, symbol)` when present. |
|
|
151
|
+
| `symbols` | table | `symbol_info` | Opt-in. One row per symbol per collection/update, snapshotted at `date_to` / update end. |
|
|
121
152
|
| `cash_events` | view | `history_deals` | Non-trade deal types (deposits, balance ops, etc.). Requires `type` column. |
|
|
122
153
|
| `positions_reconstructed` | view | `history_deals` | One row per closed `position_id`; volume-weighted prices and reversal stats. |
|
|
123
154
|
|
|
@@ -240,7 +271,7 @@ frame = series["EURUSD", 1] # keyed by (symbol, integer timeframe)
|
|
|
240
271
|
`require_existing` is ignored.
|
|
241
272
|
- `load_rate_series_from_sqlite()` returns a mapping keyed by
|
|
242
273
|
`(symbol, integer timeframe)`. Unless `explicit_tables` is supplied, it
|
|
243
|
-
requires existing managed `rate_*` compatibility views and raises
|
|
274
|
+
requires existing managed `rate_*__*` compatibility views and raises
|
|
244
275
|
`ValueError` when they are missing. Duplicate `(symbol, timeframe)` targets
|
|
245
276
|
are rejected.
|
|
246
277
|
- `load_rate_series_by_granularity()` is a thin wrapper that builds the targets,
|
|
@@ -88,6 +88,7 @@ strategy entries, exits, Kelly sizing, or signal logic.
|
|
|
88
88
|
| ------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------- |
|
|
89
89
|
| `get_account_snapshot`, `get_symbol_snapshot`, `get_tick_snapshot`, `get_positions_frame` | Normalized account/symbol/tick/position views |
|
|
90
90
|
| `extract_tick_price` | Positive finite bid/ask extraction from tick mappings |
|
|
91
|
+
| `estimate_server_clock_offset_seconds` | Broker server clock offset from true UTC, via the latest tick |
|
|
91
92
|
| `detect_position_side` | Net long / short / flat from open positions |
|
|
92
93
|
| `calculate_spread_ratio` | Relative bid-ask spread |
|
|
93
94
|
| `calculate_margin_and_volume`, `calculate_volume_by_margin`, `calculate_new_position_margin_ratio` | Margin budget and volume sizing |
|
|
@@ -234,8 +235,12 @@ that closes open positions by `--symbol` or `--ticket` using
|
|
|
234
235
|
`close_open_positions()`. Both `order-send --yes` and `close-positions --yes`
|
|
235
236
|
are live execution paths. `close-positions --dry-run` previews close orders
|
|
236
237
|
without placing them and does not require `--yes`. `close-positions` also
|
|
237
|
-
accepts optional `--deviation`, `--comment`, and `--magic`;
|
|
238
|
-
the selected open positions fail-closed when position magic
|
|
238
|
+
accepts optional `--filling-mode`, `--deviation`, `--comment`, and `--magic`;
|
|
239
|
+
`--magic` scopes the selected open positions fail-closed when position magic
|
|
240
|
+
metadata is absent. When `--filling-mode` (or the `order_filling_mode`
|
|
241
|
+
parameter of `close_open_positions()`) is omitted, the filling mode is
|
|
242
|
+
resolved per symbol with `resolve_broker_filling_mode()` so closes are not
|
|
243
|
+
rejected on brokers whose symbols do not support IOC.
|
|
239
244
|
|
|
240
245
|
`history-gaps` reads an existing SQLite history database and exports one row
|
|
241
246
|
per detected gap from managed rate compatibility views. It never initializes
|
|
@@ -160,8 +160,8 @@ updater = ThrottledHistoryUpdater(
|
|
|
160
160
|
)
|
|
161
161
|
```
|
|
162
162
|
|
|
163
|
-
By default recoverable errors (`
|
|
164
|
-
`
|
|
163
|
+
By default recoverable errors (`Mt5RuntimeError`, `sqlite3.Error`,
|
|
164
|
+
`ValueError`, `OSError`, and MT5 client capability
|
|
165
165
|
`AttributeError` / `TypeError` for history API methods) propagate so the caller
|
|
166
166
|
controls logging; pass `suppress_errors=True` to swallow them and return
|
|
167
167
|
`False` without advancing the throttle. Other `AttributeError` / `TypeError`
|
|
@@ -236,6 +236,45 @@ or `None` result from the underlying client is normalized to an empty DataFrame.
|
|
|
236
236
|
Downstream packages own all strategy-specific transformations. mt5cli does not
|
|
237
237
|
provide entry-deal classification, Kelly sizing, or any betting-specific helpers.
|
|
238
238
|
|
|
239
|
+
## Broker server clock offset
|
|
240
|
+
|
|
241
|
+
MT5 tick, bar, and deal timestamps are epoch values labeled in the broker
|
|
242
|
+
server's wall clock, which is commonly UTC+2 or UTC+3 rather than true UTC.
|
|
243
|
+
Any code that mixes those timestamps with true UTC (freshness checks,
|
|
244
|
+
trailing history windows) silently inherits the broker's offset as a bias
|
|
245
|
+
unless it is measured and applied explicitly.
|
|
246
|
+
|
|
247
|
+
`estimate_server_clock_offset_seconds()` reads the latest tick for a symbol
|
|
248
|
+
and returns the broker's clock offset from true UTC, rounded to the nearest
|
|
249
|
+
half hour, or `None` when no valid tick time is available. Pass the result to
|
|
250
|
+
`fetch_recent_history_deals_for_trading_client()` via
|
|
251
|
+
`server_clock_offset_seconds` to shift the trailing window so it covers the
|
|
252
|
+
true most-recent deals:
|
|
253
|
+
|
|
254
|
+
```python
|
|
255
|
+
from mt5cli import (
|
|
256
|
+
create_trading_client,
|
|
257
|
+
estimate_server_clock_offset_seconds,
|
|
258
|
+
fetch_recent_history_deals_for_trading_client,
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
client = create_trading_client(login=12345, server="Broker-Demo")
|
|
262
|
+
try:
|
|
263
|
+
offset = estimate_server_clock_offset_seconds(client, "JP225")
|
|
264
|
+
deals_df = fetch_recent_history_deals_for_trading_client(
|
|
265
|
+
client,
|
|
266
|
+
symbol="JP225",
|
|
267
|
+
hours=24,
|
|
268
|
+
server_clock_offset_seconds=offset,
|
|
269
|
+
)
|
|
270
|
+
finally:
|
|
271
|
+
client.shutdown()
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
No offset is applied automatically anywhere; omitting
|
|
275
|
+
`server_clock_offset_seconds` keeps the trailing window anchored to true UTC
|
|
276
|
+
(current behavior, byte-identical to prior releases).
|
|
277
|
+
|
|
239
278
|
## Migration from application-local helpers
|
|
240
279
|
|
|
241
280
|
| Application-local concern | mt5cli replacement |
|
|
@@ -247,6 +286,7 @@ provide entry-deal classification, Kelly sizing, or any betting-specific helpers
|
|
|
247
286
|
| Local order or position margin estimation | `estimate_order_margin()`, `calculate_positions_margin()` |
|
|
248
287
|
| Local closed-bar fetch from a trading session | `fetch_latest_closed_rates_for_trading_client()`, `fetch_latest_closed_rates_indexed()` |
|
|
249
288
|
| Local recent deal history fetch from a trading session | `fetch_recent_history_deals_for_trading_client()` |
|
|
289
|
+
| Local broker server clock offset measurement | `estimate_server_clock_offset_seconds()` |
|
|
250
290
|
| Local SL/TP price derivation | `determine_order_limits()` |
|
|
251
291
|
| Throttled SQLite history loop with ad-hoc error handling | `ThrottledHistoryUpdater(suppress_errors=True)` |
|
|
252
292
|
|
|
@@ -166,10 +166,10 @@ mt5cli --login '${MT5_LOGIN}' --password '${MT5_PASSWORD}' --server '${MT5_SERVE
|
|
|
166
166
|
These commands send requests to the live trade server and can place or close
|
|
167
167
|
real trades. Both require `--yes` for live execution.
|
|
168
168
|
|
|
169
|
-
| Command | Description
|
|
170
|
-
| ----------------- |
|
|
171
|
-
| `order-send` | Send a **raw** trade request directly to MT5 (`--yes` required; expert path — no extra validation)
|
|
172
|
-
| `close-positions` | Close open positions by `--symbol` or `--ticket` (`--yes` required for live; `--dry-run` to preview; optional `--deviation` / `--comment` / `--magic`) |
|
|
169
|
+
| Command | Description |
|
|
170
|
+
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
171
|
+
| `order-send` | Send a **raw** trade request directly to MT5 (`--yes` required; expert path — no extra validation) |
|
|
172
|
+
| `close-positions` | Close open positions by `--symbol` or `--ticket` (`--yes` required for live; `--dry-run` to preview; optional `--filling-mode` / `--deviation` / `--comment` / `--magic`) |
|
|
173
173
|
|
|
174
174
|
Use `order-check` (Trading State) to validate funds before running `order-send --yes`.
|
|
175
175
|
`close-positions` is the safer high-level alternative that builds correct close
|
|
@@ -178,10 +178,10 @@ applications should prefer dedicated closing helpers or their own risk controls.
|
|
|
178
178
|
|
|
179
179
|
### Bulk Collection
|
|
180
180
|
|
|
181
|
-
| Command | Description
|
|
182
|
-
| ----------------- |
|
|
183
|
-
| `collect-history` | Collect rates, history-orders, and history-deals (ticks opt-in via `--dataset ticks`) for one or more symbols into a single SQLite database (optional cash-event/position views) |
|
|
184
|
-
| `history-gaps` | Export a SQLite-only one-row-per-gap report from managed rate compatibility views without connecting to MT5
|
|
181
|
+
| Command | Description |
|
|
182
|
+
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
183
|
+
| `collect-history` | Collect rates, history-orders, and history-deals (ticks and symbol metadata opt-in via `--dataset ticks` / `--dataset symbols`) for one or more symbols into a single SQLite database (optional cash-event/position views) |
|
|
184
|
+
| `history-gaps` | Export a SQLite-only one-row-per-gap report from managed rate compatibility views without connecting to MT5 |
|
|
185
185
|
|
|
186
186
|
```bash
|
|
187
187
|
mt5cli -o history.db collect-history \
|
|
@@ -193,16 +193,16 @@ mt5cli -o history.db collect-history \
|
|
|
193
193
|
|
|
194
194
|
`collect-history` options:
|
|
195
195
|
|
|
196
|
-
| Option | Default | Description
|
|
197
|
-
| -------------- | ------------------------------------ |
|
|
198
|
-
| `--symbol/-s` | _required_ | Symbol to collect (repeat for multiple).
|
|
199
|
-
| `--date-from` | _required_ | Start date in ISO 8601.
|
|
200
|
-
| `--date-to` | _required_ | End date in ISO 8601.
|
|
201
|
-
| `--dataset` | rates, history-orders, history-deals | Repeatable: `rates`, `ticks`, `history-orders`, `history-deals`. Ticks are opt-in: pass `--dataset ticks` to include them. |
|
|
202
|
-
| `--timeframe` | `M1` | Rates timeframe; recorded in a `timeframe` column on the `rates` table.
|
|
203
|
-
| `--flags` | `ALL` | Tick copy flags forwarded to `copy_ticks_range`.
|
|
204
|
-
| `--if-exists` | `fail` | `append`, `replace`, or `fail` when a target table already exists.
|
|
205
|
-
| `--with-views` | off | Add `cash_events` and `positions_reconstructed` views (requires the `history-deals` dataset).
|
|
196
|
+
| Option | Default | Description |
|
|
197
|
+
| -------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
198
|
+
| `--symbol/-s` | _required_ | Symbol to collect (repeat for multiple). |
|
|
199
|
+
| `--date-from` | _required_ | Start date in ISO 8601. |
|
|
200
|
+
| `--date-to` | _required_ | End date in ISO 8601. |
|
|
201
|
+
| `--dataset` | rates, history-orders, history-deals | Repeatable: `rates`, `ticks`, `history-orders`, `history-deals`, `symbols`. Ticks and symbol metadata are opt-in: pass `--dataset ticks` / `--dataset symbols` to include them. |
|
|
202
|
+
| `--timeframe` | `M1` | Rates timeframe; recorded in a `timeframe` column on the `rates` table. |
|
|
203
|
+
| `--flags` | `ALL` | Tick copy flags forwarded to `copy_ticks_range`. |
|
|
204
|
+
| `--if-exists` | `fail` | `append`, `replace`, or `fail` when a target table already exists. |
|
|
205
|
+
| `--with-views` | off | Add `cash_events` and `positions_reconstructed` views (requires the `history-deals` dataset). |
|
|
206
206
|
|
|
207
207
|
History orders and deals are fetched per symbol and concatenated, so the symbol filter is applied consistently across all datasets. The `cash_events` view is derived from symbol-filtered `history_deals`, so account-level cash events with empty or non-matching symbols may be excluded. The `positions_reconstructed` view excludes positions with no closing deal, uses volume-weighted open/close prices, and reports reversal deals (`DEAL_ENTRY_INOUT`) via `volume_reversal` / `reversal_count`.
|
|
208
208
|
|
|
@@ -66,6 +66,7 @@ from .trading import (
|
|
|
66
66
|
determine_order_limits,
|
|
67
67
|
ensure_symbol_selected,
|
|
68
68
|
estimate_order_margin,
|
|
69
|
+
estimate_server_clock_offset_seconds,
|
|
69
70
|
extract_tick_price,
|
|
70
71
|
fetch_latest_closed_rates_for_trading_client,
|
|
71
72
|
fetch_latest_closed_rates_indexed,
|
|
@@ -127,6 +128,7 @@ __all__ = [
|
|
|
127
128
|
"drop_forming_rate_bar",
|
|
128
129
|
"ensure_symbol_selected",
|
|
129
130
|
"estimate_order_margin",
|
|
131
|
+
"estimate_server_clock_offset_seconds",
|
|
130
132
|
"extract_tick_price",
|
|
131
133
|
"fetch_latest_closed_rates",
|
|
132
134
|
"fetch_latest_closed_rates_for_trading_client",
|
|
@@ -6,7 +6,7 @@ import json
|
|
|
6
6
|
import logging
|
|
7
7
|
import os
|
|
8
8
|
import re
|
|
9
|
-
import
|
|
9
|
+
from contextlib import closing
|
|
10
10
|
from dataclasses import dataclass
|
|
11
11
|
from datetime import datetime # noqa: TC003
|
|
12
12
|
from pathlib import Path # noqa: TC003
|
|
@@ -17,7 +17,11 @@ import typer
|
|
|
17
17
|
|
|
18
18
|
from . import sdk
|
|
19
19
|
from .client import MT5Client
|
|
20
|
-
from .history import
|
|
20
|
+
from .history import (
|
|
21
|
+
open_existing_sqlite_database,
|
|
22
|
+
report_rate_gaps,
|
|
23
|
+
resolve_granularity_name,
|
|
24
|
+
)
|
|
21
25
|
from .trading import OrderExecutionResult, close_open_positions, create_trading_client
|
|
22
26
|
from .utils import (
|
|
23
27
|
DATETIME_TYPE,
|
|
@@ -33,10 +37,13 @@ from .utils import (
|
|
|
33
37
|
)
|
|
34
38
|
|
|
35
39
|
if TYPE_CHECKING:
|
|
40
|
+
import sqlite3
|
|
36
41
|
from collections.abc import Callable
|
|
37
42
|
|
|
38
43
|
from pdmt5 import Mt5Config
|
|
39
44
|
|
|
45
|
+
from .trading import OrderFillingMode
|
|
46
|
+
|
|
40
47
|
logger = logging.getLogger(__name__)
|
|
41
48
|
|
|
42
49
|
# ---------------------------------------------------------------------------
|
|
@@ -727,6 +734,16 @@ def close_positions(
|
|
|
727
734
|
help="Position ticket to close (repeat for multiple tickets).",
|
|
728
735
|
),
|
|
729
736
|
] = None,
|
|
737
|
+
filling_mode: Annotated[
|
|
738
|
+
str | None,
|
|
739
|
+
typer.Option(
|
|
740
|
+
"--filling-mode",
|
|
741
|
+
help=(
|
|
742
|
+
"Order filling mode for close requests (IOC, FOK, or RETURN)."
|
|
743
|
+
" Defaults to per-symbol broker resolution."
|
|
744
|
+
),
|
|
745
|
+
),
|
|
746
|
+
] = None,
|
|
730
747
|
deviation: Annotated[
|
|
731
748
|
int | None,
|
|
732
749
|
typer.Option(help="Optional slippage/deviation for each close request."),
|
|
@@ -762,11 +779,19 @@ def close_positions(
|
|
|
762
779
|
|
|
763
780
|
Raises:
|
|
764
781
|
typer.BadParameter: If neither ``--symbol`` nor ``--ticket`` is given,
|
|
765
|
-
|
|
782
|
+
if ``--filling-mode`` is not IOC, FOK, or RETURN, or if ``--yes``
|
|
783
|
+
is missing for a live (non-dry-run) run.
|
|
766
784
|
"""
|
|
767
785
|
if not symbol and not ticket:
|
|
768
786
|
msg = "Provide at least one --symbol or --ticket to close positions."
|
|
769
787
|
raise typer.BadParameter(msg)
|
|
788
|
+
order_filling_mode: OrderFillingMode | None = None
|
|
789
|
+
if filling_mode is not None:
|
|
790
|
+
normalized_filling_mode = filling_mode.upper()
|
|
791
|
+
if normalized_filling_mode not in {"IOC", "FOK", "RETURN"}:
|
|
792
|
+
msg = f"Unsupported filling mode: {filling_mode!r}."
|
|
793
|
+
raise typer.BadParameter(msg, param_hint="--filling-mode")
|
|
794
|
+
order_filling_mode = cast("OrderFillingMode", normalized_filling_mode)
|
|
770
795
|
if not dry_run and not yes:
|
|
771
796
|
msg = "Pass --yes to close live positions."
|
|
772
797
|
raise typer.BadParameter(msg, param_hint="--yes")
|
|
@@ -777,6 +802,7 @@ def close_positions(
|
|
|
777
802
|
client,
|
|
778
803
|
symbols=list(symbol) if symbol else None,
|
|
779
804
|
tickets=list(ticket) if ticket else None,
|
|
805
|
+
order_filling_mode=order_filling_mode,
|
|
780
806
|
deviation=deviation,
|
|
781
807
|
comment=comment,
|
|
782
808
|
magic=magic,
|
|
@@ -817,10 +843,15 @@ def history_gaps(
|
|
|
817
843
|
"""Export SQLite rate gaps without connecting to MT5.
|
|
818
844
|
|
|
819
845
|
Raises:
|
|
820
|
-
typer.BadParameter: If
|
|
821
|
-
|
|
846
|
+
typer.BadParameter: If the source database does not exist, if no
|
|
847
|
+
compatible rate view is available and no explicit table is
|
|
848
|
+
provided, or if granularity inference fails.
|
|
822
849
|
"""
|
|
823
|
-
|
|
850
|
+
try:
|
|
851
|
+
conn, _ = open_existing_sqlite_database(sqlite3_path)
|
|
852
|
+
except ValueError as exc:
|
|
853
|
+
raise typer.BadParameter(str(exc), param_hint="--sqlite3") from exc
|
|
854
|
+
with closing(conn):
|
|
824
855
|
tables = list(table) if table else _default_gap_tables(conn)
|
|
825
856
|
if not tables:
|
|
826
857
|
msg = (
|
|
@@ -881,7 +912,8 @@ def collect_history(
|
|
|
881
912
|
help=(
|
|
882
913
|
"Dataset to include (repeat for multiple)."
|
|
883
914
|
" Defaults to rates, history-orders, history-deals."
|
|
884
|
-
" Ticks are opt-in:
|
|
915
|
+
" Ticks and symbols metadata are opt-in:"
|
|
916
|
+
" pass --dataset ticks or --dataset symbols to include them."
|
|
885
917
|
),
|
|
886
918
|
),
|
|
887
919
|
] = None,
|
|
@@ -922,6 +954,9 @@ def collect_history(
|
|
|
922
954
|
Tables written depend on ``--dataset``: ``rates``, ``history_orders``,
|
|
923
955
|
``history_deals`` by default. ``ticks`` are opt-in: pass
|
|
924
956
|
``--dataset ticks`` to include them (tick data grows the database quickly).
|
|
957
|
+
``symbols`` is also opt-in: pass ``--dataset symbols`` to snapshot
|
|
958
|
+
per-symbol metadata (point, digits, contract size, volume limits) at
|
|
959
|
+
``date_to``, one row per symbol per collection.
|
|
925
960
|
History datasets are fetched per symbol and concatenated. Rates rows carry
|
|
926
961
|
the requested ``timeframe`` so appended runs at different timeframes remain
|
|
927
962
|
distinguishable.
|
|
@@ -44,6 +44,7 @@ STABLE_SDK_EXPORTS: frozenset[str] = frozenset({
|
|
|
44
44
|
"drop_forming_rate_bar",
|
|
45
45
|
"ensure_symbol_selected",
|
|
46
46
|
"estimate_order_margin",
|
|
47
|
+
"estimate_server_clock_offset_seconds",
|
|
47
48
|
"extract_tick_price",
|
|
48
49
|
"fetch_latest_closed_rates",
|
|
49
50
|
"fetch_latest_closed_rates_for_trading_client",
|