| def main() -> None:
- """Run the mt5cli CLI."""
- app()
+ | def main() -> None:
+ """Run the mt5cli CLI."""
+ app()
|
@@ -1979,6 +2081,225 @@ with no additional validation beyond what MT5 itself performs. Use
+
+ snapshot
+
+
+
+ snapshot(
+ ctx: Context,
+ symbol: Annotated[
+ list[str] | None,
+ Option(
+ "--symbol",
+ "-s",
+ help="Symbol filter for positions/orders (repeat for multiple).",
+ ),
+ ] = None,
+ with_account: Annotated[
+ bool,
+ Option(
+ "--with-account/--no-account",
+ help="Snapshot account info.",
+ ),
+ ] = True,
+ with_positions: Annotated[
+ bool,
+ Option(
+ "--with-positions/--no-positions",
+ help="Snapshot open positions.",
+ ),
+ ] = True,
+ with_orders: Annotated[
+ bool,
+ Option(
+ "--with-orders/--no-orders",
+ help="Snapshot active orders.",
+ ),
+ ] = True,
+ with_terminal: Annotated[
+ bool,
+ Option(
+ "--with-terminal/--no-terminal",
+ help="Snapshot terminal info.",
+ ),
+ ] = True,
+ with_grafana_schema: Annotated[
+ bool,
+ Option(
+ "--with-grafana-schema/--no-grafana-schema",
+ help="Ensure Grafana views and indexes exist.",
+ ),
+ ] = False,
+) -> None
+
+
+
+
+ Snapshot current account, position, order, and terminal state into SQLite.
+ Appends a timestamped snapshot row for each data type. Never places
+orders or modifies trading state.
+
+
+ Raises:
+
+
+
+ | Type |
+ Description |
+
+
+
+
+
+ BadParameter
+ |
+
+
+ If the output format is not SQLite3.
+
+ |
+
+
+
+
+
+
+ Source code in mt5cli/cli.py
+ | @app.command(rich_help_panel="Collection")
+def snapshot(
+ ctx: typer.Context,
+ symbol: Annotated[
+ list[str] | None,
+ typer.Option(
+ "--symbol",
+ "-s",
+ help="Symbol filter for positions/orders (repeat for multiple).",
+ ),
+ ] = None,
+ with_account: Annotated[
+ bool,
+ typer.Option("--with-account/--no-account", help="Snapshot account info."),
+ ] = True,
+ with_positions: Annotated[
+ bool,
+ typer.Option(
+ "--with-positions/--no-positions", help="Snapshot open positions."
+ ),
+ ] = True,
+ with_orders: Annotated[
+ bool,
+ typer.Option("--with-orders/--no-orders", help="Snapshot active orders."),
+ ] = True,
+ with_terminal: Annotated[
+ bool,
+ typer.Option("--with-terminal/--no-terminal", help="Snapshot terminal info."),
+ ] = True,
+ with_grafana_schema: Annotated[
+ bool,
+ typer.Option(
+ "--with-grafana-schema/--no-grafana-schema",
+ help="Ensure Grafana views and indexes exist.",
+ ),
+ ] = False,
+) -> None:
+ """Snapshot current account, position, order, and terminal state into SQLite.
+
+ Appends a timestamped snapshot row for each data type. Never places
+ orders or modifies trading state.
+
+ Raises:
+ typer.BadParameter: If the output format is not SQLite3.
+ """
+ export_ctx = _get_export_context(ctx)
+ if export_ctx.output_format != "sqlite3":
+ msg = (
+ "snapshot requires SQLite3 output."
+ " Use a .db/.sqlite/.sqlite3 extension or --format sqlite3."
+ )
+ raise typer.BadParameter(msg)
+ sdk.update_observability_with_config(
+ output=export_ctx.output,
+ config=export_ctx.config,
+ symbols=list(symbol) if symbol else None,
+ include_account=with_account,
+ include_positions=with_positions,
+ include_orders=with_orders,
+ include_terminal=with_terminal,
+ with_grafana_schema=with_grafana_schema,
+ )
+ logger.info("Snapshot written to %s", export_ctx.output)
+
|
+
+
+
+
+
+
+
+
symbol_info
diff --git a/api/client/index.html b/api/client/index.html
index 3bbd5f4..249c596 100644
--- a/api/client/index.html
+++ b/api/client/index.html
@@ -242,19 +242,7 @@ responsibility of downstream applications.
Source code in mt5cli/sdk.py
- 419
-420
-421
-422
-423
-424
-425
-426
-427
-428
-429
-430
-431
+ | def __init__(
- self,
- *,
- path: str | None = None,
- login: int | None = None,
- password: str | None = None,
- server: str | None = None,
- timeout: int | None = None,
- retry_count: int = 3,
- config: Mt5Config | None = None,
- client: Mt5DataClient | None = None,
-) -> None:
- """Initialize the SDK client.
-
- Args:
- path: Path to MetaTrader5 terminal EXE file.
- login: Trading account login.
- password: Trading account password.
- server: Trading server name.
- timeout: Connection timeout in milliseconds.
- retry_count: Number of MT5 initialization retries for sessions
- opened by this client.
- config: Optional pre-built ``Mt5Config`` (overrides other args).
- client: Optional already-connected ``Mt5DataClient``. Injected
- clients are reused as-is and are not initialized or shut down.
- """
- self._config = config or build_config(
- path=path,
- login=login,
- password=password,
- server=server,
- timeout=timeout,
- )
- self._retry_count = retry_count
- self._client = client
- self._owns_client = client is None
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
| def __init__(
+ self,
+ *,
+ path: str | None = None,
+ login: int | None = None,
+ password: str | None = None,
+ server: str | None = None,
+ timeout: int | None = None,
+ retry_count: int = 3,
+ config: Mt5Config | None = None,
+ client: Mt5DataClient | None = None,
+) -> None:
+ """Initialize the SDK client.
+
+ Args:
+ path: Path to MetaTrader5 terminal EXE file.
+ login: Trading account login.
+ password: Trading account password.
+ server: Trading server name.
+ timeout: Connection timeout in milliseconds.
+ retry_count: Number of MT5 initialization retries for sessions
+ opened by this client.
+ config: Optional pre-built ``Mt5Config`` (overrides other args).
+ client: Optional already-connected ``Mt5DataClient``. Injected
+ clients are reused as-is and are not initialized or shut down.
+ """
+ self._config = config or build_config(
+ path=path,
+ login=login,
+ password=password,
+ server=server,
+ timeout=timeout,
+ )
+ self._retry_count = retry_count
+ self._client = client
+ self._owns_client = client is None
|
@@ -789,19 +789,7 @@ to path, login, password, and serve
Source code in mt5cli/sdk.py
- 311
-312
-313
-314
-315
-316
-317
-318
-319
-320
-321
-322
-323
+ | def build_config(
- *,
- path: str | None = None,
- login: int | str | None = None,
- password: str | None = None,
- server: str | None = None,
- timeout: int | None = None,
- allow_whole_dollar_env: bool = False,
-) -> Mt5Config:
- """Build an ``Mt5Config`` from optional connection parameters.
-
- Args:
- path: Optional terminal executable path.
- login: Optional trading account login. Integers are preserved. String
- values are coerced: empty or whitespace-only strings become
- ``None``; numeric strings such as ``"12345"`` are converted to
- ``int``; non-numeric strings raise ``ValueError``. When
- ``allow_whole_dollar_env=True``, ``$ENV_NAME`` and
- ``${ENV_NAME}`` placeholders are expanded before coercion.
- password: Optional trading account password.
- server: Optional trading server name.
- timeout: Optional connection timeout in milliseconds.
- allow_whole_dollar_env: When ``True``, string parameters that are
- exactly ``$ENV_NAME`` are expanded from the environment. Applies
- to ``path``, ``login``, ``password``, and ``server``. Default
- ``False`` preserves existing behavior.
-
- Returns:
- Configured ``Mt5Config`` instance.
- """
- if allow_whole_dollar_env:
- if path is not None:
- path = substitute_env_placeholders(path, allow_whole_dollar_env=True)
- if isinstance(login, str):
- login = substitute_env_placeholders(login, allow_whole_dollar_env=True)
- if password is not None:
- password = substitute_env_placeholders(
- password, allow_whole_dollar_env=True
- )
- if server is not None:
- server = substitute_env_placeholders(server, allow_whole_dollar_env=True)
- return Mt5Config(
- path=path,
- login=_coerce_login(login),
- password=password,
- server=server,
- timeout=timeout,
- )
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
| def build_config(
+ *,
+ path: str | None = None,
+ login: int | str | None = None,
+ password: str | None = None,
+ server: str | None = None,
+ timeout: int | None = None,
+ allow_whole_dollar_env: bool = False,
+) -> Mt5Config:
+ """Build an ``Mt5Config`` from optional connection parameters.
+
+ Args:
+ path: Optional terminal executable path.
+ login: Optional trading account login. Integers are preserved. String
+ values are coerced: empty or whitespace-only strings become
+ ``None``; numeric strings such as ``"12345"`` are converted to
+ ``int``; non-numeric strings raise ``ValueError``. When
+ ``allow_whole_dollar_env=True``, ``$ENV_NAME`` and
+ ``${ENV_NAME}`` placeholders are expanded before coercion.
+ password: Optional trading account password.
+ server: Optional trading server name.
+ timeout: Optional connection timeout in milliseconds.
+ allow_whole_dollar_env: When ``True``, string parameters that are
+ exactly ``$ENV_NAME`` are expanded from the environment. Applies
+ to ``path``, ``login``, ``password``, and ``server``. Default
+ ``False`` preserves existing behavior.
+
+ Returns:
+ Configured ``Mt5Config`` instance.
+ """
+ if allow_whole_dollar_env:
+ if path is not None:
+ path = substitute_env_placeholders(path, allow_whole_dollar_env=True)
+ if isinstance(login, str):
+ login = substitute_env_placeholders(login, allow_whole_dollar_env=True)
+ if password is not None:
+ password = substitute_env_placeholders(
+ password, allow_whole_dollar_env=True
+ )
+ if server is not None:
+ server = substitute_env_placeholders(server, allow_whole_dollar_env=True)
+ return Mt5Config(
+ path=path,
+ login=_coerce_login(login),
+ password=password,
+ server=server,
+ timeout=timeout,
+ )
|
diff --git a/api/converters/index.html b/api/converters/index.html
index e1bbc02..83725e3 100644
--- a/api/converters/index.html
+++ b/api/converters/index.html
@@ -938,8 +938,7 @@ suffixes (for example XAUUSDm, US500.cash, or EU
Source code in mt5cli/utils.py
- 350
-351
+ | def parse_datetime(value: str) -> datetime:
- """Parse an ISO 8601 datetime string to a timezone-aware datetime.
-
- Args:
- value: ISO 8601 datetime string (e.g., '2024-01-01' or
- '2024-01-01T12:00:00+00:00').
-
- Returns:
- Parsed datetime with UTC timezone if no timezone is specified.
-
- Raises:
- ValueError: If the string cannot be parsed.
- """
- try:
- dt = datetime.fromisoformat(value)
- except ValueError:
- msg = f"Invalid datetime format: '{value}'. Use ISO 8601 format."
- raise ValueError(msg) from None
- if dt.tzinfo is None:
- dt = dt.replace(tzinfo=UTC)
- return dt
+370
+371
| def parse_datetime(value: str) -> datetime:
+ """Parse an ISO 8601 datetime string to a timezone-aware datetime.
+
+ Args:
+ value: ISO 8601 datetime string (e.g., '2024-01-01' or
+ '2024-01-01T12:00:00+00:00').
+
+ Returns:
+ Parsed datetime with UTC timezone if no timezone is specified.
+
+ Raises:
+ ValueError: If the string cannot be parsed.
+ """
+ try:
+ dt = datetime.fromisoformat(value)
+ except ValueError:
+ msg = f"Invalid datetime format: '{value}'. Use ISO 8601 format."
+ raise ValueError(msg) from None
+ if dt.tzinfo is None:
+ dt = dt.replace(tzinfo=UTC)
+ return dt
|
@@ -1080,8 +1080,7 @@ suffixes (for example XAUUSDm, US500.cash, or EU
Source code in mt5cli/utils.py
- 397
-398
+ | def parse_tick_flags(value: object) -> int:
- """Parse tick flags string or integer value.
-
- Args:
- value: Tick flag name (ALL, INFO, TRADE, COPY_TICKS_*) or integer value.
-
- Returns:
- Integer tick flag value compatible with MetaTrader 5 ``COPY_TICKS_*``.
-
- Raises:
- ValueError: If the flag is invalid.
- """
- try:
- return _parse_copy_ticks(value)
- except ValueError:
- display = value if isinstance(value, str) else repr(value)
- valid = ", ".join(_TICK_FLAG_NAMES)
- msg = (
- f"Invalid tick flags: '{display}'. "
- f"Use one of: {valid}, or a supported integer."
- )
- raise ValueError(msg) from None
+418
+419
| def parse_tick_flags(value: object) -> int:
+ """Parse tick flags string or integer value.
+
+ Args:
+ value: Tick flag name (ALL, INFO, TRADE, COPY_TICKS_*) or integer value.
+
+ Returns:
+ Integer tick flag value compatible with MetaTrader 5 ``COPY_TICKS_*``.
+
+ Raises:
+ ValueError: If the flag is invalid.
+ """
+ try:
+ return _parse_copy_ticks(value)
+ except ValueError:
+ display = value if isinstance(value, str) else repr(value)
+ valid = ", ".join(_TICK_FLAG_NAMES)
+ msg = (
+ f"Invalid tick flags: '{display}'. "
+ f"Use one of: {valid}, or a supported integer."
+ )
+ raise ValueError(msg) from None
|
@@ -1224,8 +1224,7 @@ suffixes (for example XAUUSDm, US500.cash, or EU
Source code in mt5cli/utils.py
- 373
-374
+ | def parse_timeframe(value: object) -> int:
- """Parse a timeframe string or integer value.
-
- Args:
- value: Timeframe name (e.g., 'M1', 'H1', 'D1') or integer value.
-
- Returns:
- Integer timeframe value.
-
- Raises:
- ValueError: If the timeframe is invalid.
- """
- try:
- return _parse_timeframe(value)
- except ValueError:
- display = value if isinstance(value, str) else repr(value)
- valid = ", ".join(TIMEFRAME_NAMES)
- msg = (
- f"Invalid timeframe: '{display}'. "
- f"Use one of: {valid}, or a supported integer."
- )
- raise ValueError(msg) from None
+394
+395
| def parse_timeframe(value: object) -> int:
+ """Parse a timeframe string or integer value.
+
+ Args:
+ value: Timeframe name (e.g., 'M1', 'H1', 'D1') or integer value.
+
+ Returns:
+ Integer timeframe value.
+
+ Raises:
+ ValueError: If the timeframe is invalid.
+ """
+ try:
+ return _parse_timeframe(value)
+ except ValueError:
+ display = value if isinstance(value, str) else repr(value)
+ valid = ", ".join(TIMEFRAME_NAMES)
+ msg = (
+ f"Invalid timeframe: '{display}'. "
+ f"Use one of: {valid}, or a supported integer."
+ )
+ raise ValueError(msg) from None
|
diff --git a/api/public-contract/index.html b/api/public-contract/index.html
index 9e27c11..57f3842 100644
--- a/api/public-contract/index.html
+++ b/api/public-contract/index.html
@@ -422,6 +422,144 @@ after price movement and does not inspect trade_freeze_level. Live
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().
+Grafana observability (SQLite read model)
+These helpers prepare a SQLite database as a Grafana datasource. All DDL is
+idempotent (CREATE TABLE IF NOT EXISTS, DROP VIEW IF EXISTS + CREATE
+VIEW, CREATE INDEX IF NOT EXISTS). Missing source tables are skipped with a
+warning rather than raising an error.
+
+
+
+| Symbol |
+Role |
+
+
+
+
+update_observability |
+Append one timestamped snapshot row per data type; accepts an already-connected Mt5DataClient |
+
+
+update_observability_with_config |
+Standalone wrapper: opens/closes MT5 connection automatically around update_observability |
+
+
+
+Both functions write to the SQLite path given by output=. The optional
+symbols parameter filters positions_get / orders_get by symbol.
+with_grafana_schema=False (default) skips Grafana view/index setup; run
+grafana-schema once to set up the schema, then call snapshot repeatedly
+without this flag.
+Snapshot tables (created by create_snapshot_tables in mt5cli.grafana):
+
+
+
+| Table |
+Content |
+
+
+
+
+account_snapshots |
+Balance, equity, margin, free-margin, P&L |
+
+
+position_snapshots |
+Open positions: symbol, volume, profit, … |
+
+
+order_snapshots |
+Active orders: symbol, type, price, … |
+
+
+terminal_snapshots |
+Terminal connectivity and build info |
+
+
+snapshot_runs |
+Per-run status (ok / error) timestamp |
+
+
+
+Grafana time-series views (integer epoch-second time column; snapshot views also expose run_id):
+
+
+
+| View |
+Source |
+
+
+
+
+grafana_rates |
+rates table |
+
+
+grafana_ticks |
+ticks table |
+
+
+grafana_history_deals |
+history_deals |
+
+
+grafana_history_orders |
+history_orders |
+
+
+grafana_trade_deals |
+history_deals trade types only |
+
+
+grafana_cash_events |
+history_deals non-trade events |
+
+
+grafana_symbol_pnl |
+Per-close-deal P&L per symbol |
+
+
+grafana_account_snapshots |
+account_snapshots |
+
+
+grafana_position_snapshots |
+position_snapshots |
+
+
+grafana_order_snapshots |
+order_snapshots |
+
+
+grafana_terminal_snapshots |
+terminal_snapshots |
+
+
+
+Grafana static summary views (no time column; use for table/stat panels, not time-series):
+
+
+
+| View |
+Source |
+
+
+
+
+grafana_realized_pnl |
+Cumulative realized PnL per symbol |
+
+
+grafana_trade_stats |
+Win/loss counts and profit per symbol |
+
+
+
+Lower-level helpers (ensure_grafana_schema, create_grafana_views,
+create_grafana_indexes, create_snapshot_tables, start_snapshot_run,
+insert_account_snapshot, insert_position_snapshots, insert_order_snapshots,
+insert_terminal_snapshot, record_snapshot_run) are available directly from
+mt5cli.grafana and are not part of the package-root stable surface.
Errors
@@ -449,6 +587,10 @@ of the package-root stable surface. Import them directly when needed:
+mt5cli.grafana |
+ensure_grafana_schema, create_grafana_views, create_grafana_indexes, create_snapshot_tables, start_snapshot_run, insert_account_snapshot, record_snapshot_run |
+
+
mt5cli.history |
resolve_rate_view_name, resolve_rate_tables, load_rate_data, build_rate_view_name |
@@ -484,6 +626,13 @@ of the package-root stable surface. Import them directly when needed:
Delegate to the same Python APIs described here; they are not duplicated
business logic.
+grafana-schema initializes Grafana views, indexes, and snapshot tables in the
+target SQLite database without connecting to MT5. It is idempotent and safe to
+run repeatedly.
+snapshot appends one timestamped row per enabled data type
+(--with-account, --with-positions, --with-orders, --with-terminal) and
+never places orders or modifies trading state. Both commands require
+-o/--output to point at a .db / SQLite file.
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
diff --git a/api/sdk/index.html b/api/sdk/index.html
index 05cc2c4..18d650c 100644
--- a/api/sdk/index.html
+++ b/api/sdk/index.html
@@ -281,8 +281,10 @@
"terminal_info",
"update_history",
"update_history_with_config",
- "version",
-]
+ "update_observability",
+ "update_observability_with_config",
+ "version",
+]
@@ -810,19 +812,7 @@ clients are reused as-is and are not initialized or shut down.
Source code in mt5cli/sdk.py
- 419
-420
-421
-422
-423
-424
-425
-426
-427
-428
-429
-430
-431
+ | def __init__(
- self,
- *,
- path: str | None = None,
- login: int | None = None,
- password: str | None = None,
- server: str | None = None,
- timeout: int | None = None,
- retry_count: int = 3,
- config: Mt5Config | None = None,
- client: Mt5DataClient | None = None,
-) -> None:
- """Initialize the SDK client.
-
- Args:
- path: Path to MetaTrader5 terminal EXE file.
- login: Trading account login.
- password: Trading account password.
- server: Trading server name.
- timeout: Connection timeout in milliseconds.
- retry_count: Number of MT5 initialization retries for sessions
- opened by this client.
- config: Optional pre-built ``Mt5Config`` (overrides other args).
- client: Optional already-connected ``Mt5DataClient``. Injected
- clients are reused as-is and are not initialized or shut down.
- """
- self._config = config or build_config(
- path=path,
- login=login,
- password=password,
- server=server,
- timeout=timeout,
- )
- self._retry_count = retry_count
- self._client = client
- self._owns_client = client is None
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
| def __init__(
+ self,
+ *,
+ path: str | None = None,
+ login: int | None = None,
+ password: str | None = None,
+ server: str | None = None,
+ timeout: int | None = None,
+ retry_count: int = 3,
+ config: Mt5Config | None = None,
+ client: Mt5DataClient | None = None,
+) -> None:
+ """Initialize the SDK client.
+
+ Args:
+ path: Path to MetaTrader5 terminal EXE file.
+ login: Trading account login.
+ password: Trading account password.
+ server: Trading server name.
+ timeout: Connection timeout in milliseconds.
+ retry_count: Number of MT5 initialization retries for sessions
+ opened by this client.
+ config: Optional pre-built ``Mt5Config`` (overrides other args).
+ client: Optional already-connected ``Mt5DataClient``. Injected
+ clients are reused as-is and are not initialized or shut down.
+ """
+ self._config = config or build_config(
+ path=path,
+ login=login,
+ password=password,
+ server=server,
+ timeout=timeout,
+ )
+ self._retry_count = retry_count
+ self._client = client
+ self._owns_client = client is None
|
@@ -962,39 +964,39 @@ clients are reused as-is and are not initialized or shut down.
Source code in mt5cli/sdk.py
- 473
-474
-475
-476
-477
-478
-479
-480
-481
-482
-483
-484
-485
+ | def __enter__(self) -> Self:
- """Open a persistent MT5 connection for multiple calls.
-
- Returns:
- This client instance.
- """
- if self._client is not None:
- return self
- client = Mt5DataClient(config=self._config, retry_count=self._retry_count)
- try:
- client.initialize_and_login_mt5()
- except Exception:
- client.shutdown()
- raise
- self._client = client
- self._owns_client = True # only set when this method created the client
- return self
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
| def __enter__(self) -> Self:
+ """Open a persistent MT5 connection for multiple calls.
+
+ Returns:
+ This client instance.
+ """
+ if self._client is not None:
+ return self
+ client = Mt5DataClient(config=self._config, retry_count=self._retry_count)
+ try:
+ client.initialize_and_login_mt5()
+ except Exception:
+ client.shutdown()
+ raise
+ self._client = client
+ self._owns_client = True # only set when this method created the client
+ return self
|
@@ -1023,25 +1025,25 @@ clients are reused as-is and are not initialized or shut down.
Source code in mt5cli/sdk.py
- | def __exit__(
- self,
- exc_type: type[BaseException] | None,
- exc: BaseException | None,
- tb: object,
-) -> None:
- """Shut down the persistent MT5 connection."""
- if self._client is not None and self._owns_client:
- self._client.shutdown()
- self._client = None
+ | def __exit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc: BaseException | None,
+ tb: object,
+) -> None:
+ """Shut down the persistent MT5 connection."""
+ if self._client is not None and self._owns_client:
+ self._client.shutdown()
+ self._client = None
|
@@ -1066,11 +1068,11 @@ clients are reused as-is and are not initialized or shut down.
Source code in mt5cli/sdk.py
- | def account_info(self) -> pd.DataFrame:
- """Return account information."""
- return self._fetch(lambda c: c.account_info_as_df())
+ | def account_info(self) -> pd.DataFrame:
+ """Return account information."""
+ return self._fetch(lambda c: c.account_info_as_df())
|
@@ -1147,19 +1149,7 @@ clients are reused as-is and are not initialized or shut down.
Source code in mt5cli/sdk.py
- 558
-559
-560
-561
-562
-563
-564
-565
-566
-567
-568
-569
-570
+ | def collect_latest_rates(
- self,
- symbols: Sequence[str],
- timeframes: Sequence[int | str],
- *,
- count: int,
- start_pos: int = 0,
-) -> dict[tuple[str, int], pd.DataFrame]:
- """Return latest rates for each symbol/timeframe pair.
-
- Returns:
- Mapping keyed by ``(symbol, timeframe_int)``.
-
- Raises:
- ValueError: If ``count`` is not positive or inputs are empty.
- """
- _require_positive(count, "count")
- if not symbols:
- msg = "At least one symbol is required."
- raise ValueError(msg)
- if not timeframes:
- msg = "At least one timeframe is required."
- raise ValueError(msg)
- resolved_timeframes = [_coerce_timeframe(timeframe) for timeframe in timeframes]
- return self._fetch_value(
- lambda c: {
- (symbol, timeframe): c.copy_rates_from_pos_as_df(
- symbol=symbol,
- timeframe=timeframe,
- start_pos=start_pos,
- count=count,
- )
- for symbol in symbols
- for timeframe in resolved_timeframes
- },
- )
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
| def collect_latest_rates(
+ self,
+ symbols: Sequence[str],
+ timeframes: Sequence[int | str],
+ *,
+ count: int,
+ start_pos: int = 0,
+) -> dict[tuple[str, int], pd.DataFrame]:
+ """Return latest rates for each symbol/timeframe pair.
+
+ Returns:
+ Mapping keyed by ``(symbol, timeframe_int)``.
+
+ Raises:
+ ValueError: If ``count`` is not positive or inputs are empty.
+ """
+ _require_positive(count, "count")
+ if not symbols:
+ msg = "At least one symbol is required."
+ raise ValueError(msg)
+ if not timeframes:
+ msg = "At least one timeframe is required."
+ raise ValueError(msg)
+ resolved_timeframes = [_coerce_timeframe(timeframe) for timeframe in timeframes]
+ return self._fetch_value(
+ lambda c: {
+ (symbol, timeframe): c.copy_rates_from_pos_as_df(
+ symbol=symbol,
+ timeframe=timeframe,
+ start_pos=start_pos,
+ count=count,
+ )
+ for symbol in symbols
+ for timeframe in resolved_timeframes
+ },
+ )
|
@@ -1247,41 +1249,41 @@ clients are reused as-is and are not initialized or shut down.
Source code in mt5cli/sdk.py
- 510
-511
-512
-513
-514
-515
-516
-517
-518
-519
-520
-521
-522
+ | def copy_rates_from(
- self,
- symbol: str,
- timeframe: int | str,
- date_from: datetime | str,
- count: int,
-) -> pd.DataFrame:
- """Return rates starting from a date."""
- tf = _coerce_timeframe(timeframe)
- start = _require_datetime(date_from)
- return self._fetch(
- lambda c: c.copy_rates_from_as_df(
- symbol=symbol,
- timeframe=tf,
- date_from=start,
- count=count,
- ),
- )
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
| def copy_rates_from(
+ self,
+ symbol: str,
+ timeframe: int | str,
+ date_from: datetime | str,
+ count: int,
+) -> pd.DataFrame:
+ """Return rates starting from a date."""
+ tf = _coerce_timeframe(timeframe)
+ start = _require_datetime(date_from)
+ return self._fetch(
+ lambda c: c.copy_rates_from_as_df(
+ symbol=symbol,
+ timeframe=tf,
+ date_from=start,
+ count=count,
+ ),
+ )
|
@@ -1311,39 +1313,39 @@ clients are reused as-is and are not initialized or shut down.
Source code in mt5cli/sdk.py
- 529
-530
-531
-532
-533
-534
-535
-536
-537
-538
-539
-540
-541
+ | def copy_rates_from_pos(
- self,
- symbol: str,
- timeframe: int | str,
- start_pos: int,
- count: int,
-) -> pd.DataFrame:
- """Return rates starting from a bar position."""
- tf = _coerce_timeframe(timeframe)
- return self._fetch(
- lambda c: c.copy_rates_from_pos_as_df(
- symbol=symbol,
- timeframe=tf,
- start_pos=start_pos,
- count=count,
- ),
- )
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
| def copy_rates_from_pos(
+ self,
+ symbol: str,
+ timeframe: int | str,
+ start_pos: int,
+ count: int,
+) -> pd.DataFrame:
+ """Return rates starting from a bar position."""
+ tf = _coerce_timeframe(timeframe)
+ return self._fetch(
+ lambda c: c.copy_rates_from_pos_as_df(
+ symbol=symbol,
+ timeframe=tf,
+ start_pos=start_pos,
+ count=count,
+ ),
+ )
|
@@ -1373,43 +1375,43 @@ clients are reused as-is and are not initialized or shut down.
Source code in mt5cli/sdk.py
- 595
-596
-597
-598
-599
-600
-601
-602
-603
-604
-605
-606
-607
+ | def copy_rates_range(
- self,
- symbol: str,
- timeframe: int | str,
- date_from: datetime | str,
- date_to: datetime | str,
-) -> pd.DataFrame:
- """Return rates for a date range."""
- tf = _coerce_timeframe(timeframe)
- start = _require_datetime(date_from)
- end = _require_datetime(date_to)
- return self._fetch(
- lambda c: c.copy_rates_range_as_df(
- symbol=symbol,
- timeframe=tf,
- date_from=start,
- date_to=end,
- ),
- )
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
| def copy_rates_range(
+ self,
+ symbol: str,
+ timeframe: int | str,
+ date_from: datetime | str,
+ date_to: datetime | str,
+) -> pd.DataFrame:
+ """Return rates for a date range."""
+ tf = _coerce_timeframe(timeframe)
+ start = _require_datetime(date_from)
+ end = _require_datetime(date_to)
+ return self._fetch(
+ lambda c: c.copy_rates_range_as_df(
+ symbol=symbol,
+ timeframe=tf,
+ date_from=start,
+ date_to=end,
+ ),
+ )
|
@@ -1439,41 +1441,41 @@ clients are reused as-is and are not initialized or shut down.
Source code in mt5cli/sdk.py
- 615
-616
-617
-618
-619
-620
-621
-622
-623
-624
-625
-626
-627
+ | def copy_ticks_from(
- self,
- symbol: str,
- date_from: datetime | str,
- count: int,
- flags: int | str,
-) -> pd.DataFrame:
- """Return ticks starting from a date."""
- start = _require_datetime(date_from)
- tick_flags = _coerce_tick_flags(flags)
- return self._fetch(
- lambda c: c.copy_ticks_from_as_df(
- symbol=symbol,
- date_from=start,
- count=count,
- flags=tick_flags,
- ),
- )
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
| def copy_ticks_from(
+ self,
+ symbol: str,
+ date_from: datetime | str,
+ count: int,
+ flags: int | str,
+) -> pd.DataFrame:
+ """Return ticks starting from a date."""
+ start = _require_datetime(date_from)
+ tick_flags = _coerce_tick_flags(flags)
+ return self._fetch(
+ lambda c: c.copy_ticks_from_as_df(
+ symbol=symbol,
+ date_from=start,
+ count=count,
+ flags=tick_flags,
+ ),
+ )
|
@@ -1503,43 +1505,43 @@ clients are reused as-is and are not initialized or shut down.
Source code in mt5cli/sdk.py
- 634
-635
-636
-637
-638
-639
-640
-641
-642
-643
-644
-645
-646
+ | def copy_ticks_range(
- self,
- symbol: str,
- date_from: datetime | str,
- date_to: datetime | str,
- flags: int | str,
-) -> pd.DataFrame:
- """Return ticks for a date range."""
- start = _require_datetime(date_from)
- end = _require_datetime(date_to)
- tick_flags = _coerce_tick_flags(flags)
- return self._fetch(
- lambda c: c.copy_ticks_range_as_df(
- symbol=symbol,
- date_from=start,
- date_to=end,
- flags=tick_flags,
- ),
- )
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
| def copy_ticks_range(
+ self,
+ symbol: str,
+ date_from: datetime | str,
+ date_to: datetime | str,
+ flags: int | str,
+) -> pd.DataFrame:
+ """Return ticks for a date range."""
+ start = _require_datetime(date_from)
+ end = _require_datetime(date_to)
+ tick_flags = _coerce_tick_flags(flags)
+ return self._fetch(
+ lambda c: c.copy_ticks_range_as_df(
+ symbol=symbol,
+ date_from=start,
+ date_to=end,
+ flags=tick_flags,
+ ),
+ )
|
@@ -1593,27 +1595,27 @@ injected client, including when used as a context manager.
Source code in mt5cli/sdk.py
- | @classmethod
-def from_connected_client(cls, client: Mt5DataClient) -> Self:
- """Bind to an already-connected ``Mt5DataClient`` without owning it.
-
- The returned ``Mt5CliClient`` never initializes or shuts down the
- injected client, including when used as a context manager.
-
- Returns:
- Client wrapper bound to the injected connection.
- """
- return cls(client=client)
+ | @classmethod
+def from_connected_client(cls, client: Mt5DataClient) -> Self:
+ """Bind to an already-connected ``Mt5DataClient`` without owning it.
+
+ The returned ``Mt5CliClient`` never initializes or shuts down the
+ injected client, including when used as a context manager.
+
+ Returns:
+ Client wrapper bound to the injected connection.
+ """
+ return cls(client=client)
|
@@ -1645,19 +1647,7 @@ injected client, including when used as a context manager.
Source code in mt5cli/sdk.py
- 723
-724
-725
-726
-727
-728
-729
-730
-731
-732
-733
-734
-735
+ | def history_deals(
- self,
- date_from: datetime | str | None = None,
- date_to: datetime | str | None = None,
- group: str | None = None,
- symbol: str | None = None,
- ticket: int | None = None,
- position: int | None = None,
-) -> pd.DataFrame:
- """Return historical deals."""
- start = _coerce_datetime(date_from)
- end = _coerce_datetime(date_to)
- return self._fetch(
- lambda c: c.history_deals_get_as_df(
- date_from=start,
- date_to=end,
- group=group,
- symbol=symbol,
- ticket=ticket,
- position=position,
- ),
- )
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
| def history_deals(
+ self,
+ date_from: datetime | str | None = None,
+ date_to: datetime | str | None = None,
+ group: str | None = None,
+ symbol: str | None = None,
+ ticket: int | None = None,
+ position: int | None = None,
+) -> pd.DataFrame:
+ """Return historical deals."""
+ start = _coerce_datetime(date_from)
+ end = _coerce_datetime(date_to)
+ return self._fetch(
+ lambda c: c.history_deals_get_as_df(
+ date_from=start,
+ date_to=end,
+ group=group,
+ symbol=symbol,
+ ticket=ticket,
+ position=position,
+ ),
+ )
|
@@ -1719,19 +1721,7 @@ injected client, including when used as a context manager.
Source code in mt5cli/sdk.py
- 700
-701
-702
-703
-704
-705
-706
-707
-708
-709
-710
-711
-712
+ | def history_orders(
- self,
- date_from: datetime | str | None = None,
- date_to: datetime | str | None = None,
- group: str | None = None,
- symbol: str | None = None,
- ticket: int | None = None,
- position: int | None = None,
-) -> pd.DataFrame:
- """Return historical orders."""
- start = _coerce_datetime(date_from)
- end = _coerce_datetime(date_to)
- return self._fetch(
- lambda c: c.history_orders_get_as_df(
- date_from=start,
- date_to=end,
- group=group,
- symbol=symbol,
- ticket=ticket,
- position=position,
- ),
- )
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
| def history_orders(
+ self,
+ date_from: datetime | str | None = None,
+ date_to: datetime | str | None = None,
+ group: str | None = None,
+ symbol: str | None = None,
+ ticket: int | None = None,
+ position: int | None = None,
+) -> pd.DataFrame:
+ """Return historical orders."""
+ start = _coerce_datetime(date_from)
+ end = _coerce_datetime(date_to)
+ return self._fetch(
+ lambda c: c.history_orders_get_as_df(
+ date_from=start,
+ date_to=end,
+ group=group,
+ symbol=symbol,
+ ticket=ticket,
+ position=position,
+ ),
+ )
|
@@ -1786,11 +1788,11 @@ injected client, including when used as a context manager.
Source code in mt5cli/sdk.py
- | def last_error(self) -> pd.DataFrame:
- """Return the last error information."""
- return self._fetch(lambda c: c.last_error_as_df())
+ | def last_error(self) -> pd.DataFrame:
+ """Return the last error information."""
+ return self._fetch(lambda c: c.last_error_as_df())
|
@@ -1820,25 +1822,25 @@ injected client, including when used as a context manager.
Source code in mt5cli/sdk.py
- | def latest_rates(
- self,
- symbol: str,
- timeframe: int | str,
- count: int,
- start_pos: int = 0,
-) -> pd.DataFrame:
- """Return the latest rates from a bar position."""
- _require_positive(count, "count")
- return self.copy_rates_from_pos(symbol, timeframe, start_pos, count)
+ | def latest_rates(
+ self,
+ symbol: str,
+ timeframe: int | str,
+ count: int,
+ start_pos: int = 0,
+) -> pd.DataFrame:
+ """Return the latest rates from a bar position."""
+ _require_positive(count, "count")
+ return self.copy_rates_from_pos(symbol, timeframe, start_pos, count)
|
@@ -1863,11 +1865,11 @@ injected client, including when used as a context manager.
Source code in mt5cli/sdk.py
- | def market_book(self, symbol: str) -> pd.DataFrame:
- """Return market depth for a symbol."""
- return self._fetch(lambda c: c.market_book_get_as_df(symbol=symbol))
+ | def market_book(self, symbol: str) -> pd.DataFrame:
+ """Return market depth for a symbol."""
+ return self._fetch(lambda c: c.market_book_get_as_df(symbol=symbol))
|
@@ -1956,27 +1958,27 @@ injected client, including when used as a context manager.
Source code in mt5cli/sdk.py
- | def minimum_margins(self, symbol: str) -> pd.DataFrame:
- """Return minimum-volume buy and sell margin requirements.
-
- Args:
- symbol: Symbol name.
-
- Returns:
- One-row DataFrame with columns ``symbol``, ``account_currency``,
- ``volume_min``, ``buy_margin``, and ``sell_margin``.
- """
- return self._fetch(lambda c: _fetch_minimum_margins(c, symbol))
+ | def minimum_margins(self, symbol: str) -> pd.DataFrame:
+ """Return minimum-volume buy and sell margin requirements.
+
+ Args:
+ symbol: Symbol name.
+
+ Returns:
+ One-row DataFrame with columns ``symbol``, ``account_currency``,
+ ``volume_min``, ``buy_margin``, and ``sell_margin``.
+ """
+ return self._fetch(lambda c: _fetch_minimum_margins(c, symbol))
|
@@ -2001,45 +2003,45 @@ injected client, including when used as a context manager.
Source code in mt5cli/sdk.py
- 831
-832
-833
-834
-835
-836
-837
-838
-839
-840
-841
-842
-843
+ | def mt5_summary(self) -> dict[str, object]:
- """Return a compact terminal/account status summary."""
-
- def _summary(client: Mt5DataClient) -> dict[str, object]:
- return {
- "version": _plain_mt5_value(
- _call_required_client_method(client, "version"),
- ),
- "terminal_info": _plain_mt5_value(
- _call_required_client_method(client, "terminal_info"),
- ),
- "account_info": _plain_mt5_value(
- _call_required_client_method(client, "account_info"),
- ),
- "symbols_total": _plain_mt5_value(
- _call_required_client_method(client, "symbols_total"),
- ),
- }
-
- return self._fetch_value(_summary)
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
| def mt5_summary(self) -> dict[str, object]:
+ """Return a compact terminal/account status summary."""
+
+ def _summary(client: Mt5DataClient) -> dict[str, object]:
+ return {
+ "version": _plain_mt5_value(
+ _call_required_client_method(client, "version"),
+ ),
+ "terminal_info": _plain_mt5_value(
+ _call_required_client_method(client, "terminal_info"),
+ ),
+ "account_info": _plain_mt5_value(
+ _call_required_client_method(client, "account_info"),
+ ),
+ "symbols_total": _plain_mt5_value(
+ _call_required_client_method(client, "symbols_total"),
+ ),
+ }
+
+ return self._fetch_value(_summary)
|
@@ -2064,27 +2066,27 @@ injected client, including when used as a context manager.
Source code in mt5cli/sdk.py
- | def mt5_summary_as_df(self) -> pd.DataFrame:
- """Return an export-safe one-row terminal/account summary DataFrame."""
- summary = self.mt5_summary()
- return pd.DataFrame(
- [
- {
- key: _mt5_summary_export_value(value)
- for key, value in summary.items()
- },
- ],
- )
+ | def mt5_summary_as_df(self) -> pd.DataFrame:
+ """Return an export-safe one-row terminal/account summary DataFrame."""
+ summary = self.mt5_summary()
+ return pd.DataFrame(
+ [
+ {
+ key: _mt5_summary_export_value(value)
+ for key, value in summary.items()
+ },
+ ],
+ )
|
@@ -2113,33 +2115,33 @@ injected client, including when used as a context manager.
Source code in mt5cli/sdk.py
- | def orders(
- self,
- symbol: str | None = None,
- group: str | None = None,
- ticket: int | None = None,
-) -> pd.DataFrame:
- """Return active orders."""
- return self._fetch(
- lambda c: c.orders_get_as_df(
- symbol=symbol,
- group=group,
- ticket=ticket,
- ),
- )
+ | def orders(
+ self,
+ symbol: str | None = None,
+ group: str | None = None,
+ ticket: int | None = None,
+) -> pd.DataFrame:
+ """Return active orders."""
+ return self._fetch(
+ lambda c: c.orders_get_as_df(
+ symbol=symbol,
+ group=group,
+ ticket=ticket,
+ ),
+ )
|
@@ -2168,33 +2170,33 @@ injected client, including when used as a context manager.
Source code in mt5cli/sdk.py
- | def positions(
- self,
- symbol: str | None = None,
- group: str | None = None,
- ticket: int | None = None,
-) -> pd.DataFrame:
- """Return open positions."""
- return self._fetch(
- lambda c: c.positions_get_as_df(
- symbol=symbol,
- group=group,
- ticket=ticket,
- ),
- )
+ | def positions(
+ self,
+ symbol: str | None = None,
+ group: str | None = None,
+ ticket: int | None = None,
+) -> pd.DataFrame:
+ """Return open positions."""
+ return self._fetch(
+ lambda c: c.positions_get_as_df(
+ symbol=symbol,
+ group=group,
+ ticket=ticket,
+ ),
+ )
|
@@ -2224,39 +2226,39 @@ injected client, including when used as a context manager.
Source code in mt5cli/sdk.py
- 746
-747
-748
-749
-750
-751
-752
-753
-754
-755
-756
-757
-758
+ | def recent_history_deals(
- self,
- hours: float,
- date_to: datetime | str | None = None,
- group: str | None = None,
- symbol: str | None = None,
-) -> pd.DataFrame:
- """Return historical deals from a recent trailing window."""
- _require_positive(hours, "hours")
- end = _require_datetime(date_to) if date_to is not None else datetime.now(UTC)
- start = end - timedelta(hours=hours)
- return self.history_deals(
- date_from=start,
- date_to=end,
- group=group,
- symbol=symbol,
- )
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
| def recent_history_deals(
+ self,
+ hours: float,
+ date_to: datetime | str | None = None,
+ group: str | None = None,
+ symbol: str | None = None,
+) -> pd.DataFrame:
+ """Return historical deals from a recent trailing window."""
+ _require_positive(hours, "hours")
+ end = _require_datetime(date_to) if date_to is not None else datetime.now(UTC)
+ start = end - timedelta(hours=hours)
+ return self.history_deals(
+ date_from=start,
+ date_to=end,
+ group=group,
+ symbol=symbol,
+ )
|
@@ -2420,19 +2422,7 @@ fetching the entire range.
Source code in mt5cli/sdk.py
- 780
-781
-782
-783
-784
-785
-786
-787
-788
-789
-790
-791
-792
+ | def recent_ticks(
- self,
- symbol: str,
- seconds: float,
- *,
- date_to: datetime | str | None = None,
- count: int = 10000,
- flags: int | str = "ALL",
-) -> pd.DataFrame:
- """Return ticks from a recent time window.
-
- Args:
- symbol: Symbol name.
- seconds: Lookback window in seconds ending at ``date_to``.
- date_to: Window end time. When ``None``, uses the latest
- ``symbol_info_tick().time`` rather than wall-clock now.
- count: Maximum ticks to return. Values ``<= 0`` return the full
- window without trimming. Positive values keep the most recent
- ticks; when the window is sparse, ``copy_ticks_from`` avoids
- fetching the entire range.
- flags: Tick flags as ``ALL``, ``INFO``, ``TRADE``, or an integer.
-
- Returns:
- Tick DataFrame with MT5 tick columns such as ``time``, ``bid``,
- ``ask``, ``last``, and ``volume``.
- """
- tick_flags = _coerce_tick_flags(flags)
- end = _coerce_datetime(date_to)
- return self._fetch(
- lambda c: _fetch_recent_ticks(
- c,
- symbol,
- seconds,
- end,
- count,
- tick_flags,
- ),
- )
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
| def recent_ticks(
+ self,
+ symbol: str,
+ seconds: float,
+ *,
+ date_to: datetime | str | None = None,
+ count: int = 10000,
+ flags: int | str = "ALL",
+) -> pd.DataFrame:
+ """Return ticks from a recent time window.
+
+ Args:
+ symbol: Symbol name.
+ seconds: Lookback window in seconds ending at ``date_to``.
+ date_to: Window end time. When ``None``, uses the latest
+ ``symbol_info_tick().time`` rather than wall-clock now.
+ count: Maximum ticks to return. Values ``<= 0`` return the full
+ window without trimming. Positive values keep the most recent
+ ticks; when the window is sparse, ``copy_ticks_from`` avoids
+ fetching the entire range.
+ flags: Tick flags as ``ALL``, ``INFO``, ``TRADE``, or an integer.
+
+ Returns:
+ Tick DataFrame with MT5 tick columns such as ``time``, ``bid``,
+ ``ask``, ``last``, and ``volume``.
+ """
+ tick_flags = _coerce_tick_flags(flags)
+ end = _coerce_datetime(date_to)
+ return self._fetch(
+ lambda c: _fetch_recent_ticks(
+ c,
+ symbol,
+ seconds,
+ end,
+ count,
+ tick_flags,
+ ),
+ )
|
@@ -2519,11 +2521,11 @@ fetching the entire range.
Source code in mt5cli/sdk.py
- | def symbol_info(self, symbol: str) -> pd.DataFrame:
- """Return details for one symbol."""
- return self._fetch(lambda c: c.symbol_info_as_df(symbol=symbol))
+ | def symbol_info(self, symbol: str) -> pd.DataFrame:
+ """Return details for one symbol."""
+ return self._fetch(lambda c: c.symbol_info_as_df(symbol=symbol))
|
@@ -2548,11 +2550,11 @@ fetching the entire range.
Source code in mt5cli/sdk.py
- | def symbol_info_tick(self, symbol: str) -> pd.DataFrame:
- """Return the last tick for a symbol."""
- return self._fetch(lambda c: c.symbol_info_tick_as_df(symbol=symbol))
+ | def symbol_info_tick(self, symbol: str) -> pd.DataFrame:
+ """Return the last tick for a symbol."""
+ return self._fetch(lambda c: c.symbol_info_tick_as_df(symbol=symbol))
|
@@ -2577,11 +2579,11 @@ fetching the entire range.
Source code in mt5cli/sdk.py
- | def symbols(self, group: str | None = None) -> pd.DataFrame:
- """Return the symbol list."""
- return self._fetch(lambda c: c.symbols_get_as_df(group=group))
+ | def symbols(self, group: str | None = None) -> pd.DataFrame:
+ """Return the symbol list."""
+ return self._fetch(lambda c: c.symbols_get_as_df(group=group))
|
@@ -2606,11 +2608,11 @@ fetching the entire range.
Source code in mt5cli/sdk.py
- | def terminal_info(self) -> pd.DataFrame:
- """Return terminal information."""
- return self._fetch(lambda c: c.terminal_info_as_df())
+ | def terminal_info(self) -> pd.DataFrame:
+ """Return terminal information."""
+ return self._fetch(lambda c: c.terminal_info_as_df())
|
@@ -2635,11 +2637,11 @@ fetching the entire range.
Source code in mt5cli/sdk.py
- | def version(self) -> pd.DataFrame:
- """Return MetaTrader5 version information."""
- return self._fetch(lambda c: c.version_as_df())
+ | def version(self) -> pd.DataFrame:
+ """Return MetaTrader5 version information."""
+ return self._fetch(lambda c: c.version_as_df())
|
@@ -2905,19 +2907,7 @@ when :meth:update runs. Receives the same keyword arguments as
Source code in mt5cli/sdk.py
- 1096
-1097
-1098
-1099
-1100
-1101
-1102
-1103
-1104
-1105
-1106
-1107
-1108
+ | def __init__(
- self,
- *,
- output: Path | str,
- datasets: set[Dataset] | None = None,
- timeframes: Sequence[int | str] | None = None,
- flags: int | str = "ALL",
- lookback_hours: float = 24.0,
- with_views: bool = False,
- include_account_events: bool = True,
- interval_seconds: float = 0.0,
- suppress_errors: bool = False,
- update_backend: UpdateHistoryBackend | None = None,
-) -> None:
- """Initialize the throttled updater.
-
- Args:
- output: SQLite database path.
- datasets: Datasets to include (defaults to rates, history-orders,
- history-deals; pass ``{Dataset.ticks}`` to opt in to ticks).
- timeframes: Rate timeframes to update (defaults to all fixed MT5
- timeframes).
- flags: Tick copy flags as integer or name (e.g. ``ALL``).
- lookback_hours: First-run lookback when a table has no prior rows.
- with_views: Create ``cash_events`` and ``positions_reconstructed``
- views.
- include_account_events: Include account-level cash events.
- interval_seconds: Minimum seconds between successful updates. Values
- ``<= 0`` update on every call.
- suppress_errors: When True, recoverable errors (``Mt5TradingError``,
- ``Mt5RuntimeError``, ``sqlite3.Error``, ``ValueError``,
- ``OSError``, and MT5 client capability ``AttributeError`` /
- ``TypeError`` for history API methods) raised during an update
- are swallowed and :meth:`update` returns False without advancing
- the throttle. Other ``AttributeError`` / ``TypeError`` values
- always propagate. When False (default), recoverable errors
- propagate so callers control logging.
- update_backend: Callable invoked instead of :func:`update_history`
- when :meth:`update` runs. Receives the same keyword arguments as
- :func:`update_history` (``client``, ``output``, ``symbols``,
- ``datasets``, ``timeframes``, ``flags``, ``lookback_hours``,
- ``with_views``, ``include_account_events``). Defaults to
- :func:`update_history`.
- """
- self.output = output
- self.datasets = datasets
- self.timeframes = timeframes
- self.flags = flags
- self.lookback_hours = lookback_hours
- self.with_views = with_views
- self.include_account_events = include_account_events
- self.interval_seconds = interval_seconds
- self.suppress_errors = suppress_errors
- self.update_backend = (
- update_history if update_backend is None else update_backend
- )
- self._last_update_monotonic: float | None = None
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
| def __init__(
+ self,
+ *,
+ output: Path | str,
+ datasets: set[Dataset] | None = None,
+ timeframes: Sequence[int | str] | None = None,
+ flags: int | str = "ALL",
+ lookback_hours: float = 24.0,
+ with_views: bool = False,
+ include_account_events: bool = True,
+ interval_seconds: float = 0.0,
+ suppress_errors: bool = False,
+ update_backend: UpdateHistoryBackend | None = None,
+) -> None:
+ """Initialize the throttled updater.
+
+ Args:
+ output: SQLite database path.
+ datasets: Datasets to include (defaults to rates, history-orders,
+ history-deals; pass ``{Dataset.ticks}`` to opt in to ticks).
+ timeframes: Rate timeframes to update (defaults to all fixed MT5
+ timeframes).
+ flags: Tick copy flags as integer or name (e.g. ``ALL``).
+ lookback_hours: First-run lookback when a table has no prior rows.
+ with_views: Create ``cash_events`` and ``positions_reconstructed``
+ views.
+ include_account_events: Include account-level cash events.
+ interval_seconds: Minimum seconds between successful updates. Values
+ ``<= 0`` update on every call.
+ suppress_errors: When True, recoverable errors (``Mt5TradingError``,
+ ``Mt5RuntimeError``, ``sqlite3.Error``, ``ValueError``,
+ ``OSError``, and MT5 client capability ``AttributeError`` /
+ ``TypeError`` for history API methods) raised during an update
+ are swallowed and :meth:`update` returns False without advancing
+ the throttle. Other ``AttributeError`` / ``TypeError`` values
+ always propagate. When False (default), recoverable errors
+ propagate so callers control logging.
+ update_backend: Callable invoked instead of :func:`update_history`
+ when :meth:`update` runs. Receives the same keyword arguments as
+ :func:`update_history` (``client``, ``output``, ``symbols``,
+ ``datasets``, ``timeframes``, ``flags``, ``lookback_hours``,
+ ``with_views``, ``include_account_events``). Defaults to
+ :func:`update_history`.
+ """
+ self.output = output
+ self.datasets = datasets
+ self.timeframes = timeframes
+ self.flags = flags
+ self.lookback_hours = lookback_hours
+ self.with_views = with_views
+ self.include_account_events = include_account_events
+ self.interval_seconds = interval_seconds
+ self.suppress_errors = suppress_errors
+ self.update_backend = (
+ update_history if update_backend is None else update_backend
+ )
+ self._last_update_monotonic: float | None = None
|
@@ -3343,27 +3345,27 @@ when :meth:update runs. Receives the same keyword arguments as
Source code in mt5cli/sdk.py
- | def should_update(self) -> bool:
- """Return whether enough time has elapsed to run another update.
-
- Returns:
- True when ``interval_seconds <= 0``, when no update has succeeded
- yet, or when at least ``interval_seconds`` have elapsed since the
- last successful update.
- """
- if self.interval_seconds <= 0 or self._last_update_monotonic is None:
- return True
- return (time.monotonic() - self._last_update_monotonic) >= self.interval_seconds
+ | def should_update(self) -> bool:
+ """Return whether enough time has elapsed to run another update.
+
+ Returns:
+ True when ``interval_seconds <= 0``, when no update has succeeded
+ yet, or when at least ``interval_seconds`` have elapsed since the
+ last successful update.
+ """
+ if self.interval_seconds <= 0 or self._last_update_monotonic is None:
+ return True
+ return (time.monotonic() - self._last_update_monotonic) >= self.interval_seconds
|
@@ -3525,19 +3527,7 @@ is False, or any other type error.
Source code in mt5cli/sdk.py
- 1171
-1172
-1173
-1174
-1175
-1176
-1177
-1178
-1179
-1180
-1181
-1182
-1183
+ | def update(self, client: Mt5DataClient, symbols: Sequence[str]) -> bool:
- """Run a throttled incremental history update.
-
- Args:
- client: Connected MT5 data client.
- symbols: Symbols to update.
-
- Returns:
- True if an update ran successfully, False if it was throttled or
- (when ``suppress_errors`` is True) failed with a recoverable error.
- When ``suppress_errors`` is False, recoverable update failures
- propagate to the caller.
-
- Raises:
- AttributeError: MT5 client capability mismatch when
- ``suppress_errors`` is False, or any other attribute error.
- TypeError: MT5 client capability mismatch when ``suppress_errors``
- is False, or any other type error.
- """
- if not self.should_update():
- return False
- try:
- _resolve_update_history_request(
- output=self.output,
- symbols=symbols,
- datasets=self.datasets,
- timeframes=self.timeframes,
- flags=self.flags,
- lookback_hours=self.lookback_hours,
- date_to=None,
- )
- self.update_backend(
- client=client,
- output=self.output,
- symbols=symbols,
- datasets=self.datasets,
- timeframes=self.timeframes,
- flags=self.flags,
- lookback_hours=self.lookback_hours,
- with_views=self.with_views,
- include_account_events=self.include_account_events,
- )
- except _RECOVERABLE_HISTORY_UPDATE_ERRORS:
- if self.suppress_errors:
- logger.warning("Suppressed history update error", exc_info=True)
- return False
- raise
- except (AttributeError, TypeError) as exc:
- if self.suppress_errors and _is_mt5_client_capability_error(exc):
- logger.warning("Suppressed history update error", exc_info=True)
- return False
- raise
- self._last_update_monotonic = time.monotonic()
- return True
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
| def update(self, client: Mt5DataClient, symbols: Sequence[str]) -> bool:
+ """Run a throttled incremental history update.
+
+ Args:
+ client: Connected MT5 data client.
+ symbols: Symbols to update.
+
+ Returns:
+ True if an update ran successfully, False if it was throttled or
+ (when ``suppress_errors`` is True) failed with a recoverable error.
+ When ``suppress_errors`` is False, recoverable update failures
+ propagate to the caller.
+
+ Raises:
+ AttributeError: MT5 client capability mismatch when
+ ``suppress_errors`` is False, or any other attribute error.
+ TypeError: MT5 client capability mismatch when ``suppress_errors``
+ is False, or any other type error.
+ """
+ if not self.should_update():
+ return False
+ try:
+ _resolve_update_history_request(
+ output=self.output,
+ symbols=symbols,
+ datasets=self.datasets,
+ timeframes=self.timeframes,
+ flags=self.flags,
+ lookback_hours=self.lookback_hours,
+ date_to=None,
+ )
+ self.update_backend(
+ client=client,
+ output=self.output,
+ symbols=symbols,
+ datasets=self.datasets,
+ timeframes=self.timeframes,
+ flags=self.flags,
+ lookback_hours=self.lookback_hours,
+ with_views=self.with_views,
+ include_account_events=self.include_account_events,
+ )
+ except _RECOVERABLE_HISTORY_UPDATE_ERRORS:
+ if self.suppress_errors:
+ logger.warning("Suppressed history update error", exc_info=True)
+ return False
+ raise
+ except (AttributeError, TypeError) as exc:
+ if self.suppress_errors and _is_mt5_client_capability_error(exc):
+ logger.warning("Suppressed history update error", exc_info=True)
+ return False
+ raise
+ self._last_update_monotonic = time.monotonic()
+ return True
|
@@ -3667,11 +3669,11 @@ is False, or any other type error.
Source code in mt5cli/sdk.py
- | def account_info(*, config: Mt5Config | None = None) -> pd.DataFrame:
- """Return account information."""
- return _make_client(config=config).account_info()
+ | def account_info(*, config: Mt5Config | None = None) -> pd.DataFrame:
+ """Return account information."""
+ return _make_client(config=config).account_info()
|
@@ -3846,19 +3848,7 @@ to path, login, password, and serve
Source code in mt5cli/sdk.py
- 311
-312
-313
-314
-315
-316
-317
-318
-319
-320
-321
-322
-323
+ | def build_config(
- *,
- path: str | None = None,
- login: int | str | None = None,
- password: str | None = None,
- server: str | None = None,
- timeout: int | None = None,
- allow_whole_dollar_env: bool = False,
-) -> Mt5Config:
- """Build an ``Mt5Config`` from optional connection parameters.
-
- Args:
- path: Optional terminal executable path.
- login: Optional trading account login. Integers are preserved. String
- values are coerced: empty or whitespace-only strings become
- ``None``; numeric strings such as ``"12345"`` are converted to
- ``int``; non-numeric strings raise ``ValueError``. When
- ``allow_whole_dollar_env=True``, ``$ENV_NAME`` and
- ``${ENV_NAME}`` placeholders are expanded before coercion.
- password: Optional trading account password.
- server: Optional trading server name.
- timeout: Optional connection timeout in milliseconds.
- allow_whole_dollar_env: When ``True``, string parameters that are
- exactly ``$ENV_NAME`` are expanded from the environment. Applies
- to ``path``, ``login``, ``password``, and ``server``. Default
- ``False`` preserves existing behavior.
-
- Returns:
- Configured ``Mt5Config`` instance.
- """
- if allow_whole_dollar_env:
- if path is not None:
- path = substitute_env_placeholders(path, allow_whole_dollar_env=True)
- if isinstance(login, str):
- login = substitute_env_placeholders(login, allow_whole_dollar_env=True)
- if password is not None:
- password = substitute_env_placeholders(
- password, allow_whole_dollar_env=True
- )
- if server is not None:
- server = substitute_env_placeholders(server, allow_whole_dollar_env=True)
- return Mt5Config(
- path=path,
- login=_coerce_login(login),
- password=password,
- server=server,
- timeout=timeout,
- )
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
| def build_config(
+ *,
+ path: str | None = None,
+ login: int | str | None = None,
+ password: str | None = None,
+ server: str | None = None,
+ timeout: int | None = None,
+ allow_whole_dollar_env: bool = False,
+) -> Mt5Config:
+ """Build an ``Mt5Config`` from optional connection parameters.
+
+ Args:
+ path: Optional terminal executable path.
+ login: Optional trading account login. Integers are preserved. String
+ values are coerced: empty or whitespace-only strings become
+ ``None``; numeric strings such as ``"12345"`` are converted to
+ ``int``; non-numeric strings raise ``ValueError``. When
+ ``allow_whole_dollar_env=True``, ``$ENV_NAME`` and
+ ``${ENV_NAME}`` placeholders are expanded before coercion.
+ password: Optional trading account password.
+ server: Optional trading server name.
+ timeout: Optional connection timeout in milliseconds.
+ allow_whole_dollar_env: When ``True``, string parameters that are
+ exactly ``$ENV_NAME`` are expanded from the environment. Applies
+ to ``path``, ``login``, ``password``, and ``server``. Default
+ ``False`` preserves existing behavior.
+
+ Returns:
+ Configured ``Mt5Config`` instance.
+ """
+ if allow_whole_dollar_env:
+ if path is not None:
+ path = substitute_env_placeholders(path, allow_whole_dollar_env=True)
+ if isinstance(login, str):
+ login = substitute_env_placeholders(login, allow_whole_dollar_env=True)
+ if password is not None:
+ password = substitute_env_placeholders(
+ password, allow_whole_dollar_env=True
+ )
+ if server is not None:
+ server = substitute_env_placeholders(server, allow_whole_dollar_env=True)
+ return Mt5Config(
+ path=path,
+ login=_coerce_login(login),
+ password=password,
+ server=server,
+ timeout=timeout,
+ )
|
@@ -4165,19 +4167,7 @@ history-deals; pass {Dataset.ticks} to opt in to ticks).
Source code in mt5cli/sdk.py
- 1227
-1228
-1229
-1230
-1231
-1232
-1233
-1234
-1235
-1236
-1237
-1238
-1239
+ | def collect_history(
- output: Path,
- symbols: list[str],
- date_from: datetime | str,
- date_to: datetime | str,
- *,
- datasets: set[Dataset] | None = None,
- timeframe: int | str = 1,
- flags: int | str = "ALL",
- if_exists: IfExists = IfExists.FAIL,
- with_views: bool = False,
- config: Mt5Config | None = None,
-) -> None:
- """Collect historical datasets into a single SQLite database.
-
- Args:
- output: SQLite database path.
- symbols: Symbols to collect.
- date_from: Start date.
- date_to: End date.
- datasets: Datasets to include (defaults to rates, history-orders,
- history-deals; pass ``{Dataset.ticks}`` to opt in to ticks).
- timeframe: Rates timeframe as integer or name (e.g. ``M1``).
- flags: Tick copy flags as integer or name (e.g. ``ALL``).
- if_exists: Behavior when a target table already exists.
- with_views: Create ``cash_events`` and ``positions_reconstructed`` views.
- config: MT5 connection configuration.
- """
- start = _require_datetime(date_from)
- end = _require_datetime(date_to)
- selected = resolve_history_datasets(datasets)
- tf = _coerce_timeframe(timeframe)
- tick_flags = _coerce_tick_flags(flags)
- mt5_config = config or build_config()
- with connected_client(mt5_config) as client, sqlite3.connect(output) as conn:
- conn.execute("PRAGMA journal_mode=WAL")
- conn.execute("PRAGMA synchronous=NORMAL")
- written_tables, written_columns = write_collected_datasets(
- conn,
- client,
- symbols,
- selected,
- tf,
- tick_flags,
- start,
- end,
- if_exists,
- )
- create_history_indexes(conn, written_columns)
- if with_views and Dataset.history_deals in written_tables:
- create_cash_events_view(conn, written_columns[Dataset.history_deals])
- create_positions_reconstructed_view(
- conn,
- written_columns[Dataset.history_deals],
- )
- elif with_views:
- logger.warning(
- "--with-views ignored: history_deals table was not written",
- )
- logger.info(
- "Collected %s for %d symbol(s) into %s",
- ", ".join(sorted(ds.value for ds in selected)),
- len(symbols),
- output,
- )
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
| def collect_history(
+ output: Path,
+ symbols: list[str],
+ date_from: datetime | str,
+ date_to: datetime | str,
+ *,
+ datasets: set[Dataset] | None = None,
+ timeframe: int | str = 1,
+ flags: int | str = "ALL",
+ if_exists: IfExists = IfExists.FAIL,
+ with_views: bool = False,
+ config: Mt5Config | None = None,
+) -> None:
+ """Collect historical datasets into a single SQLite database.
+
+ Args:
+ output: SQLite database path.
+ symbols: Symbols to collect.
+ date_from: Start date.
+ date_to: End date.
+ datasets: Datasets to include (defaults to rates, history-orders,
+ history-deals; pass ``{Dataset.ticks}`` to opt in to ticks).
+ timeframe: Rates timeframe as integer or name (e.g. ``M1``).
+ flags: Tick copy flags as integer or name (e.g. ``ALL``).
+ if_exists: Behavior when a target table already exists.
+ with_views: Create ``cash_events`` and ``positions_reconstructed`` views.
+ config: MT5 connection configuration.
+ """
+ start = _require_datetime(date_from)
+ end = _require_datetime(date_to)
+ selected = resolve_history_datasets(datasets)
+ tf = _coerce_timeframe(timeframe)
+ tick_flags = _coerce_tick_flags(flags)
+ mt5_config = config or build_config()
+ with (
+ connected_client(mt5_config) as client,
+ closing(sqlite3.connect(output)) as conn,
+ conn,
+ ):
+ conn.execute("PRAGMA journal_mode=WAL")
+ conn.execute("PRAGMA synchronous=NORMAL")
+ written_tables, written_columns = write_collected_datasets(
+ conn,
+ client,
+ symbols,
+ selected,
+ tf,
+ tick_flags,
+ start,
+ end,
+ if_exists,
+ )
+ create_history_indexes(conn, written_columns)
+ if with_views and Dataset.history_deals in written_tables:
+ create_cash_events_view(conn, written_columns[Dataset.history_deals])
+ create_positions_reconstructed_view(
+ conn,
+ written_columns[Dataset.history_deals],
+ )
+ elif with_views:
+ logger.warning(
+ "--with-views ignored: history_deals table was not written",
+ )
+ logger.info(
+ "Collected %s for %d symbol(s) into %s",
+ ", ".join(sorted(ds.value for ds in selected)),
+ len(symbols),
+ output,
+ )
|
@@ -4502,23 +4512,7 @@ disables retries.
Source code in mt5cli/sdk.py
- 1867
-1868
-1869
-1870
-1871
-1872
-1873
-1874
-1875
-1876
-1877
-1878
-1879
-1880
-1881
-1882
-1883
+ | def collect_latest_closed_rates_by_granularity(
- accounts: Sequence[AccountSpec],
- granularities: Sequence[int | str],
- count: int,
- *,
- start_pos: int = 0,
- base_config: Mt5Config | None = None,
- retry_count: int = 0,
- backoff_base: float = 2.0,
-) -> dict[tuple[str, str], pd.DataFrame]:
- """Collect latest closed rate bars keyed by symbol and granularity name.
-
- Thin wrapper around :func:`collect_latest_closed_rates_for_accounts` that
- rekeys the result by granularity name (for example ``M1``) instead of the
- integer timeframe.
-
- Args:
- accounts: Account groups to read. Each must define at least one symbol.
- granularities: MT5 timeframes as integers or names (for example ``M1``).
- count: Number of closed bars to return per symbol/timeframe.
- start_pos: Initial bar position offset passed to the underlying collector.
- base_config: Optional base configuration whose fields fill any value not
- set on an individual account.
- retry_count: Maximum number of retries after the first attempt. ``0``
- disables retries.
- backoff_base: Base for exponential backoff between retry attempts.
-
- Returns:
- Mapping keyed by ``(symbol, granularity_name)``. Propagates
- ``ValueError`` from :func:`collect_latest_closed_rates_for_accounts`.
- """
- loaded = collect_latest_closed_rates_for_accounts(
- accounts,
- granularities,
- count,
- start_pos=start_pos,
- base_config=base_config,
- retry_count=retry_count,
- backoff_base=backoff_base,
- )
- return {
- (symbol, resolve_granularity_name(timeframe)): frame
- for (symbol, timeframe), frame in loaded.items()
- }
+1910
+1911
+1912
+1913
+1914
+1915
+1916
+1917
+1918
+1919
+1920
+1921
+1922
+1923
+1924
+1925
+1926
| def collect_latest_closed_rates_by_granularity(
+ accounts: Sequence[AccountSpec],
+ granularities: Sequence[int | str],
+ count: int,
+ *,
+ start_pos: int = 0,
+ base_config: Mt5Config | None = None,
+ retry_count: int = 0,
+ backoff_base: float = 2.0,
+) -> dict[tuple[str, str], pd.DataFrame]:
+ """Collect latest closed rate bars keyed by symbol and granularity name.
+
+ Thin wrapper around :func:`collect_latest_closed_rates_for_accounts` that
+ rekeys the result by granularity name (for example ``M1``) instead of the
+ integer timeframe.
+
+ Args:
+ accounts: Account groups to read. Each must define at least one symbol.
+ granularities: MT5 timeframes as integers or names (for example ``M1``).
+ count: Number of closed bars to return per symbol/timeframe.
+ start_pos: Initial bar position offset passed to the underlying collector.
+ base_config: Optional base configuration whose fields fill any value not
+ set on an individual account.
+ retry_count: Maximum number of retries after the first attempt. ``0``
+ disables retries.
+ backoff_base: Base for exponential backoff between retry attempts.
+
+ Returns:
+ Mapping keyed by ``(symbol, granularity_name)``. Propagates
+ ``ValueError`` from :func:`collect_latest_closed_rates_for_accounts`.
+ """
+ loaded = collect_latest_closed_rates_for_accounts(
+ accounts,
+ granularities,
+ count,
+ start_pos=start_pos,
+ base_config=base_config,
+ retry_count=retry_count,
+ backoff_base=backoff_base,
+ )
+ return {
+ (symbol, resolve_granularity_name(timeframe)): frame
+ for (symbol, timeframe), frame in loaded.items()
+ }
|
@@ -4816,23 +4826,7 @@ dropping the still-forming bar when start_pos is 0).
Source code in mt5cli/sdk.py
- 1804
-1805
-1806
-1807
-1808
-1809
-1810
-1811
-1812
-1813
-1814
-1815
-1816
-1817
-1818
-1819
-1820
+ | def collect_latest_closed_rates_for_accounts(
- accounts: Sequence[AccountSpec],
- timeframes: Sequence[int | str],
- count: int,
- *,
- start_pos: int = 0,
- base_config: Mt5Config | None = None,
- retry_count: int = 0,
- backoff_base: float = 2.0,
-) -> dict[tuple[str, int], pd.DataFrame]:
- """Collect latest closed rate bars across multiple MT5 account groups.
-
- When ``start_pos`` is ``0`` (the default), MetaTrader 5 includes the
- still-forming current bar as the last row. This helper fetches
- ``count + 1`` bars, drops that bar with :func:`drop_forming_rate_bar`, and
- validates that each resulting frame is non-empty. When ``start_pos`` is
- greater than zero the forming bar is not in range, so only ``count`` bars
- are fetched and no row is dropped.
-
- Wraps :func:`collect_latest_rates_for_accounts_with_retries` for transient
- MT5 error handling.
-
- Args:
- accounts: Account groups to read. Each must define at least one symbol.
- timeframes: MT5 timeframes as integers or names (for example ``M1``).
- count: Number of closed bars to return per symbol/timeframe.
- start_pos: Initial bar position offset passed to the underlying collector.
- base_config: Optional base configuration whose fields fill any value not
- set on an individual account.
- retry_count: Maximum number of retries after the first attempt. ``0``
- disables retries.
- backoff_base: Base for exponential backoff between retry attempts.
-
- Returns:
- Mapping keyed by ``(symbol, timeframe_int)``.
-
- Raises:
- ValueError: If inputs are invalid, or any series is empty (after
- dropping the still-forming bar when ``start_pos`` is ``0``).
- """
- _require_positive(count, "count")
- _require_non_negative(start_pos, "start_pos")
- fetch_count = count + 1 if start_pos == 0 else count
- loaded = collect_latest_rates_for_accounts_with_retries(
- accounts,
- timeframes,
- fetch_count,
- start_pos=start_pos,
- base_config=base_config,
- retry_count=retry_count,
- backoff_base=backoff_base,
- )
- result: dict[tuple[str, int], pd.DataFrame] = {}
- for key, df_rate in loaded.items():
- closed = drop_forming_rate_bar(df_rate) if start_pos == 0 else df_rate
- if closed.empty:
- symbol, timeframe = key
- msg = f"Rate data is empty for {symbol!r} at timeframe {timeframe}."
- raise ValueError(msg)
- result[key] = closed
- return result
+1864
+1865
+1866
+1867
+1868
+1869
+1870
+1871
+1872
+1873
+1874
+1875
+1876
+1877
+1878
+1879
+1880
| def collect_latest_closed_rates_for_accounts(
+ accounts: Sequence[AccountSpec],
+ timeframes: Sequence[int | str],
+ count: int,
+ *,
+ start_pos: int = 0,
+ base_config: Mt5Config | None = None,
+ retry_count: int = 0,
+ backoff_base: float = 2.0,
+) -> dict[tuple[str, int], pd.DataFrame]:
+ """Collect latest closed rate bars across multiple MT5 account groups.
+
+ When ``start_pos`` is ``0`` (the default), MetaTrader 5 includes the
+ still-forming current bar as the last row. This helper fetches
+ ``count + 1`` bars, drops that bar with :func:`drop_forming_rate_bar`, and
+ validates that each resulting frame is non-empty. When ``start_pos`` is
+ greater than zero the forming bar is not in range, so only ``count`` bars
+ are fetched and no row is dropped.
+
+ Wraps :func:`collect_latest_rates_for_accounts_with_retries` for transient
+ MT5 error handling.
+
+ Args:
+ accounts: Account groups to read. Each must define at least one symbol.
+ timeframes: MT5 timeframes as integers or names (for example ``M1``).
+ count: Number of closed bars to return per symbol/timeframe.
+ start_pos: Initial bar position offset passed to the underlying collector.
+ base_config: Optional base configuration whose fields fill any value not
+ set on an individual account.
+ retry_count: Maximum number of retries after the first attempt. ``0``
+ disables retries.
+ backoff_base: Base for exponential backoff between retry attempts.
+
+ Returns:
+ Mapping keyed by ``(symbol, timeframe_int)``.
+
+ Raises:
+ ValueError: If inputs are invalid, or any series is empty (after
+ dropping the still-forming bar when ``start_pos`` is ``0``).
+ """
+ _require_positive(count, "count")
+ _require_non_negative(start_pos, "start_pos")
+ fetch_count = count + 1 if start_pos == 0 else count
+ loaded = collect_latest_rates_for_accounts_with_retries(
+ accounts,
+ timeframes,
+ fetch_count,
+ start_pos=start_pos,
+ base_config=base_config,
+ retry_count=retry_count,
+ backoff_base=backoff_base,
+ )
+ result: dict[tuple[str, int], pd.DataFrame] = {}
+ for key, df_rate in loaded.items():
+ closed = drop_forming_rate_bar(df_rate) if start_pos == 0 else df_rate
+ if closed.empty:
+ symbol, timeframe = key
+ msg = f"Rate data is empty for {symbol!r} at timeframe {timeframe}."
+ raise ValueError(msg)
+ result[key] = closed
+ return result
|
@@ -4968,35 +4978,35 @@ dropping the still-forming bar when start_pos is 0).
Source code in mt5cli/sdk.py
- | def collect_latest_rates(
- symbols: Sequence[str],
- timeframes: Sequence[int | str],
- *,
- count: int,
- start_pos: int = 0,
- config: Mt5Config | None = None,
-) -> dict[tuple[str, int], pd.DataFrame]:
- """Return latest rates for each symbol/timeframe pair."""
- return _make_client(config=config).collect_latest_rates(
- symbols,
- timeframes,
- count=count,
- start_pos=start_pos,
- )
+ | def collect_latest_rates(
+ symbols: Sequence[str],
+ timeframes: Sequence[int | str],
+ *,
+ count: int,
+ start_pos: int = 0,
+ config: Mt5Config | None = None,
+) -> dict[tuple[str, int], pd.DataFrame]:
+ """Return latest rates for each symbol/timeframe pair."""
+ return _make_client(config=config).collect_latest_rates(
+ symbols,
+ timeframes,
+ count=count,
+ start_pos=start_pos,
+ )
|
@@ -5193,23 +5203,7 @@ empty, or count is not positive.
Source code in mt5cli/sdk.py
- 1696
-1697
-1698
-1699
-1700
-1701
-1702
-1703
-1704
-1705
-1706
-1707
-1708
-1709
-1710
-1711
-1712
+ | def collect_latest_rates_for_accounts(
- accounts: Sequence[AccountSpec],
- timeframes: Sequence[int | str],
- count: int,
- *,
- start_pos: int = 0,
- base_config: Mt5Config | None = None,
-) -> dict[tuple[str, int], pd.DataFrame]:
- """Collect latest rates across multiple MT5 account groups.
-
- Each account is connected in turn, its symbols are read for every
- timeframe, and the resulting frames are merged into a single mapping.
-
- Args:
- accounts: Account groups to read. Each must define at least one symbol.
- timeframes: MT5 timeframes as integers or names (for example ``M1``).
- count: Number of most recent bars to read per symbol/timeframe.
- start_pos: Initial bar position offset.
- base_config: Optional base configuration whose fields fill any value not
- set on an individual account.
-
- Returns:
- Mapping keyed by ``(symbol, timeframe_int)``. When accounts share a
- symbol/timeframe pair, the last account processed wins.
-
- Raises:
- ValueError: If ``accounts``, ``timeframes``, or any account's symbols are
- empty, or ``count`` is not positive.
- """
- account_list = list(accounts)
- if not account_list:
- msg = "At least one account is required."
- raise ValueError(msg)
- if not timeframes:
- msg = "At least one timeframe is required."
- raise ValueError(msg)
- if any(not account.symbols for account in account_list):
- msg = "Each account requires at least one symbol."
- raise ValueError(msg)
- _require_positive(count, "count")
- result: dict[tuple[str, int], pd.DataFrame] = {}
- for account in account_list:
- config = _build_account_config(account, base_config)
- with Mt5CliClient(config=config) as client:
- result.update(
- client.collect_latest_rates(
- account.symbols,
- timeframes,
- count=count,
- start_pos=start_pos,
- ),
- )
- return result
+1748
+1749
+1750
+1751
+1752
+1753
+1754
+1755
+1756
+1757
+1758
+1759
+1760
+1761
+1762
+1763
+1764
| def collect_latest_rates_for_accounts(
+ accounts: Sequence[AccountSpec],
+ timeframes: Sequence[int | str],
+ count: int,
+ *,
+ start_pos: int = 0,
+ base_config: Mt5Config | None = None,
+) -> dict[tuple[str, int], pd.DataFrame]:
+ """Collect latest rates across multiple MT5 account groups.
+
+ Each account is connected in turn, its symbols are read for every
+ timeframe, and the resulting frames are merged into a single mapping.
+
+ Args:
+ accounts: Account groups to read. Each must define at least one symbol.
+ timeframes: MT5 timeframes as integers or names (for example ``M1``).
+ count: Number of most recent bars to read per symbol/timeframe.
+ start_pos: Initial bar position offset.
+ base_config: Optional base configuration whose fields fill any value not
+ set on an individual account.
+
+ Returns:
+ Mapping keyed by ``(symbol, timeframe_int)``. When accounts share a
+ symbol/timeframe pair, the last account processed wins.
+
+ Raises:
+ ValueError: If ``accounts``, ``timeframes``, or any account's symbols are
+ empty, or ``count`` is not positive.
+ """
+ account_list = list(accounts)
+ if not account_list:
+ msg = "At least one account is required."
+ raise ValueError(msg)
+ if not timeframes:
+ msg = "At least one timeframe is required."
+ raise ValueError(msg)
+ if any(not account.symbols for account in account_list):
+ msg = "Each account requires at least one symbol."
+ raise ValueError(msg)
+ _require_positive(count, "count")
+ result: dict[tuple[str, int], pd.DataFrame] = {}
+ for account in account_list:
+ config = _build_account_config(account, base_config)
+ with Mt5CliClient(config=config) as client:
+ result.update(
+ client.collect_latest_rates(
+ account.symbols,
+ timeframes,
+ count=count,
+ start_pos=start_pos,
+ ),
+ )
+ return result
|
@@ -5528,23 +5538,7 @@ attempt n (1-indexed) is backoff_base ** n seconds.
Source code in mt5cli/sdk.py
- 1751
-1752
-1753
-1754
-1755
-1756
-1757
-1758
-1759
-1760
-1761
-1762
-1763
-1764
-1765
-1766
-1767
+ | def collect_latest_rates_for_accounts_with_retries(
- accounts: Sequence[AccountSpec],
- timeframes: Sequence[int | str],
- count: int,
- *,
- start_pos: int = 0,
- base_config: Mt5Config | None = None,
- retry_count: int = 0,
- backoff_base: float = 2.0,
-) -> dict[tuple[str, int], pd.DataFrame]:
- """Collect latest rates across accounts, retrying transient MT5 failures.
-
- Wraps :func:`collect_latest_rates_for_accounts` with bounded exponential
- backoff. Only ``pdmt5.Mt5TradingError`` and ``pdmt5.Mt5RuntimeError`` are
- retried; other exceptions propagate immediately. The final failure is
- re-raised once retries are exhausted.
-
- Args:
- accounts: Account groups to read. Each must define at least one symbol.
- timeframes: MT5 timeframes as integers or names (for example ``M1``).
- count: Number of most recent bars to read per symbol/timeframe.
- start_pos: Initial bar position offset.
- base_config: Optional base configuration whose fields fill any value not
- set on an individual account.
- retry_count: Maximum number of retries after the first attempt. ``0``
- disables retries.
- backoff_base: Base for exponential backoff. The delay before retry
- attempt ``n`` (1-indexed) is ``backoff_base ** n`` seconds.
-
- Returns:
- Mapping keyed by ``(symbol, timeframe_int)``. Propagates ``ValueError``
- for invalid inputs (see :func:`collect_latest_rates_for_accounts`) and
- re-raises the last ``pdmt5.Mt5TradingError`` or ``pdmt5.Mt5RuntimeError``
- once retries are exhausted.
- """
-
- def _collect() -> dict[tuple[str, int], pd.DataFrame]:
- return collect_latest_rates_for_accounts(
- accounts,
- timeframes,
- count,
- start_pos=start_pos,
- base_config=base_config,
- )
+1801
+1802
+1803
+1804
+1805
+1806
+1807
+1808
+1809
+1810
+1811
+1812
+1813
+1814
+1815
+1816
+1817
| def collect_latest_rates_for_accounts_with_retries(
+ accounts: Sequence[AccountSpec],
+ timeframes: Sequence[int | str],
+ count: int,
+ *,
+ start_pos: int = 0,
+ base_config: Mt5Config | None = None,
+ retry_count: int = 0,
+ backoff_base: float = 2.0,
+) -> dict[tuple[str, int], pd.DataFrame]:
+ """Collect latest rates across accounts, retrying transient MT5 failures.
+
+ Wraps :func:`collect_latest_rates_for_accounts` with bounded exponential
+ backoff. Only ``pdmt5.Mt5TradingError`` and ``pdmt5.Mt5RuntimeError`` are
+ retried; other exceptions propagate immediately. The final failure is
+ re-raised once retries are exhausted.
+
+ Args:
+ accounts: Account groups to read. Each must define at least one symbol.
+ timeframes: MT5 timeframes as integers or names (for example ``M1``).
+ count: Number of most recent bars to read per symbol/timeframe.
+ start_pos: Initial bar position offset.
+ base_config: Optional base configuration whose fields fill any value not
+ set on an individual account.
+ retry_count: Maximum number of retries after the first attempt. ``0``
+ disables retries.
+ backoff_base: Base for exponential backoff. The delay before retry
+ attempt ``n`` (1-indexed) is ``backoff_base ** n`` seconds.
- return retry_with_backoff(
- _collect,
- retry_count=retry_count,
- backoff_base=backoff_base,
- operation="Rate collection",
- )
+ Returns:
+ Mapping keyed by ``(symbol, timeframe_int)``. Propagates ``ValueError``
+ for invalid inputs (see :func:`collect_latest_rates_for_accounts`) and
+ re-raises the last ``pdmt5.Mt5TradingError`` or ``pdmt5.Mt5RuntimeError``
+ once retries are exhausted.
+ """
+
+ def _collect() -> dict[tuple[str, int], pd.DataFrame]:
+ return collect_latest_rates_for_accounts(
+ accounts,
+ timeframes,
+ count,
+ start_pos=start_pos,
+ base_config=base_config,
+ )
+
+ return retry_with_backoff(
+ _collect,
+ retry_count=retry_count,
+ backoff_base=backoff_base,
+ operation="Rate collection",
+ )
|
@@ -5709,37 +5719,37 @@ attempt n (1-indexed) is backoff_base ** n seconds.
Source code in mt5cli/sdk.py
- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|