mt5cli 0.9.6__tar.gz → 1.0.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.
Files changed (57) hide show
  1. {mt5cli-0.9.6 → mt5cli-1.0.0}/PKG-INFO +17 -11
  2. {mt5cli-0.9.6 → mt5cli-1.0.0}/README.md +13 -8
  3. {mt5cli-0.9.6 → mt5cli-1.0.0}/docs/api/history.md +4 -2
  4. {mt5cli-0.9.6 → mt5cli-1.0.0}/docs/api/index.md +3 -5
  5. {mt5cli-0.9.6 → mt5cli-1.0.0}/docs/api/public-contract.md +54 -89
  6. {mt5cli-0.9.6 → mt5cli-1.0.0}/docs/api/sdk.md +2 -1
  7. {mt5cli-0.9.6 → mt5cli-1.0.0}/docs/api/trading.md +6 -5
  8. {mt5cli-0.9.6 → mt5cli-1.0.0}/docs/index.md +11 -9
  9. {mt5cli-0.9.6 → mt5cli-1.0.0}/mkdocs.yml +0 -1
  10. {mt5cli-0.9.6 → mt5cli-1.0.0}/mt5cli/__init__.py +1 -155
  11. mt5cli-1.0.0/mt5cli/contract.py +69 -0
  12. {mt5cli-0.9.6 → mt5cli-1.0.0}/mt5cli/exceptions.py +9 -4
  13. {mt5cli-0.9.6 → mt5cli-1.0.0}/mt5cli/sdk.py +7 -2
  14. {mt5cli-0.9.6 → mt5cli-1.0.0}/mt5cli/trading.py +153 -91
  15. {mt5cli-0.9.6 → mt5cli-1.0.0}/mt5cli/utils.py +13 -6
  16. {mt5cli-0.9.6 → mt5cli-1.0.0}/pyproject.toml +10 -4
  17. {mt5cli-0.9.6 → mt5cli-1.0.0}/tests/test_contracts.py +138 -111
  18. {mt5cli-0.9.6 → mt5cli-1.0.0}/tests/test_history.py +3 -1
  19. {mt5cli-0.9.6 → mt5cli-1.0.0}/tests/test_trading.py +44 -43
  20. {mt5cli-0.9.6 → mt5cli-1.0.0}/tests/test_utils.py +21 -13
  21. {mt5cli-0.9.6 → mt5cli-1.0.0}/uv.lock +14 -7
  22. mt5cli-0.9.6/docs/api/storage.md +0 -3
  23. mt5cli-0.9.6/mt5cli/contract.py +0 -151
  24. mt5cli-0.9.6/mt5cli/storage.py +0 -49
  25. {mt5cli-0.9.6 → mt5cli-1.0.0}/.agents/skills/local-qa/SKILL.md +0 -0
  26. {mt5cli-0.9.6 → mt5cli-1.0.0}/.agents/skills/local-qa/scripts/qa.sh +0 -0
  27. {mt5cli-0.9.6 → mt5cli-1.0.0}/.agents/skills/mt5cli/SKILL.md +0 -0
  28. {mt5cli-0.9.6 → mt5cli-1.0.0}/.agents/skills/pr-feedback-triage/SKILL.md +0 -0
  29. {mt5cli-0.9.6 → mt5cli-1.0.0}/.claude/agents/codex.md +0 -0
  30. {mt5cli-0.9.6 → mt5cli-1.0.0}/.claude/settings.json +0 -0
  31. {mt5cli-0.9.6 → mt5cli-1.0.0}/.github/FUNDING.yml +0 -0
  32. {mt5cli-0.9.6 → mt5cli-1.0.0}/.github/dependabot.yml +0 -0
  33. {mt5cli-0.9.6 → mt5cli-1.0.0}/.github/renovate.json +0 -0
  34. {mt5cli-0.9.6 → mt5cli-1.0.0}/.github/workflows/ci.yml +0 -0
  35. {mt5cli-0.9.6 → mt5cli-1.0.0}/.github/workflows/claude.yml +0 -0
  36. {mt5cli-0.9.6 → mt5cli-1.0.0}/.github/workflows/release.yml +0 -0
  37. {mt5cli-0.9.6 → mt5cli-1.0.0}/.gitignore +0 -0
  38. {mt5cli-0.9.6 → mt5cli-1.0.0}/AGENTS.md +0 -0
  39. {mt5cli-0.9.6 → mt5cli-1.0.0}/CLAUDE.md +0 -0
  40. {mt5cli-0.9.6 → mt5cli-1.0.0}/LICENSE +0 -0
  41. {mt5cli-0.9.6 → mt5cli-1.0.0}/docs/api/cli.md +0 -0
  42. {mt5cli-0.9.6 → mt5cli-1.0.0}/docs/api/client.md +0 -0
  43. {mt5cli-0.9.6 → mt5cli-1.0.0}/docs/api/converters.md +0 -0
  44. {mt5cli-0.9.6 → mt5cli-1.0.0}/docs/api/exceptions.md +0 -0
  45. {mt5cli-0.9.6 → mt5cli-1.0.0}/docs/api/schemas.md +0 -0
  46. {mt5cli-0.9.6 → mt5cli-1.0.0}/docs/api/utils.md +0 -0
  47. {mt5cli-0.9.6 → mt5cli-1.0.0}/mt5cli/__main__.py +0 -0
  48. {mt5cli-0.9.6 → mt5cli-1.0.0}/mt5cli/cli.py +0 -0
  49. {mt5cli-0.9.6 → mt5cli-1.0.0}/mt5cli/client.py +0 -0
  50. {mt5cli-0.9.6 → mt5cli-1.0.0}/mt5cli/converters.py +0 -0
  51. {mt5cli-0.9.6 → mt5cli-1.0.0}/mt5cli/history.py +0 -0
  52. {mt5cli-0.9.6 → mt5cli-1.0.0}/mt5cli/retry.py +0 -0
  53. {mt5cli-0.9.6 → mt5cli-1.0.0}/mt5cli/schemas.py +0 -0
  54. {mt5cli-0.9.6 → mt5cli-1.0.0}/tests/__init__.py +0 -0
  55. {mt5cli-0.9.6 → mt5cli-1.0.0}/tests/conftest.py +0 -0
  56. {mt5cli-0.9.6 → mt5cli-1.0.0}/tests/test_cli.py +0 -0
  57. {mt5cli-0.9.6 → mt5cli-1.0.0}/tests/test_sdk.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mt5cli
