Files
mt5cli/docs/api/public-contract.md
T
Daichi Narushima dfe80ce500 feat: add close-positions CLI and replace_symbol projection mode (#65 #66) (#67)
* feat: add close-positions CLI command and replace_symbol projection mode (#65 #66)

Part 1 — close-positions CLI (#65):
- Add `close-positions` subcommand delegating to `close_open_positions()`.
- Accepts repeated `--symbol` and `--ticket` filters (AND semantics).
- Supports `--dry-run` (no `--yes` required); live execution requires `--yes`.
- Fails closed with `BadParameter` when neither `--symbol` nor `--ticket` is given.
- Exports normalized `OrderExecutionResult` list as a DataFrame (request/response
  serialized as JSON strings for clean CSV/JSON/Parquet/SQLite output).
- `order-send` remains the raw expert path; `close-positions` is the safer
  high-level helper that builds correct close requests automatically.

Part 2 — ProjectionMode and replace_symbol (#66):
- Add `ProjectionMode = Literal["add", "replace_symbol"]` type alias.
- Add optional `projection_mode` parameter to `calculate_symbol_group_margin_ratio`.
  Default `"add"` preserves existing additive behavior.
  `"replace_symbol"` subtracts current margin for `new_symbol`, then adds
  candidate margin — the subtraction and addition are atomic (suppressed together).
- Export `ProjectionMode` from `mt5cli` and add to `STABLE_SDK_EXPORTS`.
- No mteor-specific strategy, risk-threshold, or policy logic added.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: remove unused ProjectionMode import in test_contracts.py

The parametrized test_stable_exports_are_importable_from_package_root
already covers ProjectionMode via hasattr(mt5cli, name). Ruff correctly
flagged the explicit top-level import as unused (F401).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Bump version to v0.9.6

* fix: address PR #67 review feedback

- Floor replace_symbol margin subtraction at zero to prevent negative ratio
- Serialize response unconditionally via json.dumps (null for dry-run rows)
- Return a schema-preserving empty DataFrame when results list is empty
- Add test: --dry-run --yes precedence (dry-run wins, no order_send)
- Add test: zero-match filter produces empty JSON array with exit 0
- Move projection_mode prose to stable trading section in docs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add runtime validation for projection_mode in calculate_symbol_group_margin_ratio

Unsupported values previously silently fell through as "add". The new
_validate_projection_mode helper raises ValueError with a message that
names the bad value and the two accepted modes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: agent <agent@localhost>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 10:39:49 +09:00

21 KiB

Public API Contract

mt5cli is the generic MT5 data and execution infrastructure layer for downstream Python applications. The intended dependency direction is:

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

Downstream packages should import from the package root (from mt5cli import ...) and use the public tier sets in mt5cli.contract to distinguish API stability. CLI commands mirror the same behavior but are not importable Python APIs.

Public API tiers

mt5cli classifies package-root imports by intended downstream use:

Tier Contract set Meaning
Stable core STABLE_SDK_EXPORTS Preferred SDK surface for downstream MT5 infrastructure adapters. Changes require a deliberate compatibility path.
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.

Stable downstream SDK API

These names are exported from mt5cli and covered by the contract 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 pdmt5.Mt5TradingClient lifecycle
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
substitute_env_placeholders Replace ${NAME} substrings from the environment; opt-in allow_whole_dollar_env for whole-value $NAME
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

Credential resolution is generic: any environment variable name may appear inside ${...}. mt5cli does not hard-code application-specific keys such as mt5_login or mt5_exe.

Pass allow_whole_dollar_env=True to substitute_env_placeholders(), substitute_mapping_values(), resolve_account_spec(), resolve_account_specs(), and build_config() to additionally expand strings whose entire value is a bare $ENV_NAME identifier. Partial strings such as "plan$pass", "abc$ENV", or "$ENV-suffix" are never expanded — only an exact $IDENTIFIER whole-string match qualifies. Default is False to preserve backward compatibility.

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 Mt5TradingClient 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
resolve_history_datasets, resolve_history_timeframes, resolve_history_tick_flags History pipeline configuration
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
RateTarget, build_rate_targets Neutral (symbol, timeframe) series descriptors
load_rate_data, load_rate_data_from_connection Load one table/view into a time-indexed DataFrame
load_rate_series_from_sqlite, load_rate_series_by_granularity Load one or many series; fail clearly when managed views are missing

Pass require_existing=True to rate view resolution helpers when downstream code must fail instead of receiving a best-guess view name. Multi-series loaders require existing managed rate_*__* views unless explicit_tables is supplied.

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 Mt5TradingError 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 and MT5 type re-exports

Symbol Role
Mt5CliError, Mt5ConnectionError, Mt5OperationError, Mt5SchemaError Stable mt5cli exception types
normalize_mt5_exception, call_with_normalized_errors, is_recoverable_mt5_error Error normalization and retry classification
Mt5Config, Mt5RuntimeError, Mt5TradingClient, Mt5TradingError Re-exported pdmt5 types for adapter convenience

Secondary public exports

These names remain importable from mt5cli and are covered by SECONDARY_PUBLIC_EXPORTS, but they are oriented toward CLI/export/schema integrations, parsing, and lower-level MT5 access rather than the stable core SDK surface. Prefer the stable symbols above for downstream infrastructure adapters.

Read-only MT5 data wrappers

Module-level helpers open a transient connection per call. Prefer mt5_session or MT5Client when making many requests in one process.

Area Symbols
Rates copy_rates_from, copy_rates_from_pos, copy_rates_range, latest_rates, collect_latest_rates
Ticks copy_ticks_from, copy_ticks_range, recent_ticks
Account / terminal account_info, terminal_info, mt5_version, last_error, mt5_summary, mt5_summary_as_df
Symbols / market symbols, symbol_info, symbol_info_tick, market_book, minimum_margins
Trading state (read) orders, positions, history_orders, history_deals, recent_history_deals
Multi-account rates collect_latest_rates_for_accounts

Use mt5_version for MetaTrader 5 terminal version data. The name version at the package root refers to importlib.metadata.version (package metadata), not the MT5 SDK helper.

Schema, export, and parser helpers

Area Symbols
Dataset contracts DataKind, Dataset, IfExists, DEDUP_KEYS, REQUIRED_COLUMNS, TIME_COLUMNS, KNOWN_MT5_TIME_COLUMNS
Schema normalization normalize_dataframe, normalize_time_columns, schema_columns, validate_schema
Export helpers detect_format, export_dataframe, export_dataframe_to_sqlite
Symbol parsing normalize_symbol, normalize_symbols
Time parsing ensure_utc, parse_date_range, parse_datetime, recent_window
MT5 parsing maps granularity_name, parse_tick_flags, parse_timeframe, TICK_FLAG_MAP, TIMEFRAME_MAP
Trading data shapes POSITION_COLUMNS

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 the stable and secondary tier sets is importable from mt5cli, documents key closed-bar, rate-view, SQLite loading, account-resolution, and trading-session behaviors, and keeps the tier sets aligned with __all__.