* feat: add injectable update_backend to ThrottledHistoryUpdater Allow downstream applications to substitute the history update backend via the ThrottledHistoryUpdater constructor without monkey-patching mt5cli.sdk.update_history. Defaults to update_history for backward compatibility. Co-authored-by: Daichi Narushima <dceoy@users.noreply.github.com> * chore: fix lint and format after QA Co-authored-by: Daichi Narushima <dceoy@users.noreply.github.com> * chore: bump version to 0.8.2 Co-authored-by: Daichi Narushima <dceoy@users.noreply.github.com> * fix: use explicit None check for ThrottledHistoryUpdater backend Only None selects the default update_history backend so falsy callable objects with __bool__ returning False are preserved as custom backends. Co-authored-by: Daichi Narushima <dceoy@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Daichi Narushima <dceoy@users.noreply.github.com>
4.8 KiB
SDK Module
::: mt5cli.sdk
Resilient multi-account orchestration
The SDK ships strategy-agnostic helpers for building long-running collectors on top of the read-only client. None of them depend on a particular trading application.
Retrying transient rate collection
collect_latest_rates_for_accounts_with_retries() wraps
collect_latest_rates_for_accounts() with bounded exponential backoff. Only
pdmt5.Mt5TradingError and pdmt5.Mt5RuntimeError are retried; the final
failure is re-raised once retry_count is exhausted.
from mt5cli import AccountSpec, collect_latest_rates_for_accounts_with_retries
accounts = [AccountSpec(symbols=["EURUSD"], login=12345)]
rates = collect_latest_rates_for_accounts_with_retries(
accounts,
["M1", "H1"],
count=500,
retry_count=3,
backoff_base=2, # sleeps 2s, 4s, 8s between attempts
)
Latest closed rate bars
MetaTrader 5 start_pos=0 includes the still-forming current bar as the last
row. fetch_latest_closed_rates() handles one connected client; multi-account
helpers fetch count + 1 bars, drop that row with drop_forming_rate_bar(),
and validate each series is non-empty. Returned frames are ordered
oldest-to-newest and may contain fewer than count rows only when MT5 returns
fewer closed bars.
from mt5cli import (
AccountSpec,
collect_latest_closed_rates_by_granularity,
fetch_latest_closed_rates,
)
closed = fetch_latest_closed_rates(
client,
symbol="EURUSD",
granularity="M1",
count=500,
)
rates = collect_latest_closed_rates_by_granularity(
[AccountSpec(symbols=["EURUSD"], login=12345)],
["M1", "H1"],
count=500,
retry_count=3,
)
closed_m1 = rates["EURUSD", "M1"]
Use collect_latest_closed_rates_by_granularity() when callers prefer keys such
as ("EURUSD", "M1") instead of integer timeframes.
Resolving credentials and ${ENV_VAR} placeholders
resolve_account_spec() / resolve_account_specs() merge explicit override
values over AccountSpec fields and expand ${ENV_VAR} placeholders, keeping
secrets out of plan/config files. A missing environment variable raises
ValueError.
import os
from mt5cli import AccountSpec, resolve_account_specs
os.environ["MT5_LOGIN"] = "12345"
os.environ["MT5_PASSWORD"] = "secret"
accounts = [
AccountSpec(symbols=["EURUSD"], login="${MT5_LOGIN}", password="${MT5_PASSWORD}")
]
resolved = resolve_account_specs(accounts, server="Broker-Demo")
# resolved[0].login == "12345", resolved[0].server == "Broker-Demo"
Throttled incremental history updates
ThrottledHistoryUpdater wraps update_history() with a minimum interval
between successful runs (using a monotonic clock), so an application loop can
call it every iteration without over-fetching.
from pdmt5 import Mt5Config, Mt5DataClient
from mt5cli import Dataset, ThrottledHistoryUpdater
updater = ThrottledHistoryUpdater(
output="history.db",
datasets={Dataset.rates},
timeframes=["M1"],
interval_seconds=60, # <= 0 updates on every call
)
client = Mt5DataClient(config=Mt5Config(login=12345))
client.initialize_and_login_mt5()
try:
while True:
updater.update(client, ["EURUSD", "GBPUSD"]) # no-op until 60s elapse
# ... do other work; break when shutting down ...
finally:
client.shutdown()
Pass update_backend to substitute the default update_history implementation
without monkey-patching mt5cli.sdk.update_history. The callable receives the
same keyword arguments as update_history (client, output, symbols,
datasets, timeframes, flags, lookback_hours, with_views,
include_account_events). The resolved backend is stored on
updater.update_backend for inspection or subclassing.
from mt5cli import ThrottledHistoryUpdater, update_history
def app_update_history(**kwargs) -> None:
update_history(**kwargs) # or delegate to application-specific logic
updater = ThrottledHistoryUpdater(
output="history.db",
interval_seconds=60,
update_backend=app_update_history,
)
By default recoverable errors (Mt5TradingError, Mt5RuntimeError,
sqlite3.Error, ValueError, OSError, and MT5 client capability
AttributeError / TypeError for history API methods) propagate so the caller
controls logging; pass suppress_errors=True to swallow them and return
False without advancing the throttle. Other AttributeError / TypeError
values always propagate. Input validation (_resolve_update_history_request)
runs before any MT5 or SQLite calls, but when suppress_errors=True the
resulting ValueError is suppressed along with other recoverable errors.
Trading-capable sessions
For order placement and trading calculations, use the dedicated
Trading module. The read-only Mt5CliClient and mt5_session()
helpers in this module are unchanged.