mt5cli 0.5.3__tar.gz → 0.6.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.
Files changed (40) hide show
  1. {mt5cli-0.5.3 → mt5cli-0.6.1}/PKG-INFO +74 -2
  2. {mt5cli-0.5.3 → mt5cli-0.6.1}/README.md +73 -1
  3. {mt5cli-0.5.3 → mt5cli-0.6.1}/docs/api/index.md +7 -2
  4. {mt5cli-0.5.3 → mt5cli-0.6.1}/docs/api/sdk.md +34 -3
  5. mt5cli-0.6.1/docs/api/trading.md +70 -0
  6. {mt5cli-0.5.3 → mt5cli-0.6.1}/mkdocs.yml +1 -0
  7. {mt5cli-0.5.3 → mt5cli-0.6.1}/mt5cli/__init__.py +16 -0
  8. {mt5cli-0.5.3 → mt5cli-0.6.1}/mt5cli/history.py +17 -0
  9. {mt5cli-0.5.3 → mt5cli-0.6.1}/mt5cli/sdk.py +204 -9
  10. mt5cli-0.6.1/mt5cli/trading.py +210 -0
  11. {mt5cli-0.5.3 → mt5cli-0.6.1}/pyproject.toml +1 -1
  12. {mt5cli-0.5.3 → mt5cli-0.6.1}/tests/test_history.py +41 -0
  13. {mt5cli-0.5.3 → mt5cli-0.6.1}/tests/test_sdk.py +334 -2
  14. mt5cli-0.6.1/tests/test_trading.py +356 -0
  15. {mt5cli-0.5.3 → mt5cli-0.6.1}/uv.lock +4 -4
  16. {mt5cli-0.5.3 → mt5cli-0.6.1}/.agents/skills/local-qa/SKILL.md +0 -0
  17. {mt5cli-0.5.3 → mt5cli-0.6.1}/.agents/skills/local-qa/scripts/qa.sh +0 -0
  18. {mt5cli-0.5.3 → mt5cli-0.6.1}/.agents/skills/mt5cli/SKILL.md +0 -0
  19. {mt5cli-0.5.3 → mt5cli-0.6.1}/.claude/agents/codex.md +0 -0
  20. {mt5cli-0.5.3 → mt5cli-0.6.1}/.claude/settings.json +0 -0
  21. {mt5cli-0.5.3 → mt5cli-0.6.1}/.github/FUNDING.yml +0 -0
  22. {mt5cli-0.5.3 → mt5cli-0.6.1}/.github/dependabot.yml +0 -0
  23. {mt5cli-0.5.3 → mt5cli-0.6.1}/.github/renovate.json +0 -0
  24. {mt5cli-0.5.3 → mt5cli-0.6.1}/.github/workflows/ci.yml +0 -0
  25. {mt5cli-0.5.3 → mt5cli-0.6.1}/.github/workflows/claude.yml +0 -0
  26. {mt5cli-0.5.3 → mt5cli-0.6.1}/.github/workflows/release.yml +0 -0
  27. {mt5cli-0.5.3 → mt5cli-0.6.1}/.gitignore +0 -0
  28. {mt5cli-0.5.3 → mt5cli-0.6.1}/AGENTS.md +0 -0
  29. {mt5cli-0.5.3 → mt5cli-0.6.1}/CLAUDE.md +0 -0
  30. {mt5cli-0.5.3 → mt5cli-0.6.1}/LICENSE +0 -0
  31. {mt5cli-0.5.3 → mt5cli-0.6.1}/docs/api/cli.md +0 -0
  32. {mt5cli-0.5.3 → mt5cli-0.6.1}/docs/api/history.md +0 -0
  33. {mt5cli-0.5.3 → mt5cli-0.6.1}/docs/api/utils.md +0 -0
  34. {mt5cli-0.5.3 → mt5cli-0.6.1}/docs/index.md +0 -0
  35. {mt5cli-0.5.3 → mt5cli-0.6.1}/mt5cli/__main__.py +0 -0
  36. {mt5cli-0.5.3 → mt5cli-0.6.1}/mt5cli/cli.py +0 -0
  37. {mt5cli-0.5.3 → mt5cli-0.6.1}/mt5cli/utils.py +0 -0
  38. {mt5cli-0.5.3 → mt5cli-0.6.1}/tests/__init__.py +0 -0
  39. {mt5cli-0.5.3 → mt5cli-0.6.1}/tests/test_cli.py +0 -0
  40. {mt5cli-0.5.3 → mt5cli-0.6.1}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mt5cli
