mt5cli 1.0.3__tar.gz → 1.1.0__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.0.3 → mt5cli-1.1.0}/.agents/skills/local-qa/scripts/qa.sh +1 -1
- {mt5cli-1.0.3 → mt5cli-1.1.0}/PKG-INFO +105 -1
- {mt5cli-1.0.3 → mt5cli-1.1.0}/README.md +100 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/docs/api/public-contract.md +75 -8
- mt5cli-1.1.0/examples/grafana/README.md +95 -0
- mt5cli-1.1.0/examples/grafana/compose.yml +26 -0
- mt5cli-1.1.0/examples/grafana/dashboards/mt5cli-market.json +98 -0
- mt5cli-1.1.0/examples/grafana/dashboards/mt5cli-overview.json +254 -0
- mt5cli-1.1.0/examples/grafana/dashboards/mt5cli-trades.json +167 -0
- mt5cli-1.1.0/examples/grafana/provisioning/dashboards/mt5cli.yml +13 -0
- mt5cli-1.1.0/examples/grafana/provisioning/datasources/mt5cli-sqlite.yml +16 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/mt5cli/__init__.py +4 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/mt5cli/cli.py +125 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/mt5cli/contract.py +2 -0
- mt5cli-1.1.0/mt5cli/grafana.py +682 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/mt5cli/sdk.py +255 -17
- mt5cli-1.1.0/mt5cli/telemetry.py +354 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/mt5cli/utils.py +2 -1
- {mt5cli-1.0.3 → mt5cli-1.1.0}/pyproject.toml +8 -1
- {mt5cli-1.0.3 → mt5cli-1.1.0}/tests/conftest.py +38 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/tests/test_cli.py +239 -0
- mt5cli-1.1.0/tests/test_examples.py +75 -0
- mt5cli-1.1.0/tests/test_grafana.py +991 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/tests/test_sdk.py +515 -0
- mt5cli-1.1.0/tests/test_telemetry.py +249 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/uv.lock +123 -3
- {mt5cli-1.0.3 → mt5cli-1.1.0}/.agents/skills/local-qa/SKILL.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/.agents/skills/mt5cli/SKILL.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/.agents/skills/pr-feedback-triage/SKILL.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/.claude/agents/codex.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/.claude/settings.json +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/.github/FUNDING.yml +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/.github/dependabot.yml +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/.github/renovate.json +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/.github/workflows/ci.yml +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/.github/workflows/claude.yml +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/.github/workflows/release.yml +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/.gitignore +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/AGENTS.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/CLAUDE.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/LICENSE +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/docs/api/cli.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/docs/api/client.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/docs/api/converters.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/docs/api/exceptions.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/docs/api/history.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/docs/api/index.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/docs/api/schemas.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/docs/api/sdk.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/docs/api/trading.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/docs/api/utils.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/docs/index.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/mkdocs.yml +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/mt5cli/__main__.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/mt5cli/client.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/mt5cli/converters.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/mt5cli/exceptions.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/mt5cli/history.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/mt5cli/retry.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/mt5cli/schemas.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/mt5cli/trading.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/tests/__init__.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/tests/test_contracts.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/tests/test_history.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/tests/test_trading.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.0}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mt5cli
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
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>
|
|
@@ -19,6 +19,10 @@ Requires-Python: <3.14,>=3.11
|
|
|
19
19
|
Requires-Dist: click>=8.1.0
|
|
20
20
|
Requires-Dist: pdmt5>=1.0.0
|
|
21
21
|
Requires-Dist: typer>=0.15.0
|
|
22
|
+
Provides-Extra: otel
|
|
23
|
+
Requires-Dist: opentelemetry-api; extra == 'otel'
|
|
24
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http; extra == 'otel'
|
|
25
|
+
Requires-Dist: opentelemetry-sdk; extra == 'otel'
|
|
22
26
|
Provides-Extra: parquet
|
|
23
27
|
Requires-Dist: pyarrow>=19.0.0; extra == 'parquet'
|
|
24
28
|
Description-Content-Type: text/markdown
|
|
@@ -210,6 +214,8 @@ python -m mt5cli -o account.csv account-info
|
|
|
210
214
|
| `order-send` | Send a raw trade request to the trade server (`--yes` required; expert path) |
|
|
211
215
|
| `close-positions` | Close open positions by `--symbol` or `--ticket` (`--yes` required for live; `--dry-run` available) |
|
|
212
216
|
| `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`) |
|
|
217
|
+
| `grafana-schema` | Create or refresh Grafana-ready views and indexes in an existing SQLite database (idempotent, no MT5 connection) |
|
|
218
|
+
| `snapshot` | Snapshot current account, position, order, and terminal state into SQLite for live Grafana dashboards |
|
|
213
219
|
|
|
214
220
|
Use `order-check` to validate a request payload before running `order-send --yes`.
|
|
215
221
|
`close-positions` is the safer high-level alternative that builds correct close
|
|
@@ -229,6 +235,104 @@ mt5cli -o history.db collect-history \
|
|
|
229
235
|
|
|
230
236
|
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 `rates` table records the requested `timeframe` so appended runs at different timeframes remain distinguishable. The `positions_reconstructed` view aggregates trade deals by `position_id`, excludes positions without closing-side entries, and uses volume-weighted open/close prices; reversal deals (`DEAL_ENTRY_INOUT`) are reported via `volume_reversal` / `reversal_count` columns.
|
|
231
237
|
|
|
238
|
+
### Grafana-ready SQLite dashboards
|
|
239
|
+
|
|
240
|
+
mt5cli can prepare a SQLite database for use as a Grafana datasource (via the [SQLite plugin](https://grafana.com/grafana/plugins/frser-sqlite-datasource/) or similar). Most `grafana_*` views expose an integer epoch-second `time` column for use in Grafana time-series panels. Two views (`grafana_realized_pnl`, `grafana_trade_stats`) are static symbol-level summaries with no `time` column — use them in table or stat panels.
|
|
241
|
+
|
|
242
|
+
#### Prepare the schema (idempotent, no MT5 connection needed)
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
mt5cli -o history.db grafana-schema
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
This creates snapshot tables (`account_snapshots`, `position_snapshots`, `order_snapshots`, `terminal_snapshots`, `snapshot_runs`) and all `grafana_*` views and indexes in the SQLite database. Safe to run repeatedly — all operations are idempotent.
|
|
249
|
+
|
|
250
|
+
#### Snapshot current account state
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
mt5cli -o history.db snapshot \
|
|
254
|
+
--symbol JP225 --symbol HK50 --symbol NL25 \
|
|
255
|
+
--with-account --with-positions --with-orders --with-terminal \
|
|
256
|
+
--with-grafana-schema
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Appends one timestamped row per data type. Never places orders or modifies trading state. Run periodically (e.g. from a cron job or a loop) to build a time-series account history.
|
|
260
|
+
|
|
261
|
+
#### SDK usage
|
|
262
|
+
|
|
263
|
+
```python
|
|
264
|
+
from pdmt5 import Mt5DataClient, Mt5Config
|
|
265
|
+
from mt5cli import update_observability, update_observability_with_config
|
|
266
|
+
|
|
267
|
+
# Reuse an already-connected client
|
|
268
|
+
client = Mt5DataClient(config=Mt5Config(login=12345))
|
|
269
|
+
client.initialize_and_login_mt5()
|
|
270
|
+
try:
|
|
271
|
+
update_observability(
|
|
272
|
+
client=client,
|
|
273
|
+
output="history.db",
|
|
274
|
+
symbols=["EURUSD", "GBPUSD"], # optional position/order filter
|
|
275
|
+
include_account=True,
|
|
276
|
+
include_positions=True,
|
|
277
|
+
include_orders=True,
|
|
278
|
+
include_terminal=True,
|
|
279
|
+
with_grafana_schema=True,
|
|
280
|
+
)
|
|
281
|
+
finally:
|
|
282
|
+
client.shutdown()
|
|
283
|
+
|
|
284
|
+
# Standalone wrapper that opens/closes MT5 automatically
|
|
285
|
+
update_observability_with_config(
|
|
286
|
+
output="history.db",
|
|
287
|
+
config=Mt5Config(login=12345),
|
|
288
|
+
)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
#### Available Grafana views
|
|
292
|
+
|
|
293
|
+
**Time-series views** (integer epoch-second `time` column; snapshot views also expose `run_id`):
|
|
294
|
+
|
|
295
|
+
| View | Source | Description |
|
|
296
|
+
| ---------------------------- | -------------------- | ---------------------------------------------------------- |
|
|
297
|
+
| `grafana_rates` | `rates` | OHLCV bars with integer epoch `time` |
|
|
298
|
+
| `grafana_ticks` | `ticks` | Tick data with integer epoch `time` |
|
|
299
|
+
| `grafana_history_deals` | `history_deals` | All deals with epoch `time` |
|
|
300
|
+
| `grafana_history_orders` | `history_orders` | All historical orders; adds epoch `time` from `time_setup` |
|
|
301
|
+
| `grafana_trade_deals` | `history_deals` | Trade deals only (`type IN (0,1)`) |
|
|
302
|
+
| `grafana_cash_events` | `history_deals` | Non-trade deals (deposits, dividends, etc.) |
|
|
303
|
+
| `grafana_symbol_pnl` | `history_deals` | Per-close-deal profit/loss per symbol |
|
|
304
|
+
| `grafana_account_snapshots` | `account_snapshots` | Account balance/equity/margin time series |
|
|
305
|
+
| `grafana_position_snapshots` | `position_snapshots` | Open position snapshots over time |
|
|
306
|
+
| `grafana_order_snapshots` | `order_snapshots` | Active order snapshots over time |
|
|
307
|
+
| `grafana_terminal_snapshots` | `terminal_snapshots` | Terminal connectivity snapshots |
|
|
308
|
+
|
|
309
|
+
**Static summary views** (no `time` column; use in table or stat panels, not time-series):
|
|
310
|
+
|
|
311
|
+
| View | Source | Description |
|
|
312
|
+
| ---------------------- | --------------- | ------------------------------------- |
|
|
313
|
+
| `grafana_realized_pnl` | `history_deals` | Cumulative realized PnL per symbol |
|
|
314
|
+
| `grafana_trade_stats` | `history_deals` | Win/loss counts and profit per symbol |
|
|
315
|
+
|
|
316
|
+
#### Example Grafana queries
|
|
317
|
+
|
|
318
|
+
```sql
|
|
319
|
+
-- Equity curve over time
|
|
320
|
+
SELECT time, equity FROM grafana_account_snapshots ORDER BY time;
|
|
321
|
+
|
|
322
|
+
-- Rolling balance by account login
|
|
323
|
+
SELECT time, login, balance FROM grafana_account_snapshots
|
|
324
|
+
WHERE login = $login ORDER BY time;
|
|
325
|
+
|
|
326
|
+
-- Open positions at latest successful snapshot
|
|
327
|
+
SELECT symbol, volume, profit FROM grafana_position_snapshots
|
|
328
|
+
WHERE run_id = (SELECT MAX(run_id) FROM snapshot_runs WHERE status = 'ok');
|
|
329
|
+
|
|
330
|
+
-- Realized PnL by symbol
|
|
331
|
+
SELECT symbol, total_profit FROM grafana_trade_stats ORDER BY total_profit DESC;
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
> **Note**: OpenTelemetry integration is intentionally not part of this release and is tracked separately.
|
|
335
|
+
|
|
232
336
|
### Incremental history SDK
|
|
233
337
|
|
|
234
338
|
For automated pipelines, use the importable incremental API instead of re-fetching fixed date ranges:
|
|
@@ -185,6 +185,8 @@ python -m mt5cli -o account.csv account-info
|
|
|
185
185
|
| `order-send` | Send a raw trade request to the trade server (`--yes` required; expert path) |
|
|
186
186
|
| `close-positions` | Close open positions by `--symbol` or `--ticket` (`--yes` required for live; `--dry-run` available) |
|
|
187
187
|
| `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`) |
|
|
188
|
+
| `grafana-schema` | Create or refresh Grafana-ready views and indexes in an existing SQLite database (idempotent, no MT5 connection) |
|
|
189
|
+
| `snapshot` | Snapshot current account, position, order, and terminal state into SQLite for live Grafana dashboards |
|
|
188
190
|
|
|
189
191
|
Use `order-check` to validate a request payload before running `order-send --yes`.
|
|
190
192
|
`close-positions` is the safer high-level alternative that builds correct close
|
|
@@ -204,6 +206,104 @@ mt5cli -o history.db collect-history \
|
|
|
204
206
|
|
|
205
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 `rates` table records the requested `timeframe` so appended runs at different timeframes remain distinguishable. The `positions_reconstructed` view aggregates trade deals by `position_id`, excludes positions without closing-side entries, and uses volume-weighted open/close prices; reversal deals (`DEAL_ENTRY_INOUT`) are reported via `volume_reversal` / `reversal_count` columns.
|
|
206
208
|
|
|
209
|
+
### Grafana-ready SQLite dashboards
|
|
210
|
+
|
|
211
|
+
mt5cli can prepare a SQLite database for use as a Grafana datasource (via the [SQLite plugin](https://grafana.com/grafana/plugins/frser-sqlite-datasource/) or similar). Most `grafana_*` views expose an integer epoch-second `time` column for use in Grafana time-series panels. Two views (`grafana_realized_pnl`, `grafana_trade_stats`) are static symbol-level summaries with no `time` column — use them in table or stat panels.
|
|
212
|
+
|
|
213
|
+
#### Prepare the schema (idempotent, no MT5 connection needed)
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
mt5cli -o history.db grafana-schema
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
This creates snapshot tables (`account_snapshots`, `position_snapshots`, `order_snapshots`, `terminal_snapshots`, `snapshot_runs`) and all `grafana_*` views and indexes in the SQLite database. Safe to run repeatedly — all operations are idempotent.
|
|
220
|
+
|
|
221
|
+
#### Snapshot current account state
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
mt5cli -o history.db snapshot \
|
|
225
|
+
--symbol JP225 --symbol HK50 --symbol NL25 \
|
|
226
|
+
--with-account --with-positions --with-orders --with-terminal \
|
|
227
|
+
--with-grafana-schema
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Appends one timestamped row per data type. Never places orders or modifies trading state. Run periodically (e.g. from a cron job or a loop) to build a time-series account history.
|
|
231
|
+
|
|
232
|
+
#### SDK usage
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
from pdmt5 import Mt5DataClient, Mt5Config
|
|
236
|
+
from mt5cli import update_observability, update_observability_with_config
|
|
237
|
+
|
|
238
|
+
# Reuse an already-connected client
|
|
239
|
+
client = Mt5DataClient(config=Mt5Config(login=12345))
|
|
240
|
+
client.initialize_and_login_mt5()
|
|
241
|
+
try:
|
|
242
|
+
update_observability(
|
|
243
|
+
client=client,
|
|
244
|
+
output="history.db",
|
|
245
|
+
symbols=["EURUSD", "GBPUSD"], # optional position/order filter
|
|
246
|
+
include_account=True,
|
|
247
|
+
include_positions=True,
|
|
248
|
+
include_orders=True,
|
|
249
|
+
include_terminal=True,
|
|
250
|
+
with_grafana_schema=True,
|
|
251
|
+
)
|
|
252
|
+
finally:
|
|
253
|
+
client.shutdown()
|
|
254
|
+
|
|
255
|
+
# Standalone wrapper that opens/closes MT5 automatically
|
|
256
|
+
update_observability_with_config(
|
|
257
|
+
output="history.db",
|
|
258
|
+
config=Mt5Config(login=12345),
|
|
259
|
+
)
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
#### Available Grafana views
|
|
263
|
+
|
|
264
|
+
**Time-series views** (integer epoch-second `time` column; snapshot views also expose `run_id`):
|
|
265
|
+
|
|
266
|
+
| View | Source | Description |
|
|
267
|
+
| ---------------------------- | -------------------- | ---------------------------------------------------------- |
|
|
268
|
+
| `grafana_rates` | `rates` | OHLCV bars with integer epoch `time` |
|
|
269
|
+
| `grafana_ticks` | `ticks` | Tick data with integer epoch `time` |
|
|
270
|
+
| `grafana_history_deals` | `history_deals` | All deals with epoch `time` |
|
|
271
|
+
| `grafana_history_orders` | `history_orders` | All historical orders; adds epoch `time` from `time_setup` |
|
|
272
|
+
| `grafana_trade_deals` | `history_deals` | Trade deals only (`type IN (0,1)`) |
|
|
273
|
+
| `grafana_cash_events` | `history_deals` | Non-trade deals (deposits, dividends, etc.) |
|
|
274
|
+
| `grafana_symbol_pnl` | `history_deals` | Per-close-deal profit/loss per symbol |
|
|
275
|
+
| `grafana_account_snapshots` | `account_snapshots` | Account balance/equity/margin time series |
|
|
276
|
+
| `grafana_position_snapshots` | `position_snapshots` | Open position snapshots over time |
|
|
277
|
+
| `grafana_order_snapshots` | `order_snapshots` | Active order snapshots over time |
|
|
278
|
+
| `grafana_terminal_snapshots` | `terminal_snapshots` | Terminal connectivity snapshots |
|
|
279
|
+
|
|
280
|
+
**Static summary views** (no `time` column; use in table or stat panels, not time-series):
|
|
281
|
+
|
|
282
|
+
| View | Source | Description |
|
|
283
|
+
| ---------------------- | --------------- | ------------------------------------- |
|
|
284
|
+
| `grafana_realized_pnl` | `history_deals` | Cumulative realized PnL per symbol |
|
|
285
|
+
| `grafana_trade_stats` | `history_deals` | Win/loss counts and profit per symbol |
|
|
286
|
+
|
|
287
|
+
#### Example Grafana queries
|
|
288
|
+
|
|
289
|
+
```sql
|
|
290
|
+
-- Equity curve over time
|
|
291
|
+
SELECT time, equity FROM grafana_account_snapshots ORDER BY time;
|
|
292
|
+
|
|
293
|
+
-- Rolling balance by account login
|
|
294
|
+
SELECT time, login, balance FROM grafana_account_snapshots
|
|
295
|
+
WHERE login = $login ORDER BY time;
|
|
296
|
+
|
|
297
|
+
-- Open positions at latest successful snapshot
|
|
298
|
+
SELECT symbol, volume, profit FROM grafana_position_snapshots
|
|
299
|
+
WHERE run_id = (SELECT MAX(run_id) FROM snapshot_runs WHERE status = 'ok');
|
|
300
|
+
|
|
301
|
+
-- Realized PnL by symbol
|
|
302
|
+
SELECT symbol, total_profit FROM grafana_trade_stats ORDER BY total_profit DESC;
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
> **Note**: OpenTelemetry integration is intentionally not part of this release and is tracked separately.
|
|
306
|
+
|
|
207
307
|
### Incremental history SDK
|
|
208
308
|
|
|
209
309
|
For automated pipelines, use the importable incremental API instead of re-fetching fixed date ranges:
|
|
@@ -124,6 +124,63 @@ sending requests. Failed, malformed, or unknown broker retcodes are fail-closed
|
|
|
124
124
|
and returned as `status="failed"` with normalized `request` / `response` details;
|
|
125
125
|
`dry_run=True` never calls `ensure_symbol_selected()` or `order_send()`.
|
|
126
126
|
|
|
127
|
+
### Grafana observability (SQLite read model)
|
|
128
|
+
|
|
129
|
+
These helpers prepare a SQLite database as a Grafana datasource. All DDL is
|
|
130
|
+
idempotent (`CREATE TABLE IF NOT EXISTS`, `DROP VIEW IF EXISTS` + `CREATE
|
|
131
|
+
VIEW`, `CREATE INDEX IF NOT EXISTS`). Missing source tables are skipped with a
|
|
132
|
+
warning rather than raising an error.
|
|
133
|
+
|
|
134
|
+
| Symbol | Role |
|
|
135
|
+
| ---------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
136
|
+
| `update_observability` | Append one timestamped snapshot row per data type; accepts an already-connected `Mt5DataClient` |
|
|
137
|
+
| `update_observability_with_config` | Standalone wrapper: opens/closes MT5 connection automatically around `update_observability` |
|
|
138
|
+
|
|
139
|
+
Both functions write to the SQLite path given by `output=`. The optional
|
|
140
|
+
`symbols` parameter filters `positions_get` / `orders_get` by symbol.
|
|
141
|
+
`with_grafana_schema=False` (default) skips Grafana view/index setup; run
|
|
142
|
+
`grafana-schema` once to set up the schema, then call `snapshot` repeatedly
|
|
143
|
+
without this flag.
|
|
144
|
+
|
|
145
|
+
**Snapshot tables** (created by `create_snapshot_tables` in `mt5cli.grafana`):
|
|
146
|
+
|
|
147
|
+
| Table | Content |
|
|
148
|
+
| -------------------- | ----------------------------------------- |
|
|
149
|
+
| `account_snapshots` | Balance, equity, margin, free-margin, P&L |
|
|
150
|
+
| `position_snapshots` | Open positions: symbol, volume, profit, … |
|
|
151
|
+
| `order_snapshots` | Active orders: symbol, type, price, … |
|
|
152
|
+
| `terminal_snapshots` | Terminal connectivity and build info |
|
|
153
|
+
| `snapshot_runs` | Per-run status (`ok` / `error`) timestamp |
|
|
154
|
+
|
|
155
|
+
**Grafana time-series views** (integer epoch-second `time` column; snapshot views also expose `run_id`):
|
|
156
|
+
|
|
157
|
+
| View | Source |
|
|
158
|
+
| ---------------------------- | -------------------------------- |
|
|
159
|
+
| `grafana_rates` | `rates` table |
|
|
160
|
+
| `grafana_ticks` | `ticks` table |
|
|
161
|
+
| `grafana_history_deals` | `history_deals` |
|
|
162
|
+
| `grafana_history_orders` | `history_orders` |
|
|
163
|
+
| `grafana_trade_deals` | `history_deals` trade types only |
|
|
164
|
+
| `grafana_cash_events` | `history_deals` non-trade events |
|
|
165
|
+
| `grafana_symbol_pnl` | Per-close-deal P&L per symbol |
|
|
166
|
+
| `grafana_account_snapshots` | `account_snapshots` |
|
|
167
|
+
| `grafana_position_snapshots` | `position_snapshots` |
|
|
168
|
+
| `grafana_order_snapshots` | `order_snapshots` |
|
|
169
|
+
| `grafana_terminal_snapshots` | `terminal_snapshots` |
|
|
170
|
+
|
|
171
|
+
**Grafana static summary views** (no `time` column; use for table/stat panels, not time-series):
|
|
172
|
+
|
|
173
|
+
| View | Source |
|
|
174
|
+
| ---------------------- | ------------------------------------- |
|
|
175
|
+
| `grafana_realized_pnl` | Cumulative realized PnL per symbol |
|
|
176
|
+
| `grafana_trade_stats` | Win/loss counts and profit per symbol |
|
|
177
|
+
|
|
178
|
+
Lower-level helpers (`ensure_grafana_schema`, `create_grafana_views`,
|
|
179
|
+
`create_grafana_indexes`, `create_snapshot_tables`, `start_snapshot_run`,
|
|
180
|
+
`insert_account_snapshot`, `insert_position_snapshots`, `insert_order_snapshots`,
|
|
181
|
+
`insert_terminal_snapshot`, `record_snapshot_run`) are available directly from
|
|
182
|
+
`mt5cli.grafana` and are not part of the package-root stable surface.
|
|
183
|
+
|
|
127
184
|
### Errors
|
|
128
185
|
|
|
129
186
|
| Symbol | Role |
|
|
@@ -135,14 +192,15 @@ and returned as `status="failed"` with normalized `request` / `response` details
|
|
|
135
192
|
Lower-level helpers are available from their owning modules and are not part
|
|
136
193
|
of the package-root stable surface. Import them directly when needed:
|
|
137
194
|
|
|
138
|
-
| Module | Examples
|
|
139
|
-
| ------------------- |
|
|
140
|
-
| `mt5cli.
|
|
141
|
-
| `mt5cli.
|
|
142
|
-
| `mt5cli.
|
|
143
|
-
| `mt5cli.
|
|
144
|
-
| `mt5cli.
|
|
145
|
-
| `mt5cli.
|
|
195
|
+
| Module | Examples |
|
|
196
|
+
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
197
|
+
| `mt5cli.grafana` | `ensure_grafana_schema`, `create_grafana_views`, `create_grafana_indexes`, `create_snapshot_tables`, `start_snapshot_run`, `insert_account_snapshot`, `record_snapshot_run` |
|
|
198
|
+
| `mt5cli.history` | `resolve_rate_view_name`, `resolve_rate_tables`, `load_rate_data`, `build_rate_view_name` |
|
|
199
|
+
| `mt5cli.sdk` | `copy_rates_from`, `copy_ticks_from`, `account_info`, `symbols`, `mt5_summary`, `latest_rates` |
|
|
200
|
+
| `mt5cli.schemas` | `DataKind`, `normalize_dataframe`, `validate_schema`, `DEDUP_KEYS` |
|
|
201
|
+
| `mt5cli.utils` | `Dataset`, `IfExists`, `detect_format`, `export_dataframe`, `export_dataframe_to_sqlite` |
|
|
202
|
+
| `mt5cli.converters` | `normalize_symbol`, `ensure_utc`, `parse_date_range`, `granularity_name` |
|
|
203
|
+
| `mt5cli.exceptions` | `normalize_mt5_exception`, `call_with_normalized_errors`, `is_recoverable_mt5_error` |
|
|
146
204
|
|
|
147
205
|
## CLI commands
|
|
148
206
|
|
|
@@ -155,6 +213,15 @@ The Typer application in `mt5cli.cli` exposes file-export commands documented in
|
|
|
155
213
|
- Delegate to the same Python APIs described here; they are not duplicated
|
|
156
214
|
business logic.
|
|
157
215
|
|
|
216
|
+
`grafana-schema` initializes Grafana views, indexes, and snapshot tables in the
|
|
217
|
+
target SQLite database without connecting to MT5. It is idempotent and safe to
|
|
218
|
+
run repeatedly.
|
|
219
|
+
|
|
220
|
+
`snapshot` appends one timestamped row per enabled data type
|
|
221
|
+
(`--with-account`, `--with-positions`, `--with-orders`, `--with-terminal`) and
|
|
222
|
+
never places orders or modifies trading state. Both commands require
|
|
223
|
+
`-o/--output` to point at a `.db` / SQLite file.
|
|
224
|
+
|
|
158
225
|
`order-send` is the expert raw-request path; it requires `--yes` and a fully
|
|
159
226
|
constructed request payload. `close-positions` is the safer high-level helper
|
|
160
227
|
that closes open positions by `--symbol` or `--ticket` using
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Grafana Integration for mt5cli
|
|
2
|
+
|
|
3
|
+
This directory contains example configuration and dashboard files for visualising
|
|
4
|
+
mt5cli SQLite data in [Grafana](https://grafana.com/) using the
|
|
5
|
+
[Grafana SQLite datasource plugin](https://grafana.com/grafana/plugins/frser-sqlite-datasource/).
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- mt5cli installed and able to connect to MetaTrader 5
|
|
10
|
+
- Grafana 10+ with the `frser-sqlite-datasource` plugin installed
|
|
11
|
+
- (Optional) Docker and Docker Compose for the containerised setup
|
|
12
|
+
|
|
13
|
+
## Generating the SQLite database
|
|
14
|
+
|
|
15
|
+
Collect historical data and snapshot current account state:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
# Collect OHLCV history
|
|
19
|
+
mt5cli -o history.db collect-history --symbol EURUSD --date-from 2024-01-01 --date-to 2024-12-31
|
|
20
|
+
|
|
21
|
+
# Create Grafana-ready views and indexes
|
|
22
|
+
mt5cli -o history.db grafana-schema
|
|
23
|
+
|
|
24
|
+
# Snapshot current account, positions, and orders
|
|
25
|
+
mt5cli -o history.db snapshot --with-grafana-schema
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Publishing a Grafana-readable copy
|
|
29
|
+
|
|
30
|
+
Grafana reads the SQLite file directly. To avoid read/write conflicts, publish
|
|
31
|
+
a consistent copy after each update:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
mt5cli -o history.db grafana-schema --publish-copy history.mt5cli.db
|
|
35
|
+
mt5cli -o history.db snapshot --publish-copy history.mt5cli.db
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The `--publish-copy` option uses the SQLite online backup API, which is safe
|
|
39
|
+
even when the source database uses WAL journal mode.
|
|
40
|
+
|
|
41
|
+
## Configuring the datasource path
|
|
42
|
+
|
|
43
|
+
Edit `provisioning/datasources/mt5cli-sqlite.yml` and set the `path` field
|
|
44
|
+
to the absolute path of your published `.db` file:
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
jsonData:
|
|
48
|
+
path: /absolute/path/to/history.mt5cli.db
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Running Grafana on Windows (native)
|
|
52
|
+
|
|
53
|
+
1. Download and install Grafana from <https://grafana.com/grafana/download/>.
|
|
54
|
+
2. Install the SQLite plugin: `grafana-cli plugins install frser-sqlite-datasource`.
|
|
55
|
+
3. Copy `provisioning/datasources/mt5cli-sqlite.yml` into
|
|
56
|
+
`%ProgramFiles%\GrafanaLabs\grafana\conf\provisioning\datasources\`.
|
|
57
|
+
Do not copy `provisioning/dashboards/mt5cli.yml` — it contains a
|
|
58
|
+
Docker-specific dashboard path that is not valid on Windows.
|
|
59
|
+
4. Import the dashboards from `dashboards/` via the Grafana UI
|
|
60
|
+
(Dashboards → Import → Upload JSON file).
|
|
61
|
+
|
|
62
|
+
## Running with Docker Compose
|
|
63
|
+
|
|
64
|
+
Set `MT5CLI_DB_PATH` to the absolute path of your published `.db` file, then
|
|
65
|
+
start the stack:
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
# From the examples/grafana directory
|
|
69
|
+
MT5CLI_DB_PATH=/absolute/path/to/history.mt5cli.db docker compose up -d
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Alternatively, create a `.env` file in `examples/grafana/` containing
|
|
73
|
+
`MT5CLI_DB_PATH=/absolute/path/to/history.mt5cli.db` and run
|
|
74
|
+
`docker compose up -d`. Compose refuses to start if the variable is unset or
|
|
75
|
+
empty.
|
|
76
|
+
|
|
77
|
+
Then open <http://localhost:3000> (default credentials: admin / admin).
|
|
78
|
+
|
|
79
|
+
## Dashboard overview
|
|
80
|
+
|
|
81
|
+
| Dashboard | Description |
|
|
82
|
+
| ---------------------- | ------------------------------------------------------- |
|
|
83
|
+
| `mt5cli-overview.json` | Account balance, equity, margin, and snapshot freshness |
|
|
84
|
+
| `mt5cli-trades.json` | Trade P/L, win rate, symbol breakdown |
|
|
85
|
+
| `mt5cli-market.json` | OHLCV rates, spreads, and tick volume |
|
|
86
|
+
|
|
87
|
+
All panel queries use the `grafana_*` views; they do not read internal storage
|
|
88
|
+
tables directly.
|
|
89
|
+
|
|
90
|
+
## Importing dashboards
|
|
91
|
+
|
|
92
|
+
1. Open Grafana and navigate to **Dashboards → Import**.
|
|
93
|
+
2. Click **Upload JSON file** and select one of the files in `dashboards/`.
|
|
94
|
+
3. Select the `mt5cli-SQLite` datasource when prompted.
|
|
95
|
+
4. Click **Import**.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Docker Compose for Grafana with mt5cli SQLite datasource.
|
|
2
|
+
#
|
|
3
|
+
# MT5CLI_DB_PATH must be set to the absolute host path of your published .db
|
|
4
|
+
# file before running `docker compose up -d`. Compose will refuse to start if
|
|
5
|
+
# the variable is missing or empty.
|
|
6
|
+
#
|
|
7
|
+
# Example:
|
|
8
|
+
# MT5CLI_DB_PATH=/home/user/history.mt5cli.db docker compose up -d
|
|
9
|
+
|
|
10
|
+
services:
|
|
11
|
+
grafana:
|
|
12
|
+
image: grafana/grafana:latest
|
|
13
|
+
ports:
|
|
14
|
+
- "3000:3000"
|
|
15
|
+
environment:
|
|
16
|
+
GF_PATHS_PROVISIONING: /etc/grafana/provisioning
|
|
17
|
+
GF_INSTALL_PLUGINS: frser-sqlite-datasource
|
|
18
|
+
volumes:
|
|
19
|
+
- ./provisioning:/etc/grafana/provisioning:ro
|
|
20
|
+
- ./dashboards:/var/lib/grafana/dashboards:ro
|
|
21
|
+
- grafana-storage:/var/lib/grafana
|
|
22
|
+
- ${MT5CLI_DB_PATH:?Set MT5CLI_DB_PATH to the path of your published mt5cli SQLite DB}:/data/mt5cli.db:ro
|
|
23
|
+
user: "472"
|
|
24
|
+
|
|
25
|
+
volumes:
|
|
26
|
+
grafana-storage:
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"__inputs": [
|
|
3
|
+
{
|
|
4
|
+
"name": "DS_MT5CLI_SQLITE",
|
|
5
|
+
"label": "mt5cli-SQLite",
|
|
6
|
+
"description": "",
|
|
7
|
+
"type": "datasource",
|
|
8
|
+
"pluginId": "frser-sqlite-datasource",
|
|
9
|
+
"pluginName": "SQLite"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"__requires": [
|
|
13
|
+
{
|
|
14
|
+
"type": "datasource",
|
|
15
|
+
"id": "frser-sqlite-datasource",
|
|
16
|
+
"name": "SQLite",
|
|
17
|
+
"version": "1.0.0"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"annotations": { "list": [] },
|
|
21
|
+
"editable": true,
|
|
22
|
+
"fiscalYearStartMonth": 0,
|
|
23
|
+
"graphTooltip": 0,
|
|
24
|
+
"id": null,
|
|
25
|
+
"links": [],
|
|
26
|
+
"panels": [
|
|
27
|
+
{
|
|
28
|
+
"datasource": "${DS_MT5CLI_SQLITE}",
|
|
29
|
+
"fieldConfig": { "defaults": {}, "overrides": [] },
|
|
30
|
+
"gridPos": { "h": 8, "w": 24, "x": 0, "y": 0 },
|
|
31
|
+
"id": 1,
|
|
32
|
+
"title": "Close Price Over Time",
|
|
33
|
+
"type": "timeseries",
|
|
34
|
+
"targets": [
|
|
35
|
+
{
|
|
36
|
+
"rawSql": "SELECT \"time\" AS time, \"symbol\", \"close\" FROM grafana_rates WHERE \"time\" >= $__from / 1000 AND \"time\" < $__to / 1000 ORDER BY time",
|
|
37
|
+
"format": "time_series",
|
|
38
|
+
"refId": "A"
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"datasource": "${DS_MT5CLI_SQLITE}",
|
|
44
|
+
"fieldConfig": { "defaults": {}, "overrides": [] },
|
|
45
|
+
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 8 },
|
|
46
|
+
"id": 2,
|
|
47
|
+
"title": "Spread Over Time",
|
|
48
|
+
"type": "timeseries",
|
|
49
|
+
"targets": [
|
|
50
|
+
{
|
|
51
|
+
"rawSql": "SELECT \"time\" AS time, \"symbol\", \"spread\" FROM grafana_rates WHERE \"time\" >= $__from / 1000 AND \"time\" < $__to / 1000 ORDER BY time",
|
|
52
|
+
"format": "time_series",
|
|
53
|
+
"refId": "A"
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"datasource": "${DS_MT5CLI_SQLITE}",
|
|
59
|
+
"fieldConfig": { "defaults": {}, "overrides": [] },
|
|
60
|
+
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 8 },
|
|
61
|
+
"id": 3,
|
|
62
|
+
"title": "Tick Volume Over Time",
|
|
63
|
+
"type": "timeseries",
|
|
64
|
+
"targets": [
|
|
65
|
+
{
|
|
66
|
+
"rawSql": "SELECT \"time\" AS time, \"symbol\", \"tick_volume\" FROM grafana_rates WHERE \"time\" >= $__from / 1000 AND \"time\" < $__to / 1000 ORDER BY time",
|
|
67
|
+
"format": "time_series",
|
|
68
|
+
"refId": "A"
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
"refresh": "1m",
|
|
74
|
+
"schemaVersion": 36,
|
|
75
|
+
"tags": ["mt5cli", "market"],
|
|
76
|
+
"templating": {
|
|
77
|
+
"list": [
|
|
78
|
+
{
|
|
79
|
+
"current": {},
|
|
80
|
+
"hide": 0,
|
|
81
|
+
"includeAll": false,
|
|
82
|
+
"label": "Data Source",
|
|
83
|
+
"multi": false,
|
|
84
|
+
"name": "DS_MT5CLI_SQLITE",
|
|
85
|
+
"options": [],
|
|
86
|
+
"query": "frser-sqlite-datasource",
|
|
87
|
+
"refresh": 1,
|
|
88
|
+
"type": "datasource"
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
},
|
|
92
|
+
"time": { "from": "now-24h", "to": "now" },
|
|
93
|
+
"timepicker": {},
|
|
94
|
+
"timezone": "browser",
|
|
95
|
+
"title": "MT5CLI - Market Data",
|
|
96
|
+
"uid": "mt5cli-market",
|
|
97
|
+
"version": 1
|
|
98
|
+
}
|