3
- Version: 0.9.6
3
+ Version: 1.0.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>
@@ -17,9 +17,10 @@ Classifier: Programming Language :: Python :: 3
17
17
  Classifier: Topic :: Office/Business :: Financial :: Investment
18
18
  Requires-Python: <3.14,>=3.11
19
19
  Requires-Dist: click>=8.1.0
20
- Requires-Dist: pdmt5>=0.3.0
21
- Requires-Dist: pyarrow>=19.0.0
20
+ Requires-Dist: pdmt5>=1.0.0
22
21
  Requires-Dist: typer>=0.15.0
22
+ Provides-Extra: parquet
23
+ Requires-Dist: pyarrow>=19.0.0; extra == 'parquet'
23
24
  Description-Content-Type: text/markdown
24
25
 
25
26
  # mt5cli
@@ -53,6 +54,12 @@ Built on top of [pdmt5](https://github.com/dceoy/pdmt5), a pandas-based data han
53
54
  pip install -U mt5cli MetaTrader5
54
55
  ```
55
56
 
57
+ Parquet export is not included by default. To enable it, install the `parquet` extra:
58
+
59
+ ```bash
60
+ pip install -U "mt5cli[parquet]" MetaTrader5
61
+ ```
62
+
56
63
  ## Python API (downstream packages)
57
64
 
58
65
  Import `MT5Client` for generic MT5 data access, schema normalization, and optional order primitives.
@@ -62,16 +69,14 @@ from datetime import UTC, datetime
62
69
  from pathlib import Path
63
70
 
64
71
  from mt5cli import (
65
- DataKind,
66
- Dataset,
67
72
  MT5Client,
68
73
  build_config,
69
74
  collect_history,
70
- export_dataframe,
71
75
  mt5_session,
72
- normalize_dataframe,
73
76
  update_history_with_config,
74
77
  )
78
+ from mt5cli.schemas import DataKind, normalize_dataframe
79
+ from mt5cli.utils import Dataset, export_dataframe
75
80
 
76
81
  # Persistent session for multiple calls
77
82
  with mt5_session(build_config(login=12345, server="Broker-Demo")) as client:
@@ -107,7 +112,7 @@ update_history_with_config(
107
112
  )
108
113
  ```
109
114
 
110
- Schema contracts live in `mt5cli.schemas` (`DataKind`, `validate_schema`, `normalize_dataframe`). Storage helpers are re-exported from `mt5cli.storage` and the package root.
115
+ Schema contracts live in `mt5cli.schemas` (`DataKind`, `validate_schema`, `normalize_dataframe`). Export and storage helpers are in `mt5cli.utils` (`Dataset`, `export_dataframe`) and `mt5cli.history`.
111
116
 
112
117
  `MT5Client.order_send()` is a live execution primitive: it can place real trades on the connected account. mt5cli does not implement strategy logic, signal generation, backtesting, or optimization — downstream applications must gate live execution explicitly.
113
118
 
@@ -230,7 +235,8 @@ For automated pipelines, use the importable incremental API instead of re-fetchi
230
235
 
231
236
  ```python
232
237
  from pdmt5 import Mt5Config, Mt5DataClient
233
- from mt5cli import Dataset, update_history, update_history_with_config
238
+ from mt5cli import update_history, update_history_with_config
239
+ from mt5cli.utils import Dataset
234
240
 
235
241
  # Reuse an already-connected pdmt5 client (does not open/close MT5)
236
242
  client = Mt5DataClient(config=Mt5Config(login=12345))
@@ -265,7 +271,7 @@ update_history_with_config(
265
271
  - **Rate view resolution**: use `resolve_rate_view_name()` / `resolve_rate_view_names()` to map symbols and granularities to existing SQLite compatibility views without creating databases. Both accept `None` (or a missing path) and return deterministic default names unless `require_existing=True`.
266
272
  - **Rate view loading**: use `load_rate_data()` / `load_rate_data_from_connection()` to load a SQLite rate table or view into a `DatetimeIndex` DataFrame.
267
273
  - **Multi-series rate loading**: use `build_rate_targets()` to build neutral `RateTarget(symbol, timeframe)` pairs, `resolve_rate_tables()` to map them to table/view names (pass `require_existing=True` for strict resolution), and `load_rate_series_from_sqlite()` to load them into a mapping keyed by `(symbol, integer timeframe)`. The loader requires existing managed views unless `explicit_tables` is supplied, and rejects duplicate `(symbol, timeframe)` targets.
268
- - **Multi-account latest rates**: use `collect_latest_rates_for_accounts()` with `AccountSpec` to read the latest bars for several account groups, merged into a `(symbol, integer timeframe)` mapping. For long-running pollers, `collect_latest_rates_for_accounts_with_retries()` adds bounded exponential backoff that retries only `pdmt5.Mt5TradingError` / `pdmt5.Mt5RuntimeError` and re-raises once `retry_count` is exhausted.
274
+ - **Multi-account latest rates**: use `collect_latest_rates_for_accounts()` with `AccountSpec` to read the latest bars for several account groups, merged into a `(symbol, integer timeframe)` mapping. For long-running pollers, `collect_latest_rates_for_accounts_with_retries()` adds bounded exponential backoff that retries only recoverable MT5 errors and re-raises once `retry_count` is exhausted.
269
275
  - **Latest closed bars**: use `collect_latest_closed_rates_for_accounts()` when downstream logic must exclude the still-forming current bar. It fetches `count + 1` bars at `start_pos=0`, drops the last row with `drop_forming_rate_bar()`, and validates each series is non-empty. `collect_latest_closed_rates_by_granularity()` returns the same data keyed by `(symbol, granularity_name)` such as `("EURUSD", "M1")`.
270
276
 
271
277
  ```python
@@ -282,7 +288,7 @@ eurusd_m1 = rates["EURUSD", "M1"] # closed bars only
282
288
 
283
289
  - **Credential resolution**: use `resolve_account_spec()` / `resolve_account_specs()` to merge explicit override values over `AccountSpec` fields and expand `${ENV_VAR}` placeholders (via `substitute_env_placeholders()`), raising `ValueError` for missing variables. This keeps secrets out of plan/config files without coupling to any strategy code. For config dicts or nested structures loaded from YAML/TOML, use `substitute_mapping_values(data, keys={"login", "password"})` to expand placeholders only for caller-specified keys — key names are never hard-coded in mt5cli.
284
290
  - **Throttled history updates**: use `ThrottledHistoryUpdater` to wrap `update_history()` with a minimum `interval_seconds` between successful runs (monotonic clock). Call `should_update()` / `update(client, symbols)` from an application loop; errors propagate by default, or pass `suppress_errors=True` to swallow recoverable `Mt5*Error`, `sqlite3.Error`, `ValueError`, `OSError`, and MT5 client capability errors for history API methods without advancing the throttle (other `AttributeError` / `TypeError` values always propagate). Pass `update_backend` to inject a custom history update callable (same keyword arguments as `update_history`) instead of monkey-patching `mt5cli.sdk.update_history`.
285
- - **Trading session helpers**: use `mt5_trading_session()` for a trading-capable `pdmt5.Mt5TradingClient` that initializes/logs in via `Mt5Config.path` and always shuts down safely. Pair with `detect_position_side()`, `calculate_margin_and_volume()`, and `determine_order_limits()` for generic position and sizing utilities. Keep read-only collection on `mt5_session()` / `MT5Client`.
291
+ - **Trading session helpers**: use `mt5_trading_session()` for a trading-capable client that initializes/logs in via `Mt5Config.path` and always shuts down safely. Pair with `detect_position_side()`, `calculate_margin_and_volume()`, and `determine_order_limits()` for generic position and sizing utilities. Keep read-only collection on `mt5_session()` / `MT5Client`.
286
292
  - **Granularity-keyed rate loading**: `load_rate_series_by_granularity()` builds targets with `build_rate_targets()`, loads them with `load_rate_series_from_sqlite()`, and returns a mapping keyed by `(symbol | None, granularity_name)` such as `("EURUSD", "M1")` to reduce downstream boilerplate.
287
293
  - **MT5 session helper**: use the `mt5_session()` context manager to attach to (or, when `Mt5Config.path` is set, launch) an MT5 terminal, log in, and yield a connected `MT5Client` that shuts down on exit.
288
294
  - **SQLite export helpers**: use `export_dataframe_to_sqlite()` for append mode, optional index export, and post-write deduplication by key columns.
@@ -29,6 +29,12 @@ Built on top of [pdmt5](https://github.com/dceoy/pdmt5), a pandas-based data han
29
29
  pip install -U mt5cli MetaTrader5
30
30
  ```
31
31
 
32
+ Parquet export is not included by default. To enable it, install the `parquet` extra:
33
+
34
+ ```bash
35
+ pip install -U "mt5cli[parquet]" MetaTrader5
36
+ ```
37
+
32
38
  ## Python API (downstream packages)
33
39
 
34
40
  Import `MT5Client` for generic MT5 data access, schema normalization, and optional order primitives.
@@ -38,16 +44,14 @@ from datetime import UTC, datetime
38
44
  from pathlib import Path
39
45
 
40
46
  from mt5cli import (
41
- DataKind,
42
- Dataset,
43
47
  MT5Client,
44
48
  build_config,
45
49
  collect_history,
46
- export_dataframe,
47
50
  mt5_session,
48
- normalize_dataframe,
49
51
  update_history_with_config,
50
52
  )
53
+ from mt5cli.schemas import DataKind, normalize_dataframe
54
+ from mt5cli.utils import Dataset, export_dataframe
51
55
 
52
56
  # Persistent session for multiple calls
53
57
  with mt5_session(build_config(login=12345, server="Broker-Demo")) as client:
@@ -83,7 +87,7 @@ update_history_with_config(
83
87
  )
84
88
  ```
85
89
 
86
- Schema contracts live in `mt5cli.schemas` (`DataKind`, `validate_schema`, `normalize_dataframe`). Storage helpers are re-exported from `mt5cli.storage` and the package root.
90
+ Schema contracts live in `mt5cli.schemas` (`DataKind`, `validate_schema`, `normalize_dataframe`). Export and storage helpers are in `mt5cli.utils` (`Dataset`, `export_dataframe`) and `mt5cli.history`.
87
91
 
88
92
  `MT5Client.order_send()` is a live execution primitive: it can place real trades on the connected account. mt5cli does not implement strategy logic, signal generation, backtesting, or optimization — downstream applications must gate live execution explicitly.
89
93
 
@@ -206,7 +210,8 @@ For automated pipelines, use the importable incremental API instead of re-fetchi
206
210
 
207
211
  ```python
208
212
  from pdmt5 import Mt5Config, Mt5DataClient
209
- from mt5cli import Dataset, update_history, update_history_with_config
213
+ from mt5cli import update_history, update_history_with_config
214
+ from mt5cli.utils import Dataset
210
215
 
211
216
  # Reuse an already-connected pdmt5 client (does not open/close MT5)
212
217
  client = Mt5DataClient(config=Mt5Config(login=12345))
@@ -241,7 +246,7 @@ update_history_with_config(
241
246
  - **Rate view resolution**: use `resolve_rate_view_name()` / `resolve_rate_view_names()` to map symbols and granularities to existing SQLite compatibility views without creating databases. Both accept `None` (or a missing path) and return deterministic default names unless `require_existing=True`.
242
247
  - **Rate view loading**: use `load_rate_data()` / `load_rate_data_from_connection()` to load a SQLite rate table or view into a `DatetimeIndex` DataFrame.
243
248
  - **Multi-series rate loading**: use `build_rate_targets()` to build neutral `RateTarget(symbol, timeframe)` pairs, `resolve_rate_tables()` to map them to table/view names (pass `require_existing=True` for strict resolution), and `load_rate_series_from_sqlite()` to load them into a mapping keyed by `(symbol, integer timeframe)`. The loader requires existing managed views unless `explicit_tables` is supplied, and rejects duplicate `(symbol, timeframe)` targets.
244
- - **Multi-account latest rates**: use `collect_latest_rates_for_accounts()` with `AccountSpec` to read the latest bars for several account groups, merged into a `(symbol, integer timeframe)` mapping. For long-running pollers, `collect_latest_rates_for_accounts_with_retries()` adds bounded exponential backoff that retries only `pdmt5.Mt5TradingError` / `pdmt5.Mt5RuntimeError` and re-raises once `retry_count` is exhausted.
249
+ - **Multi-account latest rates**: use `collect_latest_rates_for_accounts()` with `AccountSpec` to read the latest bars for several account groups, merged into a `(symbol, integer timeframe)` mapping. For long-running pollers, `collect_latest_rates_for_accounts_with_retries()` adds bounded exponential backoff that retries only recoverable MT5 errors and re-raises once `retry_count` is exhausted.
245
250
  - **Latest closed bars**: use `collect_latest_closed_rates_for_accounts()` when downstream logic must exclude the still-forming current bar. It fetches `count + 1` bars at `start_pos=0`, drops the last row with `drop_forming_rate_bar()`, and validates each series is non-empty. `collect_latest_closed_rates_by_granularity()` returns the same data keyed by `(symbol, granularity_name)` such as `("EURUSD", "M1")`.
246
251
 
247
252
  ```python
@@ -258,7 +263,7 @@ eurusd_m1 = rates["EURUSD", "M1"] # closed bars only
258
263
 
259
264
  - **Credential resolution**: use `resolve_account_spec()` / `resolve_account_specs()` to merge explicit override values over `AccountSpec` fields and expand `${ENV_VAR}` placeholders (via `substitute_env_placeholders()`), raising `ValueError` for missing variables. This keeps secrets out of plan/config files without coupling to any strategy code. For config dicts or nested structures loaded from YAML/TOML, use `substitute_mapping_values(data, keys={"login", "password"})` to expand placeholders only for caller-specified keys — key names are never hard-coded in mt5cli.
260
265
  - **Throttled history updates**: use `ThrottledHistoryUpdater` to wrap `update_history()` with a minimum `interval_seconds` between successful runs (monotonic clock). Call `should_update()` / `update(client, symbols)` from an application loop; errors propagate by default, or pass `suppress_errors=True` to swallow recoverable `Mt5*Error`, `sqlite3.Error`, `ValueError`, `OSError`, and MT5 client capability errors for history API methods without advancing the throttle (other `AttributeError` / `TypeError` values always propagate). Pass `update_backend` to inject a custom history update callable (same keyword arguments as `update_history`) instead of monkey-patching `mt5cli.sdk.update_history`.
261
- - **Trading session helpers**: use `mt5_trading_session()` for a trading-capable `pdmt5.Mt5TradingClient` that initializes/logs in via `Mt5Config.path` and always shuts down safely. Pair with `detect_position_side()`, `calculate_margin_and_volume()`, and `determine_order_limits()` for generic position and sizing utilities. Keep read-only collection on `mt5_session()` / `MT5Client`.
266
+ - **Trading session helpers**: use `mt5_trading_session()` for a trading-capable client that initializes/logs in via `Mt5Config.path` and always shuts down safely. Pair with `detect_position_side()`, `calculate_margin_and_volume()`, and `determine_order_limits()` for generic position and sizing utilities. Keep read-only collection on `mt5_session()` / `MT5Client`.
262
267
  - **Granularity-keyed rate loading**: `load_rate_series_by_granularity()` builds targets with `build_rate_targets()`, loads them with `load_rate_series_from_sqlite()`, and returns a mapping keyed by `(symbol | None, granularity_name)` such as `("EURUSD", "M1")` to reduce downstream boilerplate.
263
268
  - **MT5 session helper**: use the `mt5_session()` context manager to attach to (or, when `Mt5Config.path` is set, launch) an MT5 terminal, log in, and yield a connected `MT5Client` that shuts down on exit.
264
269
  - **SQLite export helpers**: use `export_dataframe_to_sqlite()` for append mode, optional index export, and post-write deduplication by key columns.
@@ -182,12 +182,14 @@ targets without hard-coding view names:
182
182
  from pathlib import Path
183
183
 
184
184
  from mt5cli import (
185
- load_rate_data,
186
185
  load_rate_series_by_granularity,
187
186
  load_rate_series_from_sqlite,
187
+ )
188
+ from mt5cli.history import (
189
+ load_rate_data,
188
190
  resolve_rate_table_name,
191
+ resolve_rate_view_name,
189
192
  )
190
- from mt5cli.history import resolve_rate_view_name
191
193
 
192
194
  view = resolve_rate_view_name(Path("history.db"), "EURUSD", "M1", require_existing=True)
193
195
  rates = load_rate_data(Path("history.db"), view, count=1000)
@@ -13,7 +13,6 @@ responsibilities.
13
13
  | [Public API Contract](public-contract.md) | Stable downstream SDK exports, CLI boundary, and out-of-scope items |
14
14
  | [Client](client.md) | `MT5Client` session abstraction for data access and order primitives |
15
15
  | [Schemas](schemas.md) | Canonical DataFrame contracts and normalization helpers |
16
- | [Storage](storage.md) | CSV/JSON/Parquet/SQLite export and history collection helpers |
17
16
  | [Converters](converters.md) | Symbol, timeframe, timezone, and date-range utilities |
18
17
  | [Exceptions](exceptions.md) | Stable mt5cli exception types and MT5 error normalization |
19
18
  | [SDK](sdk.md) | Module-level fetch helpers, multi-account collectors, incremental history |
@@ -30,15 +29,14 @@ flowchart TD
30
29
  CLI["mt5cli CLI"] --> Client
31
30
  Client --> SDK["sdk / pdmt5"]
32
31
  Client --> Schemas["schemas"]
33
- Storage["storage"] --> History["history SQLite"]
34
- Storage --> Utils["utils export"]
32
+ History["history SQLite"] --> Utils["utils export"]
35
33
  SDK --> PDMT5["pdmt5.Mt5DataClient"]
36
34
  ```
37
35
 
38
36
  Downstream packages should depend on the package root exports documented in the
39
37
  [Public API Contract](public-contract.md) (`MT5Client`,
40
- `DataKind`, `normalize_dataframe`, `collect_history`, `load_rate_data`,
41
- `resolve_rate_view_name`, etc.) rather than private modules.
38
+ `collect_history`, `load_rate_series_from_sqlite`, etc.) rather than private
39
+ modules. Lower-level helpers are accessible directly from their owning modules.
42
40
 
43
41
  `MT5Client.order_send()` is a live execution primitive that can place real trades. mt5cli exposes minimal execution helpers only; strategy logic, signals, backtests, and optimization remain out of scope and must be implemented downstream with explicit execution gating.
44
42
 
@@ -1,29 +1,41 @@
1
1
  # Public API Contract
2
2
 
3
- mt5cli is the generic MT5 data and execution infrastructure layer for downstream
4
- Python applications. The intended dependency direction is:
3
+ mt5cli is the canonical operational trading SDK and CLI/batch layer over pdmt5.
4
+ The intended dependency direction is:
5
5
 
6
6
  ```text
7
7
  downstream app -> mt5cli -> pdmt5 -> MetaTrader 5
8
8
  ```
9
9
 
10
- Downstream packages should import from the package root (`from mt5cli import
11
- ...`) and use the public tier sets in `mt5cli.contract` to distinguish API
12
- stability. CLI commands mirror the same behavior but are not importable Python
13
- APIs.
10
+ ## Responsibility boundary
11
+
12
+ | Layer | Owns |
13
+ | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
14
+ | **pdmt5** | MT5 core wrapper; DataFrame/dict conversion; canonical MT5 constants and parsers; direct low-level order primitives |
15
+ | **mt5cli** | CLI/batch workflows; SQLite history collection; normalized datasets; closed-bar helpers; small downstream operational SDK; generic broker-facing margin/volume/order orchestration |
16
+ | **downstream** | Strategy logic; signals; risk policy; backtesting; optimization; YAML/application semantics |
14
17
 
15
- ## Public API tiers
18
+ Downstream code should import raw pdmt5 types and constants (such as
19
+ `Mt5Config`, `Mt5RuntimeError`, `TIMEFRAME_MAP`, `COPY_TICKS_MAP`) directly
20
+ from `pdmt5` when needed. mt5cli does not serve as a pass-through compatibility
21
+ namespace for pdmt5. mt5cli's trading helpers type their client parameter against
22
+ an internal protocol backed by `pdmt5.Mt5DataClient`; `Mt5TradingClient` is no
23
+ longer required. `Mt5TradingError` is conditionally imported where still present
24
+ in pdmt5, but mt5cli raises `Mt5OperationError` for all trading-related failures.
16
25
 
17
- mt5cli classifies package-root imports by intended downstream use:
26
+ Note: the former `mt5cli` re-export `TICK_FLAG_MAP` corresponds to `COPY_TICKS_MAP`
27
+ in pdmt5 — the name changed, it was not simply moved.
18
28
 
19
- | Tier | Contract set | Meaning |
20
- | ---------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
21
- | Stable core | `STABLE_SDK_EXPORTS` | Preferred SDK surface for downstream MT5 infrastructure adapters. Changes require a deliberate compatibility path. |
22
- | Secondary public | `SECONDARY_PUBLIC_EXPORTS` | Public helpers for CLI/export/schema integrations and lower-level MT5 wrappers. Importable, but less central to the downstream trading SDK. |
29
+ Downstream packages should import from the package root (`from mt5cli import
30
+ ...`). The contract set `STABLE_SDK_EXPORTS` in `mt5cli.contract` enumerates
31
+ every package-root symbol. Lower-level helpers (schema utilities, export
32
+ functions, parser helpers, low-level MT5 wrappers) are available directly from
33
+ their owning modules (`mt5cli.schemas`, `mt5cli.utils`, `mt5cli.converters`,
34
+ `mt5cli.sdk`, etc.) and are not part of the root SDK surface.
23
35
 
24
36
  ## Stable downstream SDK API
25
37
 
26
- These names are exported from `mt5cli` and covered by the contract in
38
+ These names are exported from `mt5cli` and enumerated in
27
39
  `mt5cli.STABLE_SDK_EXPORTS` (defined in `mt5cli.contract`).
28
40
 
29
41
  ### Session lifecycle and configuration
@@ -33,23 +45,9 @@ These names are exported from `mt5cli` and covered by the contract in
33
45
  | `MT5Client` | Read-only data client with optional `order_check` / `order_send` |
34
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` |
35
47
  | `mt5_session` | Context manager: initialize, login, yield client, shutdown |
36
- | `create_trading_client`, `mt5_trading_session` | Trading-capable `pdmt5.Mt5TradingClient` lifecycle |
48
+ | `create_trading_client`, `mt5_trading_session` | Trading-capable MT5 client lifecycle; returns a client supporting order execution and account management |
37
49
  | `AccountSpec` | Generic account group: symbols plus optional credentials |
38
50
  | `resolve_account_spec`, `resolve_account_specs` | Merge overrides and expand `${ENV_VAR}` placeholders; opt-in `allow_whole_dollar_env` for bare `$NAME` |
39
- | `substitute_env_placeholders` | Replace `${NAME}` substrings from the environment; opt-in `allow_whole_dollar_env` for whole-value `$NAME` |
40
- | `substitute_mapping_values` | Recursively traverse a dict/list/scalar structure and substitute `${ENV_VAR}` placeholders for caller-selected mapping keys only; optionally normalise blank strings to `None` for a separate caller-selected key set; does not hard-code any application-specific key names |
41
-
42
- Credential resolution is generic: any environment variable name may appear inside
43
- `${...}`. mt5cli does not hard-code application-specific keys such as
44
- `mt5_login` or `mt5_exe`.
45
-
46
- Pass `allow_whole_dollar_env=True` to `substitute_env_placeholders()`,
47
- `substitute_mapping_values()`, `resolve_account_spec()`, `resolve_account_specs()`,
48
- and `build_config()` to additionally expand strings whose entire value is a bare
49
- `$ENV_NAME` identifier.
50
- Partial strings such as `"plan$pass"`, `"abc$ENV"`, or `"$ENV-suffix"` are
51
- **never** expanded — only an exact `$IDENTIFIER` whole-string match qualifies.
52
- Default is `False` to preserve backward compatibility.
53
51
 
54
52
  ### Closed-bar rate helpers
55
53
 
@@ -61,7 +59,7 @@ timestamp normalization in downstream apps.
61
59
  | ------------------------------------------------ | ------------------------------------------------------------------------------- |
62
60
  | `drop_forming_rate_bar` | Remove the last row from chronologically ordered rate data |
63
61
  | `fetch_latest_closed_rates` | Single connected client: fetch `count + 1`, drop forming bar |
64
- | `fetch_latest_closed_rates_for_trading_client` | Closed bars from an active `Mt5TradingClient` session; returns RangeIndex |
62
+ | `fetch_latest_closed_rates_for_trading_client` | Closed bars from an active trading client session; returns RangeIndex |
65
63
  | `fetch_latest_closed_rates_indexed` | Same as above but returns a UTC `DatetimeIndex` named `"time"` (no time column) |
66
64
  | `collect_latest_closed_rates_for_accounts` | Multi-account closed bars with optional retry wrapper |
67
65
  | `collect_latest_closed_rates_by_granularity` | Same data keyed by `(symbol, granularity_name)` |
@@ -69,20 +67,13 @@ timestamp normalization in downstream apps.
69
67
 
70
68
  ### SQLite history collection and rate loading
71
69
 
72
- | Symbol | Role |
73
- | ----------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
74
- | `collect_history` | One-shot date-range export into SQLite |
75
- | `update_history`, `update_history_with_config` | Incremental append from `MAX(time)` cursors |
76
- | `ThrottledHistoryUpdater` | Minimum interval between successful incremental updates; optional `update_backend` injection |
77
- | `resolve_history_datasets`, `resolve_history_timeframes`, `resolve_history_tick_flags` | History pipeline configuration |
78
- | `build_rate_view_name`, `resolve_rate_table_name`, `resolve_rate_view_name`, `resolve_rate_view_names`, `resolve_rate_tables` | Map symbols/timeframes to mt5cli-managed table or view names |
79
- | `RateTarget`, `build_rate_targets` | Neutral `(symbol, timeframe)` series descriptors |
80
- | `load_rate_data`, `load_rate_data_from_connection` | Load one table/view into a time-indexed DataFrame |
81
- | `load_rate_series_from_sqlite`, `load_rate_series_by_granularity` | Load one or many series; fail clearly when managed views are missing |
82
-
83
- Pass `require_existing=True` to rate view resolution helpers when downstream
84
- code must fail instead of receiving a best-guess view name. Multi-series loaders
85
- require existing managed `rate_*__*` views unless `explicit_tables` is supplied.
70
+ | Symbol | Role |
71
+ | ----------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
72
+ | `collect_history` | One-shot date-range export into SQLite |
73
+ | `update_history`, `update_history_with_config` | Incremental append from `MAX(time)` cursors |
74
+ | `ThrottledHistoryUpdater` | Minimum interval between successful incremental updates; optional `update_backend` injection |
75
+ | `RateTarget`, `build_rate_targets` | Neutral `(symbol, timeframe)` series descriptors |
76
+ | `load_rate_series_from_sqlite`, `load_rate_series_by_granularity` | Load one or many series; fail clearly when managed views are missing |
86
77
 
87
78
  See [History Collection (SQLite)](history.md) for schema, view naming, and ER
88
79
  diagrams.
@@ -123,7 +114,7 @@ strategy policy.
123
114
  `MT5Client.order_send()` and CLI `order-send --yes` are live execution paths.
124
115
 
125
116
  Order helpers validate broker stop-level distance in `determine_order_limits()` and
126
- raise `Mt5TradingError` when computed SL/TP prices are too close to the entry
117
+ raise `Mt5OperationError` when computed SL/TP prices are too close to the entry
127
118
  quote. Validation uses `trade_stops_level * point` from the current quote and
128
119
  symbol metadata as a pre-check only; it does not guarantee live order acceptance
129
120
  after price movement and does not inspect `trade_freeze_level`. Live
@@ -133,51 +124,25 @@ sending requests. Failed, malformed, or unknown broker retcodes are fail-closed
133
124
  and returned as `status="failed"` with normalized `request` / `response` details;
134
125
  `dry_run=True` never calls `ensure_symbol_selected()` or `order_send()`.
135
126
 
136
- ### Errors and MT5 type re-exports
137
-
138
- | Symbol | Role |
139
- | ------------------------------------------------------------------------------------ | ----------------------------------------------- |
140
- | `Mt5CliError`, `Mt5ConnectionError`, `Mt5OperationError`, `Mt5SchemaError` | Stable mt5cli exception types |
141
- | `normalize_mt5_exception`, `call_with_normalized_errors`, `is_recoverable_mt5_error` | Error normalization and retry classification |
142
- | `Mt5Config`, `Mt5RuntimeError`, `Mt5TradingClient`, `Mt5TradingError` | Re-exported pdmt5 types for adapter convenience |
143
-
144
- ## Secondary public exports
145
-
146
- These names remain importable from `mt5cli` and are covered by
147
- `SECONDARY_PUBLIC_EXPORTS`, but they are oriented toward CLI/export/schema
148
- integrations, parsing, and lower-level MT5 access rather than the stable core
149
- SDK surface. Prefer the stable symbols above for downstream infrastructure
150
- adapters.
151
-
152
- ### Read-only MT5 data wrappers
153
-
154
- Module-level helpers open a transient connection per call. Prefer `mt5_session`
155
- or `MT5Client` when making many requests in one process.
127
+ ### Errors
156
128
 
157
- | Area | Symbols |
158
- | -------------------- | ---------------------------------------------------------------------------------------------------- |
159
- | Rates | `copy_rates_from`, `copy_rates_from_pos`, `copy_rates_range`, `latest_rates`, `collect_latest_rates` |
160
- | Ticks | `copy_ticks_from`, `copy_ticks_range`, `recent_ticks` |
161
- | Account / terminal | `account_info`, `terminal_info`, `mt5_version`, `last_error`, `mt5_summary`, `mt5_summary_as_df` |
162
- | Symbols / market | `symbols`, `symbol_info`, `symbol_info_tick`, `market_book`, `minimum_margins` |
163
- | Trading state (read) | `orders`, `positions`, `history_orders`, `history_deals`, `recent_history_deals` |
164
- | Multi-account rates | `collect_latest_rates_for_accounts` |
129
+ | Symbol | Role |
130
+ | -------------------------------------------------------------------------- | ----------------------------- |
131
+ | `Mt5CliError`, `Mt5ConnectionError`, `Mt5OperationError`, `Mt5SchemaError` | Stable mt5cli exception types |
165
132
 
166
- Use `mt5_version` for MetaTrader 5 terminal version data. The name `version` at
167
- the package root refers to `importlib.metadata.version` (package metadata), not
168
- the MT5 SDK helper.
133
+ ## Module-scoped helpers
169
134
 
170
- ### Schema, export, and parser helpers
135
+ Lower-level helpers are available from their owning modules and are not part
136
+ of the package-root stable surface. Import them directly when needed:
171
137
 
172
- | Area | Symbols |
173
- | -------------------- | ------------------------------------------------------------------------------------------------------------- |
174
- | Dataset contracts | `DataKind`, `Dataset`, `IfExists`, `DEDUP_KEYS`, `REQUIRED_COLUMNS`, `TIME_COLUMNS`, `KNOWN_MT5_TIME_COLUMNS` |
175
- | Schema normalization | `normalize_dataframe`, `normalize_time_columns`, `schema_columns`, `validate_schema` |
176
- | Export helpers | `detect_format`, `export_dataframe`, `export_dataframe_to_sqlite` |
177
- | Symbol parsing | `normalize_symbol`, `normalize_symbols` |
178
- | Time parsing | `ensure_utc`, `parse_date_range`, `parse_datetime`, `recent_window` |
179
- | MT5 parsing maps | `granularity_name`, `parse_tick_flags`, `parse_timeframe`, `TICK_FLAG_MAP`, `TIMEFRAME_MAP` |
180
- | Trading data shapes | `POSITION_COLUMNS` |
138
+ | Module | Examples |
139
+ | ------------------- | ---------------------------------------------------------------------------------------------- |
140
+ | `mt5cli.history` | `resolve_rate_view_name`, `resolve_rate_tables`, `load_rate_data`, `build_rate_view_name` |
141
+ | `mt5cli.sdk` | `copy_rates_from`, `copy_ticks_from`, `account_info`, `symbols`, `mt5_summary`, `latest_rates` |
142
+ | `mt5cli.schemas` | `DataKind`, `normalize_dataframe`, `validate_schema`, `DEDUP_KEYS` |
143
+ | `mt5cli.utils` | `Dataset`, `IfExists`, `detect_format`, `export_dataframe`, `export_dataframe_to_sqlite` |
144
+ | `mt5cli.converters` | `normalize_symbol`, `ensure_utc`, `parse_date_range`, `granularity_name` |
145
+ | `mt5cli.exceptions` | `normalize_mt5_exception`, `call_with_normalized_errors`, `is_recoverable_mt5_error` |
181
146
 
182
147
  ## CLI commands
183
148
 
@@ -231,7 +196,7 @@ their own adapter layer.
231
196
 
232
197
  ## Contract verification
233
198
 
234
- `tests/test_contracts.py` asserts that every name in the stable and secondary
235
- tier sets is importable from `mt5cli`, documents key closed-bar, rate-view,
236
- SQLite loading, account-resolution, and trading-session behaviors, and keeps the
237
- tier sets aligned with `__all__`.
199
+ `tests/test_contracts.py` asserts that every name in `STABLE_SDK_EXPORTS` is
200
+ importable from `mt5cli`, that all package-root exports are covered by the
201
+ stable set, and documents key closed-bar, SQLite loading, account-resolution,
202
+ and trading-session behaviors.
@@ -117,7 +117,8 @@ call it every iteration without over-fetching.
117
117
  ```python
118
118
  from pdmt5 import Mt5Config, Mt5DataClient
119
119
 
120
- from mt5cli import Dataset, ThrottledHistoryUpdater
120
+ from mt5cli import ThrottledHistoryUpdater
121
+ from mt5cli.utils import Dataset
121
122
 
122
123
  updater = ThrottledHistoryUpdater(
123
124
  output="history.db",
@@ -6,8 +6,9 @@
6
6
 
7
7
  `create_trading_client()` and `mt5_trading_session()` complement the read-only
8
8
  `mt5_session()` helper in `sdk.py`. They return or yield an initialized
9
- `pdmt5.Mt5TradingClient`, use `Mt5Config.path` to launch the terminal when
10
- configured, and `mt5_trading_session()` always calls `shutdown()` on exit.
9
+ client supporting order execution and account management, use `Mt5Config.path`
10
+ to launch the terminal when configured, and `mt5_trading_session()` always
11
+ calls `shutdown()` on exit.
11
12
 
12
13
  ```python
13
14
  from mt5cli import create_trading_client, mt5_trading_session
@@ -115,19 +116,19 @@ closed = close_open_positions(client, symbols="EURUSD", dry_run=True)
115
116
  `detect_position_side()` returns `long` for buy-only exposure, `short` for
116
117
  sell-only exposure, and `None` for no positions or mixed long/short exposure.
117
118
  `calculate_spread_ratio()` uses `(ask - bid) / ((ask + bid) / 2)` and raises
118
- `Mt5TradingError` when bid or ask is missing or non-positive.
119
+ `Mt5OperationError` when bid or ask is missing or non-positive.
119
120
  `normalize_order_volume()` returns `0.0` for invalid constraints or
120
121
  sub-minimum requests; check the result before calling `estimate_order_margin()`,
121
122
  which requires a positive finite volume. `calculate_positions_margin()` silently
122
123
  skips rows with missing symbols, non-positive volumes, non-finite volumes, or
123
- unsupported position types, but propagates `Mt5TradingError` from `estimate_order_margin()` when a valid row
124
+ unsupported position types, but propagates `Mt5OperationError` from `estimate_order_margin()` when a valid row
124
125
  encounters invalid tick data or margin results from the broker.
125
126
 
126
127
  SL/TP ratios for `determine_order_limits()` must satisfy `0 <= ratio < 1`; `0`
127
128
  omits that level. SL/TP prices are rounded with symbol `digits` metadata when
128
129
  available. `determine_order_limits()` pre-validates computed SL/TP prices against
129
130
  available `trade_stops_level * point` metadata when present; violations raise
130
- `Mt5TradingError`. This is a planning helper only: it does not guarantee broker
131
+ `Mt5OperationError`. This is a planning helper only: it does not guarantee broker
131
132
  acceptance because live validation can still depend on price movement, bid/ask
132
133
  side, freeze levels, and server-side rules, and it does not validate
133
134
  `trade_freeze_level`. When symbol metadata cannot be loaded, protective prices
@@ -27,6 +27,12 @@ mt5cli provides a stable `MT5Client` Python API, standardized dataset schemas, s
27
27
  pip install mt5cli
28
28
  ```
29
29
 
30
+ Parquet export is not included by default. To enable it, install the `parquet` extra:
31
+
32
+ ```bash
33
+ pip install "mt5cli[parquet]"
34
+ ```
35
+
30
36
  ## Python API for downstream packages
31
37
 
32
38
  Import `MT5Client` for generic MT5 data access, schema normalization, and optional order primitives.
@@ -36,19 +42,15 @@ from datetime import UTC, datetime
36
42
  from pathlib import Path
37
43
 
38
44
  from mt5cli import (
39
- DataKind,
40
- Dataset,
41
45
  MT5Client,
42
46
  build_config,
43
47
  collect_history,
44
- export_dataframe,
45
- load_rate_data,
46
- minimum_margins,
47
48
  mt5_session,
48
- normalize_dataframe,
49
- recent_ticks,
50
- resolve_rate_view_name,
51
49
  )
50
+ from mt5cli.history import load_rate_data, resolve_rate_view_name
51
+ from mt5cli.schemas import DataKind, normalize_dataframe
52
+ from mt5cli.sdk import minimum_margins, recent_ticks
53
+ from mt5cli.utils import Dataset, export_dataframe
52
54
 
53
55
  # Persistent session for multiple calls
54
56
  with mt5_session(build_config(login=12345, server="Broker-Demo")) as client:
@@ -84,7 +86,7 @@ collect_history(
84
86
  )
85
87
  ```
86
88
 
87
- Schema contracts live in `mt5cli.schemas` (`DataKind`, `validate_schema`, `normalize_dataframe`). Storage helpers are re-exported from `mt5cli.storage` and the package root.
89
+ Schema contracts live in `mt5cli.schemas` (`DataKind`, `validate_schema`, `normalize_dataframe`). Export and storage helpers are in `mt5cli.utils` (`Dataset`, `export_dataframe`) and `mt5cli.history`.
88
90
 
89
91
  `MT5Client.order_send()` is a live execution primitive: it can place real trades on the connected account. mt5cli does not implement strategy logic, signal generation, backtesting, or optimization — downstream applications must gate live execution explicitly (the CLI requires `--yes` for `order-send`).
90
92
 
@@ -59,7 +59,6 @@ nav:
59
59
  - Public API Contract: api/public-contract.md
60
60
  - Client: api/client.md
61
61
  - Schemas: api/schemas.md
62
- - Storage: api/storage.md
63
62
  - Converters: api/converters.md
64
63
  - Exceptions: api/exceptions.md
65
64
  - CLI: api/cli.md