mt5cli 1.0.3__tar.gz → 1.1.1__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.1}/.agents/skills/local-qa/scripts/qa.sh +1 -1
- {mt5cli-1.0.3 → mt5cli-1.1.1}/PKG-INFO +105 -1
- {mt5cli-1.0.3 → mt5cli-1.1.1}/README.md +100 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/docs/api/public-contract.md +80 -9
- {mt5cli-1.0.3 → mt5cli-1.1.1}/docs/api/trading.md +55 -0
- mt5cli-1.1.1/examples/grafana/README.md +95 -0
- mt5cli-1.1.1/examples/grafana/compose.yml +26 -0
- mt5cli-1.1.1/examples/grafana/dashboards/mt5cli-market.json +98 -0
- mt5cli-1.1.1/examples/grafana/dashboards/mt5cli-overview.json +254 -0
- mt5cli-1.1.1/examples/grafana/dashboards/mt5cli-trades.json +167 -0
- mt5cli-1.1.1/examples/grafana/provisioning/dashboards/mt5cli.yml +13 -0
- mt5cli-1.1.1/examples/grafana/provisioning/datasources/mt5cli-sqlite.yml +16 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/mt5cli/__init__.py +6 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/mt5cli/cli.py +125 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/mt5cli/contract.py +3 -0
- mt5cli-1.1.1/mt5cli/grafana.py +682 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/mt5cli/sdk.py +255 -17
- mt5cli-1.1.1/mt5cli/telemetry.py +354 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/mt5cli/trading.py +136 -3
- {mt5cli-1.0.3 → mt5cli-1.1.1}/mt5cli/utils.py +2 -1
- {mt5cli-1.0.3 → mt5cli-1.1.1}/pyproject.toml +8 -1
- {mt5cli-1.0.3 → mt5cli-1.1.1}/tests/conftest.py +38 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/tests/test_cli.py +220 -85
- mt5cli-1.1.1/tests/test_examples.py +75 -0
- mt5cli-1.1.1/tests/test_grafana.py +991 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/tests/test_sdk.py +487 -0
- mt5cli-1.1.1/tests/test_telemetry.py +249 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/tests/test_trading.py +176 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/uv.lock +122 -2
- {mt5cli-1.0.3 → mt5cli-1.1.1}/.agents/skills/local-qa/SKILL.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/.agents/skills/mt5cli/SKILL.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/.agents/skills/pr-feedback-triage/SKILL.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/.claude/agents/codex.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/.claude/settings.json +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/.github/FUNDING.yml +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/.github/dependabot.yml +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/.github/renovate.json +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/.github/workflows/ci.yml +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/.github/workflows/claude.yml +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/.github/workflows/release.yml +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/.gitignore +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/AGENTS.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/CLAUDE.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/LICENSE +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/docs/api/cli.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/docs/api/client.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/docs/api/converters.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/docs/api/exceptions.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/docs/api/history.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/docs/api/index.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/docs/api/schemas.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/docs/api/sdk.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/docs/api/utils.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/docs/index.md +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/mkdocs.yml +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/mt5cli/__main__.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/mt5cli/client.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/mt5cli/converters.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/mt5cli/exceptions.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/mt5cli/history.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/mt5cli/retry.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/mt5cli/schemas.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/tests/__init__.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/tests/test_contracts.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/tests/test_history.py +0 -0
- {mt5cli-1.0.3 → mt5cli-1.1.1}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mt5cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.1
|
|
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:
|
|
@@ -45,7 +45,7 @@ These names are exported from `mt5cli` and enumerated in
|
|
|
45
45
|
| `MT5Client` | Read-only data client with optional `order_check` / `order_send` |
|
|
46
46
|
| `build_config` | Build `pdmt5.Mt5Config` from connection fields; `login` accepts `int \| str \| None` — numeric strings are coerced to `int`, blank strings are treated as unset, and `${ENV_VAR}` / `$ENV_NAME` placeholders in string parameters are expanded when `allow_whole_dollar_env=True` |
|
|
47
47
|
| `mt5_session` | Context manager: initialize, login, yield client, shutdown |
|
|
48
|
-
| `create_trading_client`, `mt5_trading_session` | Trading-capable MT5 client lifecycle; returns a
|
|
48
|
+
| `create_trading_client`, `mt5_trading_session` | Trading-capable MT5 client lifecycle; returns a raw `pdmt5.Mt5DataClient` (not `MT5Client`) supporting order execution, account management, and history deal retrieval |
|
|
49
49
|
| `AccountSpec` | Generic account group: symbols plus optional credentials |
|
|
50
50
|
| `resolve_account_spec`, `resolve_account_specs` | Merge overrides and expand `${ENV_VAR}` placeholders; opt-in `allow_whole_dollar_env` for bare `$NAME` |
|
|
51
51
|
|
|
@@ -99,6 +99,7 @@ strategy entries, exits, Kelly sizing, or signal logic.
|
|
|
99
99
|
| `determine_order_limits` | SL/TP price levels from ratios |
|
|
100
100
|
| `calculate_trailing_stop_updates` | Per-ticket generic trailing stop-loss update plan |
|
|
101
101
|
| `ensure_symbol_selected` | Select/verify Market Watch visibility |
|
|
102
|
+
| `fetch_recent_history_deals_for_trading_client` | Recent deal history from a connected trading client |
|
|
102
103
|
| `place_market_order`, `close_open_positions`, `update_sltp_for_open_positions`, `update_trailing_stop_loss_for_open_positions` | Order execution helpers (`dry_run` supported) |
|
|
103
104
|
| `MarginVolume`, `OrderLimits`, `OrderExecutionResult` | Typed return contracts for order helpers |
|
|
104
105
|
| `OrderSide`, `OrderFillingMode`, `OrderTimeMode`, `PositionSide`, `ExecutionStatus` | Typed enums for order helpers |
|
|
@@ -124,6 +125,63 @@ sending requests. Failed, malformed, or unknown broker retcodes are fail-closed
|
|
|
124
125
|
and returned as `status="failed"` with normalized `request` / `response` details;
|
|
125
126
|
`dry_run=True` never calls `ensure_symbol_selected()` or `order_send()`.
|
|
126
127
|
|
|
128
|
+
### Grafana observability (SQLite read model)
|
|
129
|
+
|
|
130
|
+
These helpers prepare a SQLite database as a Grafana datasource. All DDL is
|
|
131
|
+
idempotent (`CREATE TABLE IF NOT EXISTS`, `DROP VIEW IF EXISTS` + `CREATE
|
|
132
|
+
VIEW`, `CREATE INDEX IF NOT EXISTS`). Missing source tables are skipped with a
|
|
133
|
+
warning rather than raising an error.
|
|
134
|
+
|
|
135
|
+
| Symbol | Role |
|
|
136
|
+
| ---------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
137
|
+
| `update_observability` | Append one timestamped snapshot row per data type; accepts an already-connected `Mt5DataClient` |
|
|
138
|
+
| `update_observability_with_config` | Standalone wrapper: opens/closes MT5 connection automatically around `update_observability` |
|
|
139
|
+
|
|
140
|
+
Both functions write to the SQLite path given by `output=`. The optional
|
|
141
|
+
`symbols` parameter filters `positions_get` / `orders_get` by symbol.
|
|
142
|
+
`with_grafana_schema=False` (default) skips Grafana view/index setup; run
|
|
143
|
+
`grafana-schema` once to set up the schema, then call `snapshot` repeatedly
|
|
144
|
+
without this flag.
|
|
145
|
+
|
|
146
|
+
**Snapshot tables** (created by `create_snapshot_tables` in `mt5cli.grafana`):
|
|
147
|
+
|
|
148
|
+
| Table | Content |
|
|
149
|
+
| -------------------- | ----------------------------------------- |
|
|
150
|
+
| `account_snapshots` | Balance, equity, margin, free-margin, P&L |
|
|
151
|
+
| `position_snapshots` | Open positions: symbol, volume, profit, … |
|
|
152
|
+
| `order_snapshots` | Active orders: symbol, type, price, … |
|
|
153
|
+
| `terminal_snapshots` | Terminal connectivity and build info |
|
|
154
|
+
| `snapshot_runs` | Per-run status (`ok` / `error`) timestamp |
|
|
155
|
+
|
|
156
|
+
**Grafana time-series views** (integer epoch-second `time` column; snapshot views also expose `run_id`):
|
|
157
|
+
|
|
158
|
+
| View | Source |
|
|
159
|
+
| ---------------------------- | -------------------------------- |
|
|
160
|
+
| `grafana_rates` | `rates` table |
|
|
161
|
+
| `grafana_ticks` | `ticks` table |
|
|
162
|
+
| `grafana_history_deals` | `history_deals` |
|
|
163
|
+
| `grafana_history_orders` | `history_orders` |
|
|
164
|
+
| `grafana_trade_deals` | `history_deals` trade types only |
|
|
165
|
+
| `grafana_cash_events` | `history_deals` non-trade events |
|
|
166
|
+
| `grafana_symbol_pnl` | Per-close-deal P&L per symbol |
|
|
167
|
+
| `grafana_account_snapshots` | `account_snapshots` |
|
|
168
|
+
| `grafana_position_snapshots` | `position_snapshots` |
|
|
169
|
+
| `grafana_order_snapshots` | `order_snapshots` |
|
|
170
|
+
| `grafana_terminal_snapshots` | `terminal_snapshots` |
|
|
171
|
+
|
|
172
|
+
**Grafana static summary views** (no `time` column; use for table/stat panels, not time-series):
|
|
173
|
+
|
|
174
|
+
| View | Source |
|
|
175
|
+
| ---------------------- | ------------------------------------- |
|
|
176
|
+
| `grafana_realized_pnl` | Cumulative realized PnL per symbol |
|
|
177
|
+
| `grafana_trade_stats` | Win/loss counts and profit per symbol |
|
|
178
|
+
|
|
179
|
+
Lower-level helpers (`ensure_grafana_schema`, `create_grafana_views`,
|
|
180
|
+
`create_grafana_indexes`, `create_snapshot_tables`, `start_snapshot_run`,
|
|
181
|
+
`insert_account_snapshot`, `insert_position_snapshots`, `insert_order_snapshots`,
|
|
182
|
+
`insert_terminal_snapshot`, `record_snapshot_run`) are available directly from
|
|
183
|
+
`mt5cli.grafana` and are not part of the package-root stable surface.
|
|
184
|
+
|
|
127
185
|
### Errors
|
|
128
186
|
|
|
129
187
|
| Symbol | Role |
|
|
@@ -135,14 +193,15 @@ and returned as `status="failed"` with normalized `request` / `response` details
|
|
|
135
193
|
Lower-level helpers are available from their owning modules and are not part
|
|
136
194
|
of the package-root stable surface. Import them directly when needed:
|
|
137
195
|
|
|
138
|
-
| Module | Examples
|
|
139
|
-
| ------------------- |
|
|
140
|
-
| `mt5cli.
|
|
141
|
-
| `mt5cli.
|
|
142
|
-
| `mt5cli.
|
|
143
|
-
| `mt5cli.
|
|
144
|
-
| `mt5cli.
|
|
145
|
-
| `mt5cli.
|
|
196
|
+
| Module | Examples |
|
|
197
|
+
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
198
|
+
| `mt5cli.grafana` | `ensure_grafana_schema`, `create_grafana_views`, `create_grafana_indexes`, `create_snapshot_tables`, `start_snapshot_run`, `insert_account_snapshot`, `record_snapshot_run` |
|
|
199
|
+
| `mt5cli.history` | `resolve_rate_view_name`, `resolve_rate_tables`, `load_rate_data`, `build_rate_view_name` |
|
|
200
|
+
| `mt5cli.sdk` | `copy_rates_from`, `copy_ticks_from`, `account_info`, `symbols`, `mt5_summary`, `latest_rates` |
|
|
201
|
+
| `mt5cli.schemas` | `DataKind`, `normalize_dataframe`, `validate_schema`, `DEDUP_KEYS` |
|
|
202
|
+
| `mt5cli.utils` | `Dataset`, `IfExists`, `detect_format`, `export_dataframe`, `export_dataframe_to_sqlite` |
|
|
203
|
+
| `mt5cli.converters` | `normalize_symbol`, `ensure_utc`, `parse_date_range`, `granularity_name` |
|
|
204
|
+
| `mt5cli.exceptions` | `normalize_mt5_exception`, `call_with_normalized_errors`, `is_recoverable_mt5_error` |
|
|
146
205
|
|
|
147
206
|
## CLI commands
|
|
148
207
|
|
|
@@ -155,6 +214,15 @@ The Typer application in `mt5cli.cli` exposes file-export commands documented in
|
|
|
155
214
|
- Delegate to the same Python APIs described here; they are not duplicated
|
|
156
215
|
business logic.
|
|
157
216
|
|
|
217
|
+
`grafana-schema` initializes Grafana views, indexes, and snapshot tables in the
|
|
218
|
+
target SQLite database without connecting to MT5. It is idempotent and safe to
|
|
219
|
+
run repeatedly.
|
|
220
|
+
|
|
221
|
+
`snapshot` appends one timestamped row per enabled data type
|
|
222
|
+
(`--with-account`, `--with-positions`, `--with-orders`, `--with-terminal`) and
|
|
223
|
+
never places orders or modifies trading state. Both commands require
|
|
224
|
+
`-o/--output` to point at a `.db` / SQLite file.
|
|
225
|
+
|
|
158
226
|
`order-send` is the expert raw-request path; it requires `--yes` and a fully
|
|
159
227
|
constructed request payload. `close-positions` is the safer high-level helper
|
|
160
228
|
that closes open positions by `--symbol` or `--ticket` using
|
|
@@ -187,6 +255,9 @@ The following belong in consuming applications, not in mt5cli:
|
|
|
187
255
|
- Backtesting, walk-forward analysis, or parameter optimization
|
|
188
256
|
- Strategy-specific risk policy, position sizing systems, or Kelly fractions
|
|
189
257
|
- Entry/exit decision logic or YAML strategy semantics
|
|
258
|
+
- Entry-deal classification, Kelly fractions, or betting-specific deal transformations
|
|
259
|
+
(use `fetch_recent_history_deals_for_trading_client` to retrieve raw deal data, then
|
|
260
|
+
apply downstream transformations in your own adapter layer)
|
|
190
261
|
- Application-specific credential schema keys wired into mt5cli internals
|
|
191
262
|
|
|
192
263
|
mt5cli provides connection lifecycle, normalized data access, SQLite history
|
|
@@ -10,6 +10,11 @@ client supporting order execution and account management, use `Mt5Config.path`
|
|
|
10
10
|
to launch the terminal when configured, and `mt5_trading_session()` always
|
|
11
11
|
calls `shutdown()` on exit.
|
|
12
12
|
|
|
13
|
+
`create_trading_client()` returns a raw `pdmt5.Mt5DataClient` instance, not the
|
|
14
|
+
higher-level `MT5Client` wrapper. Use `mt5_session()` / `MT5Client` for
|
|
15
|
+
read-only data collection; use `mt5_trading_session()` only where order
|
|
16
|
+
placement or trading calculations are required.
|
|
17
|
+
|
|
13
18
|
```python
|
|
14
19
|
from mt5cli import create_trading_client, mt5_trading_session
|
|
15
20
|
|
|
@@ -182,6 +187,55 @@ updates: list[OrderExecutionResult] = update_sltp_for_open_positions(
|
|
|
182
187
|
Closes issue #33: strategy-neutral order planning and execution helpers exposed
|
|
183
188
|
through the stable package root without embedding entry/exit policy.
|
|
184
189
|
|
|
190
|
+
## Retrieving recent history deals
|
|
191
|
+
|
|
192
|
+
`fetch_recent_history_deals_for_trading_client()` fetches history deals from an
|
|
193
|
+
already-connected trading client over a trailing time window. It works directly
|
|
194
|
+
with the object returned by `create_trading_client()` (a raw
|
|
195
|
+
`pdmt5.Mt5DataClient`) without requiring any additional wrapping.
|
|
196
|
+
|
|
197
|
+
The helper returns a chronologically sorted DataFrame with a `RangeIndex` and
|
|
198
|
+
all columns from the underlying client (`time`, `symbol`, `type`, `entry`,
|
|
199
|
+
`volume`, `profit`, `position_id`, etc.). It does **not** apply any
|
|
200
|
+
strategy-specific transformations — entry/exit classification, Kelly fractions,
|
|
201
|
+
and betting semantics belong in downstream applications.
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
from mt5cli import (
|
|
205
|
+
create_trading_client,
|
|
206
|
+
fetch_recent_history_deals_for_trading_client,
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
client = create_trading_client(login=12345, server="Broker-Demo")
|
|
210
|
+
try:
|
|
211
|
+
deals_df = fetch_recent_history_deals_for_trading_client(
|
|
212
|
+
client,
|
|
213
|
+
symbol="JP225",
|
|
214
|
+
hours=24,
|
|
215
|
+
)
|
|
216
|
+
finally:
|
|
217
|
+
client.shutdown()
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Or inside a managed session:
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
from mt5cli import fetch_recent_history_deals_for_trading_client, mt5_trading_session
|
|
224
|
+
|
|
225
|
+
with mt5_trading_session(login=12345, server="Broker-Demo") as client:
|
|
226
|
+
deals_df = fetch_recent_history_deals_for_trading_client(
|
|
227
|
+
client,
|
|
228
|
+
symbol="JP225",
|
|
229
|
+
hours=48,
|
|
230
|
+
)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
`hours` must be positive; `date_to` defaults to `datetime.now(UTC)`. An empty
|
|
234
|
+
or `None` result from the underlying client is normalized to an empty DataFrame.
|
|
235
|
+
|
|
236
|
+
Downstream packages own all strategy-specific transformations. mt5cli does not
|
|
237
|
+
provide entry-deal classification, Kelly sizing, or any betting-specific helpers.
|
|
238
|
+
|
|
185
239
|
## Migration from application-local helpers
|
|
186
240
|
|
|
187
241
|
| Application-local concern | mt5cli replacement |
|
|
@@ -192,6 +246,7 @@ through the stable package root without embedding entry/exit policy.
|
|
|
192
246
|
| Local broker volume step normalization | `normalize_order_volume()` |
|
|
193
247
|
| Local order or position margin estimation | `estimate_order_margin()`, `calculate_positions_margin()` |
|
|
194
248
|
| Local closed-bar fetch from a trading session | `fetch_latest_closed_rates_for_trading_client()`, `fetch_latest_closed_rates_indexed()` |
|
|
249
|
+
| Local recent deal history fetch from a trading session | `fetch_recent_history_deals_for_trading_client()` |
|
|
195
250
|
| Local SL/TP price derivation | `determine_order_limits()` |
|
|
196
251
|
| Throttled SQLite history loop with ad-hoc error handling | `ThrottledHistoryUpdater(suppress_errors=True)` |
|
|
197
252
|
|
|
@@ -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:
|