3
- Version: 0.5.3
3
+ Version: 0.6.1
4
4
  Summary: Command-line tool for MetaTrader 5
5
5
  Project-URL: Repository, https://github.com/dceoy/mt5cli.git
6
6
  Author-email: dceoy <dceoy@users.noreply.github.com>
@@ -161,8 +161,23 @@ update_history_with_config(
161
161
  - **Rate view loading**: use `load_rate_data()` / `load_rate_data_from_connection()` to load a SQLite rate table or view into a `DatetimeIndex` DataFrame.
162
162
  - **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.
163
163
  - **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.
164
+ - **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")`.
165
+
166
+ ```python
167
+ from mt5cli import AccountSpec, collect_latest_closed_rates_by_granularity
168
+
169
+ rates = collect_latest_closed_rates_by_granularity(
170
+ [AccountSpec(symbols=["EURUSD", "GBPUSD"], login=12345)],
171
+ ["M1", "H1"],
172
+ count=500,
173
+ retry_count=3,
174
+ )
175
+ eurusd_m1 = rates["EURUSD", "M1"] # closed bars only
176
+ ```
177
+
164
178
  - **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.
165
- - **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` and let the caller decide logging.
179
+ - **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).
180
+ - **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. The read-only `mt5_session()` / `Mt5CliClient` SDK is unchanged.
166
181
  - **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.
167
182
  - **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 `Mt5CliClient` that shuts down on exit.
168
183
  - **SQLite export helpers**: use `export_dataframe_to_sqlite()` for append mode, optional index export, and post-write deduplication by key columns.
@@ -174,6 +189,63 @@ update_history_with_config(
174
189
  - Windows OS (MetaTrader 5 requirement)
175
190
  - MetaTrader 5 platform installed
176
191
 
192
+ ### Migration note for mteor
193
+
194
+ Replace local MT5 lifecycle and trading helper code with mt5cli imports:
195
+
196
+ ```python
197
+ # Before (local mteor helpers)
198
+ # with local_mt5_trading_session(config) as client:
199
+ # side = local_detect_position_side(client, symbol)
200
+ # sizing = local_calculate_margin_and_volume(client, symbol, unit_ratio, preserved_ratio)
201
+ # limits = local_determine_order_limits(client, symbol, side, sl_ratio, tp_ratio)
202
+
203
+ # After (mt5cli shared layer)
204
+ from pdmt5 import Mt5Config
205
+ from mt5cli import (
206
+ calculate_margin_and_volume,
207
+ detect_position_side,
208
+ determine_order_limits,
209
+ mt5_trading_session,
210
+ )
211
+
212
+ with mt5_trading_session(
213
+ Mt5Config(path=terminal_path, login=login), retry_count=2
214
+ ) as client:
215
+ side = detect_position_side(client, symbol)
216
+ sizing = calculate_margin_and_volume(
217
+ client, symbol, unit_margin_ratio=0.5, preserved_margin_ratio=0.2
218
+ )
219
+ if side is not None:
220
+ limits = determine_order_limits(
221
+ client,
222
+ symbol,
223
+ side,
224
+ stop_loss_limit_ratio=0.01,
225
+ take_profit_limit_ratio=0.02,
226
+ )
227
+ ```
228
+
229
+ Throttled history updates use a separate read-only session:
230
+
231
+ ```python
232
+ from pdmt5 import Mt5Config, Mt5DataClient
233
+
234
+ from mt5cli import ThrottledHistoryUpdater
235
+
236
+ updater = ThrottledHistoryUpdater(
237
+ output="history.db", interval_seconds=60, suppress_errors=True
238
+ )
239
+ client = Mt5DataClient(config=Mt5Config(login=login))
240
+ client.initialize_and_login_mt5()
241
+ try:
242
+ updater.update(client, ["EURUSD"])
243
+ finally:
244
+ client.shutdown()
245
+ ```
246
+
247
+ Read-only collectors can keep using `mt5_session()` and `Mt5CliClient` without changes.
248
+
177
249
  ## Development
178
250
 
179
251
  ```bash
@@ -137,8 +137,23 @@ update_history_with_config(
137
137
  - **Rate view loading**: use `load_rate_data()` / `load_rate_data_from_connection()` to load a SQLite rate table or view into a `DatetimeIndex` DataFrame.
138
138
  - **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.
139
139
  - **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.
140
+ - **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")`.
141
+
142
+ ```python
143
+ from mt5cli import AccountSpec, collect_latest_closed_rates_by_granularity
144
+
145
+ rates = collect_latest_closed_rates_by_granularity(
146
+ [AccountSpec(symbols=["EURUSD", "GBPUSD"], login=12345)],
147
+ ["M1", "H1"],
148
+ count=500,
149
+ retry_count=3,
150
+ )
151
+ eurusd_m1 = rates["EURUSD", "M1"] # closed bars only
152
+ ```
153
+
140
154
  - **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.
141
- - **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` and let the caller decide logging.
155
+ - **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).
156
+ - **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. The read-only `mt5_session()` / `Mt5CliClient` SDK is unchanged.
142
157
  - **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.
143
158
  - **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 `Mt5CliClient` that shuts down on exit.
144
159
  - **SQLite export helpers**: use `export_dataframe_to_sqlite()` for append mode, optional index export, and post-write deduplication by key columns.
@@ -150,6 +165,63 @@ update_history_with_config(
150
165
  - Windows OS (MetaTrader 5 requirement)
151
166
  - MetaTrader 5 platform installed
152
167
 
168
+ ### Migration note for mteor
169
+
170
+ Replace local MT5 lifecycle and trading helper code with mt5cli imports:
171
+
172
+ ```python
173
+ # Before (local mteor helpers)
174
+ # with local_mt5_trading_session(config) as client:
175
+ # side = local_detect_position_side(client, symbol)
176
+ # sizing = local_calculate_margin_and_volume(client, symbol, unit_ratio, preserved_ratio)
177
+ # limits = local_determine_order_limits(client, symbol, side, sl_ratio, tp_ratio)
178
+
179
+ # After (mt5cli shared layer)
180
+ from pdmt5 import Mt5Config
181
+ from mt5cli import (
182
+ calculate_margin_and_volume,
183
+ detect_position_side,
184
+ determine_order_limits,
185
+ mt5_trading_session,
186
+ )
187
+
188
+ with mt5_trading_session(
189
+ Mt5Config(path=terminal_path, login=login), retry_count=2
190
+ ) as client:
191
+ side = detect_position_side(client, symbol)
192
+ sizing = calculate_margin_and_volume(
193
+ client, symbol, unit_margin_ratio=0.5, preserved_margin_ratio=0.2
194
+ )
195
+ if side is not None:
196
+ limits = determine_order_limits(
197
+ client,
198
+ symbol,
199
+ side,
200
+ stop_loss_limit_ratio=0.01,
201
+ take_profit_limit_ratio=0.02,
202
+ )
203
+ ```
204
+
205
+ Throttled history updates use a separate read-only session:
206
+
207
+ ```python
208
+ from pdmt5 import Mt5Config, Mt5DataClient
209
+
210
+ from mt5cli import ThrottledHistoryUpdater
211
+
212
+ updater = ThrottledHistoryUpdater(
213
+ output="history.db", interval_seconds=60, suppress_errors=True
214
+ )
215
+ client = Mt5DataClient(config=Mt5Config(login=login))
216
+ client.initialize_and_login_mt5()
217
+ try:
218
+ updater.update(client, ["EURUSD"])
219
+ finally:
220
+ client.shutdown()
221
+ ```
222
+
223
+ Read-only collectors can keep using `mt5_session()` and `Mt5CliClient` without changes.
224
+
153
225
  ## Development
154
226
 
155
227
  ```bash
@@ -18,6 +18,10 @@ Utility module providing constants, enums, Click parameter types, and helper fun
18
18
 
19
19
  Programmatic SDK for read-only MetaTrader 5 data collection. Returns pandas DataFrames and provides `collect_history` for SQLite bulk collection.
20
20
 
21
+ ### [Trading](trading.md)
22
+
23
+ Trading-capable session management and operational helpers built on `pdmt5.Mt5TradingClient`. Complements the read-only SDK without changing existing `Mt5CliClient` behavior.
24
+
21
25
  ### [History Collection (SQLite)](history.md)
22
26
 
23
27
  SQLite storage helpers for the `collect-history` command schema, incremental updates, deduplication, indexes, and optional views.
@@ -28,8 +32,9 @@ The package follows a simple architecture built on top of pdmt5:
28
32
 
29
33
  1. **CLI Layer** (`cli.py`): Typer application with subcommands that delegate to the SDK and export results.
30
34
  2. **SDK Layer** (`sdk.py`): Read-only data access functions, `Mt5CliClient`, and `collect_history` orchestration.
31
- 3. **Utils Layer** (`utils.py`): Constants, enums, custom Click parameter types, parsing helpers, and format detection/export utilities.
32
- 4. **Data Layer** (via `pdmt5`): Uses `Mt5DataClient` and `Mt5Config` from the pdmt5 package for all MetaTrader 5 data access.
35
+ 3. **Trading Layer** (`trading.py`): Trading-capable sessions and operational helpers on `Mt5TradingClient`.
36
+ 4. **Utils Layer** (`utils.py`): Constants, enums, custom Click parameter types, parsing helpers, and format detection/export utilities.
37
+ 5. **Data Layer** (via `pdmt5`): Uses `Mt5DataClient`, `Mt5TradingClient`, and `Mt5Config` from the pdmt5 package for MetaTrader 5 access.
33
38
 
34
39
  ## Usage Guidelines
35
40
 
@@ -28,6 +28,26 @@ rates = collect_latest_rates_for_accounts_with_retries(
28
28
  )
29
29
  ```
30
30
 
31
+ ### Latest closed rate bars
32
+
33
+ MetaTrader 5 `start_pos=0` includes the still-forming current bar as the last
34
+ row. `collect_latest_closed_rates_for_accounts()` fetches `count + 1` bars,
35
+ drops that row with `drop_forming_rate_bar()`, and validates each series is
36
+ non-empty. Use `collect_latest_closed_rates_by_granularity()` when callers
37
+ prefer keys such as `("EURUSD", "M1")` instead of integer timeframes.
38
+
39
+ ```python
40
+ from mt5cli import AccountSpec, collect_latest_closed_rates_by_granularity
41
+
42
+ rates = collect_latest_closed_rates_by_granularity(
43
+ [AccountSpec(symbols=["EURUSD"], login=12345)],
44
+ ["M1", "H1"],
45
+ count=500,
46
+ retry_count=3,
47
+ )
48
+ closed_m1 = rates["EURUSD", "M1"]
49
+ ```
50
+
31
51
  ### Resolving credentials and `${ENV_VAR}` placeholders
32
52
 
33
53
  `resolve_account_spec()` / `resolve_account_specs()` merge explicit override
@@ -78,6 +98,17 @@ finally:
78
98
  client.shutdown()
79
99
  ```
80
100
 
81
- By default `Mt5TradingError`, `Mt5RuntimeError`, and `sqlite3.Error` propagate so
82
- the caller controls logging; pass `suppress_errors=True` to swallow them and
83
- return `False` without advancing the throttle.
101
+ By default recoverable errors (`Mt5TradingError`, `Mt5RuntimeError`,
102
+ `sqlite3.Error`, `ValueError`, `OSError`, and MT5 client capability
103
+ `AttributeError` / `TypeError` for history API methods) propagate so the caller
104
+ controls logging; pass `suppress_errors=True` to swallow them and return
105
+ `False` without advancing the throttle. Other `AttributeError` / `TypeError`
106
+ values always propagate. Input validation (`_resolve_update_history_request`)
107
+ runs before any MT5 or SQLite calls, but when `suppress_errors=True` the
108
+ resulting `ValueError` is suppressed along with other recoverable errors.
109
+
110
+ ## Trading-capable sessions
111
+
112
+ For order placement and trading calculations, use the dedicated
113
+ [Trading module](trading.md). The read-only `Mt5CliClient` and `mt5_session()`
114
+ helpers in this module are unchanged.
@@ -0,0 +1,70 @@
1
+ # Trading Module
2
+
3
+ ::: mt5cli.trading
4
+
5
+ ## Trading-capable MT5 sessions
6
+
7
+ `mt5_trading_session()` complements the read-only `mt5_session()` helper in
8
+ `sdk.py`. It yields a connected `pdmt5.Mt5TradingClient`, uses
9
+ `Mt5Config.path` to launch the terminal when configured, and always calls
10
+ `shutdown()` on exit.
11
+
12
+ ```python
13
+ from pdmt5 import Mt5Config
14
+
15
+ from mt5cli import mt5_trading_session
16
+
17
+ with mt5_trading_session(
18
+ Mt5Config(path=r"C:\Program Files\MetaTrader 5\terminal64.exe", login=12345),
19
+ retry_count=2,
20
+ ) as client:
21
+ positions = client.positions_get_as_df(symbol="EURUSD")
22
+ ```
23
+
24
+ The read-only `Mt5CliClient` / `mt5_session()` API is unchanged.
25
+
26
+ ## Operational trading helpers
27
+
28
+ These helpers are strategy-agnostic and do not depend on signal detection,
29
+ betting logic, or scheduling code in downstream applications.
30
+
31
+ ```python
32
+ from mt5cli import (
33
+ calculate_margin_and_volume,
34
+ detect_position_side,
35
+ determine_order_limits,
36
+ )
37
+
38
+ side = detect_position_side(client, "EURUSD")
39
+ sizing = calculate_margin_and_volume(
40
+ client,
41
+ "EURUSD",
42
+ unit_margin_ratio=0.5,
43
+ preserved_margin_ratio=0.2,
44
+ )
45
+ limits = determine_order_limits(
46
+ client,
47
+ "EURUSD",
48
+ side="long",
49
+ stop_loss_limit_ratio=0.01,
50
+ take_profit_limit_ratio=0.02,
51
+ )
52
+ ```
53
+
54
+ Protective ratios must satisfy `0 <= ratio < 1`; `0` omits that level.
55
+ `calculate_margin_and_volume()` clamps negative `margin_free` to `0.0`
56
+ before sizing.
57
+
58
+ ## Migration from mteor-local helpers
59
+
60
+ | mteor-local concern | mt5cli replacement |
61
+ | -------------------------------------------------------- | ----------------------------------------------- |
62
+ | Manual terminal spawn/kill around trading code | `mt5_trading_session()` |
63
+ | Local position-side detection | `detect_position_side()` |
64
+ | Local margin/volume sizing | `calculate_margin_and_volume()` |
65
+ | Local SL/TP price derivation | `determine_order_limits()` |
66
+ | Throttled SQLite history loop with ad-hoc error handling | `ThrottledHistoryUpdater(suppress_errors=True)` |
67
+
68
+ Keep read-only data collection on `mt5_session()` / `Mt5CliClient`; use
69
+ `mt5_trading_session()` only where order placement or trading calculations are
70
+ required.
@@ -58,6 +58,7 @@ nav:
58
58
  - Overview: api/index.md
59
59
  - CLI: api/cli.md
60
60
  - SDK: api/sdk.md
61
+ - Trading: api/trading.md
61
62
  - History Collection (SQLite): api/history.md
62
63
  - Utils: api/utils.md
63
64
 
@@ -6,6 +6,7 @@ from .history import (
6
6
  RateTarget,
7
7
  build_rate_targets,
8
8
  build_rate_view_name,
9
+ drop_forming_rate_bar,
9
10
  load_rate_data,
10
11
  load_rate_data_from_connection,
11
12
  load_rate_series_by_granularity,
@@ -24,6 +25,8 @@ from .sdk import (
24
25
  account_info,
25
26
  build_config,
26
27
  collect_history,
28
+ collect_latest_closed_rates_by_granularity,
29
+ collect_latest_closed_rates_for_accounts,
27
30
  collect_latest_rates,
28
31
  collect_latest_rates_for_accounts,
29
32
  collect_latest_rates_for_accounts_with_retries,
@@ -58,6 +61,12 @@ from .sdk import (
58
61
  from .sdk import (
59
62
  version as mt5_version,
60
63
  )
64
+ from .trading import (
65
+ calculate_margin_and_volume,
66
+ detect_position_side,
67
+ determine_order_limits,
68
+ mt5_trading_session,
69
+ )
61
70
  from .utils import (
62
71
  TICK_FLAG_MAP,
63
72
  TIMEFRAME_MAP,
@@ -86,7 +95,10 @@ __all__ = [
86
95
  "build_config",
87
96
  "build_rate_targets",
88
97
  "build_rate_view_name",
98
+ "calculate_margin_and_volume",
89
99
  "collect_history",
100
+ "collect_latest_closed_rates_by_granularity",
101
+ "collect_latest_closed_rates_for_accounts",
90
102
  "collect_latest_rates",
91
103
  "collect_latest_rates_for_accounts",
92
104
  "collect_latest_rates_for_accounts_with_retries",
@@ -96,6 +108,9 @@ __all__ = [
96
108
  "copy_ticks_from",
97
109
  "copy_ticks_range",
98
110
  "detect_format",
111
+ "detect_position_side",
112
+ "determine_order_limits",
113
+ "drop_forming_rate_bar",
99
114
  "export_dataframe",
100
115
  "export_dataframe_to_sqlite",
101
116
  "history_deals",
@@ -111,6 +126,7 @@ __all__ = [
111
126
  "mt5_session",
112
127
  "mt5_summary",
113
128
  "mt5_summary_as_df",
129
+ "mt5_trading_session",
114
130
  "mt5_version",
115
131
  "orders",
116
132
  "parse_datetime",
@@ -106,6 +106,23 @@ def resolve_granularity_name(timeframe: int) -> str:
106
106
  return str(timeframe)
107
107
 
108
108
 
109
+ def drop_forming_rate_bar(df_rate: pd.DataFrame) -> pd.DataFrame:
110
+ """Return closed bars from chronologically ordered MT5 rate data.
111
+
112
+ MetaTrader 5 ``copy_rates_from_pos(start_pos=0)`` includes the still-forming
113
+ current bar as the last row. Slice it off so downstream logic only sees
114
+ completed bars. Empty frames and single-row frames return empty results.
115
+
116
+ Args:
117
+ df_rate: Rate data ordered oldest-to-newest with the forming bar last.
118
+
119
+ Returns:
120
+ A new DataFrame with all rows except the last. Index and columns are
121
+ preserved. The input frame is not modified.
122
+ """
123
+ return df_rate.iloc[:-1].copy()
124
+
125
+
109
126
  def build_rate_view_name(
110
127
  *,
111
128
  symbol: str,