Files
mt5cli/docs/api/public-contract.md
T
Daichi Narushima 93565681e1 fix: decouple mt5cli from pdmt5 high-level trading helpers (#76)
* fix: decouple mt5cli from pdmt5 high-level trading helpers

- Replace Mt5TradingClient type annotations with internal _Mt5ClientProtocol
- Lazy-import Mt5TradingClient in create_trading_client to avoid hard dependency
- Replace Mt5TradingError with Mt5OperationError in mt5cli validation paths
- Update exception handling to support future pdmt5 versions without Mt5TradingError
- Add test to enforce that mt5cli doesn't import high-level symbols at module level
- Update documentation to clarify dependency boundaries

mt5cli now relies only on low-level MT5 primitives:
- Mt5Config for configuration
- Mt5RuntimeError for runtime errors
- Raw MT5 methods (order_send, order_check, account_info, etc.)

This aligns with pdmt5's direction to remove high-level trading helpers and focus
on low-level MT5 access plus DataFrame/dict conversion.

Fixes #75 (dceoy/mt5cli#75)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PcGVFTVgyqzse3LLw38ber

* fix: address PR #76 review feedback on pdmt5 decoupling

- Replace Mt5TradingClient with Mt5DataClient in create_trading_client()
  so the function no longer depends on the high-level trading client
- Fix _RECOVERABLE_MT5_ERRORS in exceptions.py to use tuple unpacking
  form, removing the incorrect ternary assignment
- Add pragma: no cover to except ImportError branches in exceptions.py
  and sdk.py (dead code when pdmt5 is installed)
- Switch coverage exclude_lines to exclude_also so the default
  pragma: no cover pattern is preserved; also exclude bare ... stubs
  (Protocol method bodies) from coverage
- Correct inaccurate note in docs/api/public-contract.md: Mt5TradingClient
  is no longer required internally; Mt5TradingError is conditionally
  available but mt5cli raises Mt5OperationError for trading failures
- Update all mock patches from pdmt5.Mt5TradingClient to
  mt5cli.trading.Mt5DataClient to match the new module-level import

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-26 22:26:54 +09:00

17 KiB

Public API Contract

mt5cli is the canonical operational trading SDK and CLI/batch layer over pdmt5. The intended dependency direction is:

downstream app -> mt5cli -> pdmt5 -> MetaTrader 5

Responsibility boundary

Layer Owns
pdmt5 MT5 core wrapper; DataFrame/dict conversion; canonical MT5 constants and parsers; direct low-level order primitives
mt5cli CLI/batch workflows; SQLite history collection; normalized datasets; closed-bar helpers; small downstream operational SDK; generic broker-facing margin/volume/order orchestration
downstream Strategy logic; signals; risk policy; backtesting; optimization; YAML/application semantics

Downstream code should import raw pdmt5 types and constants (such as Mt5Config, Mt5RuntimeError, TIMEFRAME_MAP, COPY_TICKS_MAP) directly from pdmt5 when needed. mt5cli does not serve as a pass-through compatibility namespace for pdmt5. mt5cli's trading helpers type their client parameter against an internal protocol backed by pdmt5.Mt5DataClient; Mt5TradingClient is no longer required. Mt5TradingError is conditionally imported where still present in pdmt5, but mt5cli raises Mt5OperationError for all trading-related failures.

Note: the former mt5cli re-export TICK_FLAG_MAP corresponds to COPY_TICKS_MAP in pdmt5 — the name changed, it was not simply moved.

Downstream packages should import from the package root (from mt5cli import ...). The contract set STABLE_SDK_EXPORTS in mt5cli.contract enumerates every package-root symbol. Lower-level helpers (schema utilities, export functions, parser helpers, low-level MT5 wrappers) are available directly from their owning modules (mt5cli.schemas, mt5cli.utils, mt5cli.converters, mt5cli.sdk, etc.) and are not part of the root SDK surface.

Stable downstream SDK API

These names are exported from mt5cli and enumerated in mt5cli.STABLE_SDK_EXPORTS (defined in mt5cli.contract).

Session lifecycle and configuration

Symbol Role
MT5Client Read-only data client with optional order_check / order_send
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
mt5_session Context manager: initialize, login, yield client, shutdown
create_trading_client, mt5_trading_session Trading-capable MT5 client lifecycle; returns a client supporting order execution and account management
AccountSpec Generic account group: symbols plus optional credentials
resolve_account_spec, resolve_account_specs Merge overrides and expand ${ENV_VAR} placeholders; opt-in allow_whole_dollar_env for bare $NAME

Closed-bar rate helpers

MetaTrader 5 returns the still-forming bar as the last row when start_pos=0. Use these helpers instead of reimplementing bar trimming or timestamp normalization in downstream apps.

Symbol Role
drop_forming_rate_bar Remove the last row from chronologically ordered rate data
fetch_latest_closed_rates Single connected client: fetch count + 1, drop forming bar
fetch_latest_closed_rates_for_trading_client Closed bars from an active trading client session; returns RangeIndex
fetch_latest_closed_rates_indexed Same as above but returns a UTC DatetimeIndex named "time" (no time column)
collect_latest_closed_rates_for_accounts Multi-account closed bars with optional retry wrapper
collect_latest_closed_rates_by_granularity Same data keyed by (symbol, granularity_name)
collect_latest_rates_for_accounts_with_retries Bounded exponential backoff for transient MT5 errors

SQLite history collection and rate loading

Symbol Role
collect_history One-shot date-range export into SQLite
update_history, update_history_with_config Incremental append from MAX(time) cursors
ThrottledHistoryUpdater Minimum interval between successful incremental updates; optional update_backend injection
RateTarget, build_rate_targets Neutral (symbol, timeframe) series descriptors
load_rate_series_from_sqlite, load_rate_series_by_granularity Load one or many series; fail clearly when managed views are missing

See History Collection (SQLite) for schema, view naming, and ER diagrams.

Trading and sizing primitives (generic)

These helpers implement broker-facing calculations only. They do not encode strategy entries, exits, Kelly sizing, or signal logic.

Symbol Role
get_account_snapshot, get_symbol_snapshot, get_tick_snapshot, get_positions_frame Normalized account/symbol/tick/position views
extract_tick_price Positive finite bid/ask extraction from tick mappings
detect_position_side Net long / short / flat from open positions
calculate_spread_ratio Relative bid-ask spread
calculate_margin_and_volume, calculate_volume_by_margin, calculate_new_position_margin_ratio Margin budget and volume sizing
normalize_order_volume, estimate_order_margin, calculate_positions_margin Broker volume normalization and margin totals
calculate_positions_margin_by_symbol Per-symbol margin map (resilient, first-seen order)
calculate_positions_margin_safe Summed total margin across symbols (failed symbols skipped)
calculate_projected_margin_ratio Estimated symbol-scoped margin/equity after optional new exposure
calculate_account_projected_margin_ratio Account snapshot margin/equity after optional new exposure
calculate_symbol_group_margin_ratio Estimated symbol-group margin/equity with optional exposure
determine_order_limits SL/TP price levels from ratios
calculate_trailing_stop_updates Per-ticket generic trailing stop-loss update plan
ensure_symbol_selected Select/verify Market Watch visibility
place_market_order, close_open_positions, update_sltp_for_open_positions, update_trailing_stop_loss_for_open_positions Order execution helpers (dry_run supported)
MarginVolume, OrderLimits, OrderExecutionResult Typed return contracts for order helpers
OrderSide, OrderFillingMode, OrderTimeMode, PositionSide, ExecutionStatus Typed enums for order helpers
ProjectionMode Literal type for calculate_symbol_group_margin_ratio projection

calculate_symbol_group_margin_ratio accepts an optional projection_mode parameter ("add" by default). Pass projection_mode="replace_symbol" to subtract current exposure for new_symbol before adding the candidate margin — useful for reversal-style projections. mt5cli only calculates broker-facing exposure; downstream applications own thresholds, risk guard actions, and strategy policy.

MT5Client.order_send() and CLI order-send --yes are live execution paths.

Order helpers validate broker stop-level distance in determine_order_limits() and raise Mt5OperationError when computed SL/TP prices are too close to the entry quote. Validation uses trade_stops_level * point from the current quote and symbol metadata as a pre-check only; it does not guarantee live order acceptance after price movement and does not inspect trade_freeze_level. Live place_market_order() and SL/TP updates call ensure_symbol_selected() so hidden symbols are added to Market Watch before sending requests. Failed, malformed, or unknown broker retcodes are fail-closed and returned as status="failed" with normalized request / response details; dry_run=True never calls ensure_symbol_selected() or order_send().

Errors

Symbol Role
Mt5CliError, Mt5ConnectionError, Mt5OperationError, Mt5SchemaError Stable mt5cli exception types

Module-scoped helpers

Lower-level helpers are available from their owning modules and are not part of the package-root stable surface. Import them directly when needed:

Module Examples
mt5cli.history resolve_rate_view_name, resolve_rate_tables, load_rate_data, build_rate_view_name
mt5cli.sdk copy_rates_from, copy_ticks_from, account_info, symbols, mt5_summary, latest_rates
mt5cli.schemas DataKind, normalize_dataframe, validate_schema, DEDUP_KEYS
mt5cli.utils Dataset, IfExists, detect_format, export_dataframe, export_dataframe_to_sqlite
mt5cli.converters normalize_symbol, ensure_utc, parse_date_range, granularity_name
mt5cli.exceptions normalize_mt5_exception, call_with_normalized_errors, is_recoverable_mt5_error

CLI commands

The Typer application in mt5cli.cli exposes file-export commands documented in CLI Module and the project README. CLI commands:

  • Require -o/--output and write CSV, JSON, Parquet, or SQLite.
  • Accept global MT5 connection options (--login, --password, --server, --path, --timeout).
  • Delegate to the same Python APIs described here; they are not duplicated business logic.

order-send is the expert raw-request path; it requires --yes and a fully constructed request payload. close-positions is the safer high-level helper that closes open positions by --symbol or --ticket using close_open_positions(). Both order-send --yes and close-positions --yes are live execution paths. close-positions --dry-run previews close orders without placing them and does not require --yes.

Internal helpers (not stable)

Do not import these for downstream contracts; they may change without a semver notice:

Module Examples
mt5cli.sdk connected_client, _run_with_client, private coercion helpers
mt5cli.history write_*_dataset, deduplicate_history_tables, parse_sqlite_timestamp
mt5cli.retry retry_with_backoff
mt5cli.cli Typer command handlers and Click parameter types
Leading-underscore names Any _-prefixed function or method

Use the package-root stable exports instead of reaching into submodule internals.

Explicitly out of scope

mt5cli must not implement downstream strategy or research responsibilities. The following belong in consuming applications, not in mt5cli:

  • Signal detection (for example AR-GARCH or other model-specific triggers)
  • Backtesting, walk-forward analysis, or parameter optimization
  • Strategy-specific risk policy, position sizing systems, or Kelly fractions
  • Entry/exit decision logic or YAML strategy semantics
  • Application-specific credential schema keys wired into mt5cli internals

mt5cli provides connection lifecycle, normalized data access, SQLite history machinery, closed-bar helpers, generic margin/volume/spread/SL/TP utilities, and optional order primitives so downstream apps can focus on strategy code behind their own adapter layer.

Contract verification

tests/test_contracts.py asserts that every name in STABLE_SDK_EXPORTS is importable from mt5cli, that all package-root exports are covered by the stable set, and documents key closed-bar, SQLite loading, account-resolution, and trading-session behaviors.