SDK Module

mt5cli.sdk

Programmatic SDK for MetaTrader 5 data collection.

T module-attribute

T = TypeVar('T')

__all__ module-attribute

__all__ = [
    "AccountSpec",
    "Mt5CliClient",
    "account_info",
    "build_config",
    "collect_history",
    "collect_latest_rates",
    "collect_latest_rates_for_accounts",
    "copy_rates_from",
    "copy_rates_from_pos",
    "copy_rates_range",
    "copy_ticks_from",
    "copy_ticks_range",
    "history_deals",
    "history_orders",
    "last_error",
    "latest_rates",
    "market_book",
    "minimum_margins",
    "mt5_session",
    "mt5_summary",
    "mt5_summary_as_df",
    "orders",
    "positions",
    "recent_history_deals",
    "recent_ticks",
    "symbol_info",
    "symbol_info_tick",
    "symbols",
    "terminal_info",
    "update_history",
    "update_history_with_config",
    "version",
]

logger module-attribute

logger = getLogger(__name__)

AccountSpec dataclass

AccountSpec(
    symbols: Sequence[str],
    login: int | str | None = None,
    password: str | None = None,
    server: str | None = None,
    path: str | None = None,
    timeout: int | None = None,
)

Connection parameters and symbols for one MT5 account group.

Attributes:

Name Type Description
symbols Sequence[str]

Symbols to load latest rates for under this account.

login int | str | None

Trading account login. String values are coerced to int when non-empty.

password str | None

Trading account password.

server str | None

Trading server name.

path str | None

Path to the MetaTrader5 terminal EXE file.

timeout int | None

Connection timeout in milliseconds.

login class-attribute instance-attribute

login: int | str | None = None

password class-attribute instance-attribute

password: str | None = field(default=None, repr=False)

path class-attribute instance-attribute

path: str | None = None

server class-attribute instance-attribute

server: str | None = None

symbols instance-attribute

symbols: Sequence[str]

timeout class-attribute instance-attribute

timeout: int | None = None

Mt5CliClient

Mt5CliClient(
    *,
    path: str | None = None,
    login: int | None = None,
    password: str | None = None,
    server: str | None = None,
    timeout: int | None = None,
    config: Mt5Config | None = None,
    client: Mt5DataClient | None = None,
)

Programmatic client for read-only MetaTrader 5 data access.

Initialize the SDK client.

Parameters:

Name Type Description Default
path str | None

Path to MetaTrader5 terminal EXE file.

None
login int | None

Trading account login.

None
password str | None

Trading account password.

None
server str | None

Trading server name.

None
timeout int | None

Connection timeout in milliseconds.

None
config Mt5Config | None

Optional pre-built Mt5Config (overrides other args).

None
client Mt5DataClient | None

Optional already-connected Mt5DataClient. Injected clients are reused as-is and are not initialized or shut down.

None
Source code in mt5cli/sdk.py
def __init__(
    self,
    *,
    path: str | None = None,
    login: int | None = None,
    password: str | None = None,
    server: str | None = None,
    timeout: int | None = None,
    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.
        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._client = client
    self._owns_client = client is None

config property

config: Mt5Config

Return the underlying MT5 configuration.

__enter__

__enter__() -> Self

Open a persistent MT5 connection for multiple calls.

Returns:

Type Description
Self

This client instance.

Source code in mt5cli/sdk.py
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)
    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

__exit__

__exit__(
    exc_type: type[BaseException] | None,
    exc: BaseException | None,
    tb: object,
) -> None

Shut down the persistent MT5 connection.

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

account_info

account_info() -> DataFrame

Return account information.

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())

collect_latest_rates

collect_latest_rates(
    symbols: Sequence[str],
    timeframes: Sequence[int | str],
    *,
    count: int,
    start_pos: int = 0,
) -> dict[tuple[str, int], DataFrame]

Return latest rates for each symbol/timeframe pair.

Returns:

Type Description
dict[tuple[str, int], DataFrame]

Mapping keyed by (symbol, timeframe_int).

Raises:

Type Description
ValueError

If count is not positive or inputs are empty.

Source code in mt5cli/sdk.py
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
        },
    )

copy_rates_from

copy_rates_from(
    symbol: str,
    timeframe: int | str,
    date_from: datetime | str,
    count: int,
) -> DataFrame

Return rates starting from a date.

Source code in mt5cli/sdk.py
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,
        ),
    )

copy_rates_from_pos

copy_rates_from_pos(
    symbol: str,
    timeframe: int | str,
    start_pos: int,
    count: int,
) -> DataFrame

Return rates starting from a bar position.

Source code in mt5cli/sdk.py
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,
        ),
    )

copy_rates_range

copy_rates_range(
    symbol: str,
    timeframe: int | str,
    date_from: datetime | str,
    date_to: datetime | str,
) -> DataFrame

Return rates for a date range.

Source code in mt5cli/sdk.py
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,
        ),
    )

copy_ticks_from

copy_ticks_from(
    symbol: str,
    date_from: datetime | str,
    count: int,
    flags: int | str,
) -> DataFrame

Return ticks starting from a date.

Source code in mt5cli/sdk.py
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,
        ),
    )

copy_ticks_range

copy_ticks_range(
    symbol: str,
    date_from: datetime | str,
    date_to: datetime | str,
    flags: int | str,
) -> DataFrame

Return ticks for a date range.

Source code in mt5cli/sdk.py
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,
        ),
    )

from_connected_client classmethod

from_connected_client(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:

Type Description
Self

Client wrapper bound to the injected connection.

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)

history_deals

history_deals(
    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,
) -> DataFrame

Return historical deals.

Source code in mt5cli/sdk.py
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,
        ),
    )

history_orders

history_orders(
    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,
) -> DataFrame

Return historical orders.

Source code in mt5cli/sdk.py
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,
        ),
    )

last_error

last_error() -> DataFrame

Return the last error information.

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())

latest_rates

latest_rates(
    symbol: str,
    timeframe: int | str,
    count: int,
    start_pos: int = 0,
) -> DataFrame

Return the latest rates from a bar position.

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)

market_book

market_book(symbol: str) -> DataFrame

Return market depth for a symbol.

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))

minimum_margins

minimum_margins(symbol: str) -> DataFrame

Return minimum-volume buy and sell margin requirements.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required

Returns:

Type Description
DataFrame

One-row DataFrame with columns symbol, account_currency,

DataFrame

volume_min, buy_margin, and sell_margin.

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))

mt5_summary

mt5_summary() -> dict[str, object]

Return a compact terminal/account status summary.

Source code in mt5cli/sdk.py
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)

mt5_summary_as_df

mt5_summary_as_df() -> DataFrame

Return an export-safe one-row terminal/account summary DataFrame.

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()
            },
        ],
    )

orders

orders(
    symbol: str | None = None,
    group: str | None = None,
    ticket: int | None = None,
) -> DataFrame

Return active orders.

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,
        ),
    )

positions

positions(
    symbol: str | None = None,
    group: str | None = None,
    ticket: int | None = None,
) -> DataFrame

Return open positions.

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,
        ),
    )

recent_history_deals

recent_history_deals(
    hours: float,
    date_to: datetime | str | None = None,
    group: str | None = None,
    symbol: str | None = None,
) -> DataFrame

Return historical deals from a recent trailing window.

Source code in mt5cli/sdk.py
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,
    )

recent_ticks

recent_ticks(
    symbol: str,
    seconds: float,
    *,
    date_to: datetime | str | None = None,
    count: int = 10000,
    flags: int | str = "ALL",
) -> DataFrame

Return ticks from a recent time window.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required
seconds float

Lookback window in seconds ending at date_to.

required
date_to datetime | str | None

Window end time. When None, uses the latest symbol_info_tick().time rather than wall-clock now.

None
count int

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.

10000
flags int | str

Tick flags as ALL, INFO, TRADE, or an integer.

'ALL'

Returns:

Type Description
DataFrame

Tick DataFrame with MT5 tick columns such as time, bid,

DataFrame

ask, last, and volume.

Source code in mt5cli/sdk.py
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,
        ),
    )

symbol_info

symbol_info(symbol: str) -> DataFrame

Return details for one symbol.

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))

symbol_info_tick

symbol_info_tick(symbol: str) -> DataFrame

Return the last tick for a symbol.

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))

symbols

symbols(group: str | None = None) -> DataFrame

Return the symbol list.

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))

terminal_info

terminal_info() -> DataFrame

Return terminal information.

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())

version

version() -> DataFrame

Return MetaTrader5 version information.

Source code in mt5cli/sdk.py
def version(self) -> pd.DataFrame:
    """Return MetaTrader5 version information."""
    return self._fetch(lambda c: c.version_as_df())

account_info

account_info(
    *, config: Mt5Config | None = None
) -> DataFrame

Return account information.

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()

build_config

build_config(
    *,
    path: str | None = None,
    login: int | None = None,
    password: str | None = None,
    server: str | None = None,
    timeout: int | None = None,
) -> Mt5Config

Build an Mt5Config from optional connection parameters.

Returns:

Type Description
Mt5Config

Configured Mt5Config instance.

Source code in mt5cli/sdk.py
def build_config(
    *,
    path: str | None = None,
    login: int | None = None,
    password: str | None = None,
    server: str | None = None,
    timeout: int | None = None,
) -> Mt5Config:
    """Build an ``Mt5Config`` from optional connection parameters.

    Returns:
        Configured ``Mt5Config`` instance.
    """
    return Mt5Config(
        path=path,
        login=login,
        password=password,
        server=server,
        timeout=timeout,
    )

collect_history

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 = 1,
    if_exists: IfExists = FAIL,
    with_views: bool = False,
    config: Mt5Config | None = None,
) -> None

Collect historical datasets into a single SQLite database.

Parameters:

Name Type Description Default
output Path

SQLite database path.

required
symbols list[str]

Symbols to collect.

required
date_from datetime | str

Start date.

required
date_to datetime | str

End date.

required
datasets set[Dataset] | None

Datasets to include (defaults to all).

None
timeframe int | str

Rates timeframe as integer or name (e.g. M1).

1
flags int | str

Tick copy flags as integer or name (e.g. ALL).

1
if_exists IfExists

Behavior when a target table already exists.

FAIL
with_views bool

Create cash_events and positions_reconstructed views.

False
config Mt5Config | None

MT5 connection configuration.

None
Source code in mt5cli/sdk.py
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 = 1,
    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 all).
        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 = datasets if datasets is not None else set(Dataset)
    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,
    )

collect_latest_rates

collect_latest_rates(
    symbols: Sequence[str],
    timeframes: Sequence[int | str],
    *,
    count: int,
    start_pos: int = 0,
    config: Mt5Config | None = None,
) -> dict[tuple[str, int], DataFrame]

Return latest rates for each symbol/timeframe pair.

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,
    )

collect_latest_rates_for_accounts

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], 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.

Parameters:

Name Type Description Default
accounts Sequence[AccountSpec]

Account groups to read. Each must define at least one symbol.

required
timeframes Sequence[int | str]

MT5 timeframes as integers or names (for example M1).

required
count int

Number of most recent bars to read per symbol/timeframe.

required
start_pos int

Initial bar position offset.

0
base_config Mt5Config | None

Optional base configuration whose fields fill any value not set on an individual account.

None

Returns:

Type Description
dict[tuple[str, int], DataFrame]

Mapping keyed by (symbol, timeframe_int). When accounts share a

dict[tuple[str, int], DataFrame]

symbol/timeframe pair, the last account processed wins.

Raises:

Type Description
ValueError

If accounts, timeframes, or any account's symbols are empty, or count is not positive.

Source code in mt5cli/sdk.py
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

copy_rates_from

copy_rates_from(
    symbol: str,
    timeframe: int | str,
    date_from: datetime | str,
    count: int,
    *,
    config: Mt5Config | None = None,
) -> DataFrame

Return rates starting from a date.

Source code in mt5cli/sdk.py
def copy_rates_from(
    symbol: str,
    timeframe: int | str,
    date_from: datetime | str,
    count: int,
    *,
    config: Mt5Config | None = None,
) -> pd.DataFrame:
    """Return rates starting from a date."""
    return _make_client(config=config).copy_rates_from(
        symbol,
        timeframe,
        date_from,
        count,
    )

copy_rates_from_pos

copy_rates_from_pos(
    symbol: str,
    timeframe: int | str,
    start_pos: int,
    count: int,
    *,
    config: Mt5Config | None = None,
) -> DataFrame

Return rates starting from a bar position.

Source code in mt5cli/sdk.py
def copy_rates_from_pos(
    symbol: str,
    timeframe: int | str,
    start_pos: int,
    count: int,
    *,
    config: Mt5Config | None = None,
) -> pd.DataFrame:
    """Return rates starting from a bar position."""
    return _make_client(config=config).copy_rates_from_pos(
        symbol,
        timeframe,
        start_pos,
        count,
    )

copy_rates_range

copy_rates_range(
    symbol: str,
    timeframe: int | str,
    date_from: datetime | str,
    date_to: datetime | str,
    *,
    config: Mt5Config | None = None,
) -> DataFrame

Return rates for a date range.

Source code in mt5cli/sdk.py
def copy_rates_range(
    symbol: str,
    timeframe: int | str,
    date_from: datetime | str,
    date_to: datetime | str,
    *,
    config: Mt5Config | None = None,
) -> pd.DataFrame:
    """Return rates for a date range."""
    return _make_client(config=config).copy_rates_range(
        symbol,
        timeframe,
        date_from,
        date_to,
    )

copy_ticks_from

copy_ticks_from(
    symbol: str,
    date_from: datetime | str,
    count: int,
    flags: int | str,
    *,
    config: Mt5Config | None = None,
) -> DataFrame

Return ticks starting from a date.

Source code in mt5cli/sdk.py
def copy_ticks_from(
    symbol: str,
    date_from: datetime | str,
    count: int,
    flags: int | str,
    *,
    config: Mt5Config | None = None,
) -> pd.DataFrame:
    """Return ticks starting from a date."""
    return _make_client(config=config).copy_ticks_from(
        symbol,
        date_from,
        count,
        flags,
    )

copy_ticks_range

copy_ticks_range(
    symbol: str,
    date_from: datetime | str,
    date_to: datetime | str,
    flags: int | str,
    *,
    config: Mt5Config | None = None,
) -> DataFrame

Return ticks for a date range.

Source code in mt5cli/sdk.py
def copy_ticks_range(
    symbol: str,
    date_from: datetime | str,
    date_to: datetime | str,
    flags: int | str,
    *,
    config: Mt5Config | None = None,
) -> pd.DataFrame:
    """Return ticks for a date range."""
    return _make_client(config=config).copy_ticks_range(
        symbol,
        date_from,
        date_to,
        flags,
    )

history_deals

history_deals(
    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,
    *,
    config: Mt5Config | None = None,
) -> DataFrame

Return historical deals.

Source code in mt5cli/sdk.py
def history_deals(
    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,
    *,
    config: Mt5Config | None = None,
) -> pd.DataFrame:
    """Return historical deals."""
    return _make_client(config=config).history_deals(
        date_from=date_from,
        date_to=date_to,
        group=group,
        symbol=symbol,
        ticket=ticket,
        position=position,
    )

history_orders

history_orders(
    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,
    *,
    config: Mt5Config | None = None,
) -> DataFrame

Return historical orders.

Source code in mt5cli/sdk.py
def history_orders(
    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,
    *,
    config: Mt5Config | None = None,
) -> pd.DataFrame:
    """Return historical orders."""
    return _make_client(config=config).history_orders(
        date_from=date_from,
        date_to=date_to,
        group=group,
        symbol=symbol,
        ticket=ticket,
        position=position,
    )

last_error

last_error(*, config: Mt5Config | None = None) -> DataFrame

Return the last error information.

Source code in mt5cli/sdk.py
def last_error(*, config: Mt5Config | None = None) -> pd.DataFrame:
    """Return the last error information."""
    return _make_client(config=config).last_error()

latest_rates

latest_rates(
    symbol: str,
    timeframe: int | str,
    count: int,
    start_pos: int = 0,
    *,
    config: Mt5Config | None = None,
) -> DataFrame

Return the latest rates from a bar position.

Source code in mt5cli/sdk.py
def latest_rates(
    symbol: str,
    timeframe: int | str,
    count: int,
    start_pos: int = 0,
    *,
    config: Mt5Config | None = None,
) -> pd.DataFrame:
    """Return the latest rates from a bar position."""
    return _make_client(config=config).latest_rates(
        symbol,
        timeframe,
        count,
        start_pos=start_pos,
    )

market_book

market_book(
    symbol: str, *, config: Mt5Config | None = None
) -> DataFrame

Return market depth for a symbol.

Source code in mt5cli/sdk.py
def market_book(
    symbol: str,
    *,
    config: Mt5Config | None = None,
) -> pd.DataFrame:
    """Return market depth for a symbol."""
    return _make_client(config=config).market_book(symbol)

minimum_margins

minimum_margins(
    symbol: str, *, config: Mt5Config | None = None
) -> DataFrame

Return minimum-volume buy and sell margin requirements.

See Mt5CliClient.minimum_margins for return details.

Source code in mt5cli/sdk.py
def minimum_margins(
    symbol: str,
    *,
    config: Mt5Config | None = None,
) -> pd.DataFrame:
    """Return minimum-volume buy and sell margin requirements.

    See ``Mt5CliClient.minimum_margins`` for return details.
    """
    return _make_client(config=config).minimum_margins(symbol)

mt5_session

mt5_session(
    config: Mt5Config | None = None,
) -> Iterator[Mt5CliClient]

Open an MT5 terminal session and yield a connected client.

Launches the MetaTrader 5 terminal using Mt5Config.path (when set), logs in, yields a connected :class:Mt5CliClient, and always shuts the terminal down on exit.

Parameters:

Name Type Description Default
config Mt5Config | None

MT5 connection configuration. Defaults to an empty config that attaches to a running terminal.

None

Yields:

Type Description
Mt5CliClient

Connected Mt5CliClient bound to the session.

Source code in mt5cli/sdk.py
@contextmanager
def mt5_session(config: Mt5Config | None = None) -> Iterator[Mt5CliClient]:
    """Open an MT5 terminal session and yield a connected client.

    Launches the MetaTrader 5 terminal using ``Mt5Config.path`` (when set),
    logs in, yields a connected :class:`Mt5CliClient`, and always shuts the
    terminal down on exit.

    Args:
        config: MT5 connection configuration. Defaults to an empty config that
            attaches to a running terminal.

    Yields:
        Connected ``Mt5CliClient`` bound to the session.
    """
    mt5_config = config or build_config()
    with _connected_client(mt5_config) as client:
        yield Mt5CliClient.from_connected_client(client)

mt5_summary

mt5_summary(
    *, config: Mt5Config | None = None
) -> dict[str, object]

Return a compact terminal/account status summary.

Source code in mt5cli/sdk.py
def mt5_summary(*, config: Mt5Config | None = None) -> dict[str, object]:
    """Return a compact terminal/account status summary."""
    return _make_client(config=config).mt5_summary()

mt5_summary_as_df

mt5_summary_as_df(
    *, config: Mt5Config | None = None
) -> DataFrame

Return an export-safe terminal/account status summary DataFrame.

Source code in mt5cli/sdk.py
def mt5_summary_as_df(*, config: Mt5Config | None = None) -> pd.DataFrame:
    """Return an export-safe terminal/account status summary DataFrame."""
    return _make_client(config=config).mt5_summary_as_df()

orders

orders(
    symbol: str | None = None,
    group: str | None = None,
    ticket: int | None = None,
    *,
    config: Mt5Config | None = None,
) -> DataFrame

Return active orders.

Source code in mt5cli/sdk.py
def orders(
    symbol: str | None = None,
    group: str | None = None,
    ticket: int | None = None,
    *,
    config: Mt5Config | None = None,
) -> pd.DataFrame:
    """Return active orders."""
    return _make_client(config=config).orders(
        symbol=symbol,
        group=group,
        ticket=ticket,
    )

positions

positions(
    symbol: str | None = None,
    group: str | None = None,
    ticket: int | None = None,
    *,
    config: Mt5Config | None = None,
) -> DataFrame

Return open positions.

Source code in mt5cli/sdk.py
def positions(
    symbol: str | None = None,
    group: str | None = None,
    ticket: int | None = None,
    *,
    config: Mt5Config | None = None,
) -> pd.DataFrame:
    """Return open positions."""
    return _make_client(config=config).positions(
        symbol=symbol,
        group=group,
        ticket=ticket,
    )

recent_history_deals

recent_history_deals(
    hours: float,
    date_to: datetime | str | None = None,
    group: str | None = None,
    symbol: str | None = None,
    *,
    config: Mt5Config | None = None,
) -> DataFrame

Return historical deals from a recent trailing window.

Source code in mt5cli/sdk.py
def recent_history_deals(
    hours: float,
    date_to: datetime | str | None = None,
    group: str | None = None,
    symbol: str | None = None,
    *,
    config: Mt5Config | None = None,
) -> pd.DataFrame:
    """Return historical deals from a recent trailing window."""
    return _make_client(config=config).recent_history_deals(
        hours,
        date_to=date_to,
        group=group,
        symbol=symbol,
    )

recent_ticks

recent_ticks(
    symbol: str,
    seconds: float,
    *,
    date_to: datetime | str | None = None,
    count: int = 10000,
    flags: int | str = "ALL",
    config: Mt5Config | None = None,
) -> DataFrame

Return ticks from a recent time window ending at date_to or now.

See Mt5CliClient.recent_ticks for parameter and return details.

Source code in mt5cli/sdk.py
def recent_ticks(
    symbol: str,
    seconds: float,
    *,
    date_to: datetime | str | None = None,
    count: int = 10000,
    flags: int | str = "ALL",
    config: Mt5Config | None = None,
) -> pd.DataFrame:
    """Return ticks from a recent time window ending at ``date_to`` or now.

    See ``Mt5CliClient.recent_ticks`` for parameter and return details.
    """
    return _make_client(config=config).recent_ticks(
        symbol,
        seconds,
        date_to=date_to,
        count=count,
        flags=flags,
    )

symbol_info

symbol_info(
    symbol: str, *, config: Mt5Config | None = None
) -> DataFrame

Return details for one symbol.

Source code in mt5cli/sdk.py
def symbol_info(
    symbol: str,
    *,
    config: Mt5Config | None = None,
) -> pd.DataFrame:
    """Return details for one symbol."""
    return _make_client(config=config).symbol_info(symbol)

symbol_info_tick

symbol_info_tick(
    symbol: str, *, config: Mt5Config | None = None
) -> DataFrame

Return the last tick for a symbol.

Source code in mt5cli/sdk.py
def symbol_info_tick(
    symbol: str,
    *,
    config: Mt5Config | None = None,
) -> pd.DataFrame:
    """Return the last tick for a symbol."""
    return _make_client(config=config).symbol_info_tick(symbol)

symbols

symbols(
    group: str | None = None,
    *,
    config: Mt5Config | None = None,
) -> DataFrame

Return the symbol list.

Source code in mt5cli/sdk.py
def symbols(
    group: str | None = None,
    *,
    config: Mt5Config | None = None,
) -> pd.DataFrame:
    """Return the symbol list."""
    return _make_client(config=config).symbols(group=group)

terminal_info

terminal_info(
    *, config: Mt5Config | None = None
) -> DataFrame

Return terminal information.

Source code in mt5cli/sdk.py
def terminal_info(*, config: Mt5Config | None = None) -> pd.DataFrame:
    """Return terminal information."""
    return _make_client(config=config).terminal_info()

update_history

update_history(
    *,
    client: Mt5DataClient,
    output: Path | str,
    symbols: Sequence[str],
    datasets: set[Dataset] | None = None,
    timeframes: Sequence[int | str] | None = None,
    flags: int | str = "ALL",
    lookback_hours: float = 24.0,
    date_to: datetime | str | None = None,
    deduplicate: bool = True,
    create_rate_views: bool = True,
    with_views: bool = False,
    include_account_events: bool = True,
) -> None

Incrementally append MT5 history into a SQLite database.

Uses an already-connected Mt5DataClient and does not create or close the MT5 connection. For first-time tables, data is fetched from date_to - lookback_hours. Subsequent runs resume from existing MAX(time) per symbol (and timeframe for rates); when include_account_events=True, account-level deals use a separate cursor over type NOT IN (0, 1) / empty-symbol rows.

Parameters:

Name Type Description Default
client Mt5DataClient

Connected MT5 data client.

required
output Path | str

SQLite database path.

required
symbols Sequence[str]

Symbols to update.

required
datasets set[Dataset] | None

Datasets to include (defaults to all).

None
timeframes Sequence[int | str] | None

Rate timeframes to update (defaults to all fixed MT5 timeframes when None).

None
flags int | str

Tick copy flags as integer or name (e.g. ALL).

'ALL'
lookback_hours float

First-run lookback when a table has no prior rows.

24.0
date_to datetime | str | None

Optional update end datetime. Defaults to now (UTC).

None
deduplicate bool

Remove duplicate rows after append, keeping latest ROWID.

True
create_rate_views bool

Create rate_<symbol>__<timeframe> views.

True
with_views bool

Create cash_events and positions_reconstructed views.

False
include_account_events bool

Include account-level cash events in history_deals when True.

True
Source code in mt5cli/sdk.py
def update_history(  # noqa: PLR0913
    *,
    client: Mt5DataClient,
    output: Path | str,
    symbols: Sequence[str],
    datasets: set[Dataset] | None = None,
    timeframes: Sequence[int | str] | None = None,
    flags: int | str = "ALL",
    lookback_hours: float = 24.0,
    date_to: datetime | str | None = None,
    deduplicate: bool = True,
    create_rate_views: bool = True,
    with_views: bool = False,
    include_account_events: bool = True,
) -> None:
    """Incrementally append MT5 history into a SQLite database.

    Uses an already-connected ``Mt5DataClient`` and does not create or close
    the MT5 connection. For first-time tables, data is fetched from
    ``date_to - lookback_hours``. Subsequent runs resume from existing
    ``MAX(time)`` per symbol (and timeframe for rates); when
    ``include_account_events=True``, account-level deals use a separate cursor
    over ``type NOT IN (0, 1)`` / empty-symbol rows.

    Args:
        client: Connected MT5 data client.
        output: SQLite database path.
        symbols: Symbols to update.
        datasets: Datasets to include (defaults to all).
        timeframes: Rate timeframes to update (defaults to all fixed MT5
            timeframes when None).
        flags: Tick copy flags as integer or name (e.g. ``ALL``).
        lookback_hours: First-run lookback when a table has no prior rows.
        date_to: Optional update end datetime. Defaults to now (UTC).
        deduplicate: Remove duplicate rows after append, keeping latest ROWID.
        create_rate_views: Create ``rate_<symbol>__<timeframe>`` views.
        with_views: Create ``cash_events`` and ``positions_reconstructed`` views.
        include_account_events: Include account-level cash events in
            ``history_deals`` when True.
    """
    request = _resolve_update_history_request(
        output=output,
        symbols=symbols,
        datasets=datasets,
        timeframes=timeframes,
        flags=flags,
        lookback_hours=lookback_hours,
        date_to=date_to,
    )
    if request is None:
        return
    logger.info(
        "Updating history in SQLite: symbols=%s, datasets=%s, path=%s",
        list(symbols),
        sorted(dataset.value for dataset in request.selected),
        request.output_path,
    )
    with sqlite3.connect(request.output_path) as conn:
        conn.execute("PRAGMA journal_mode=WAL")
        conn.execute("PRAGMA synchronous=NORMAL")
        write_incremental_datasets(
            conn,
            client,
            symbols,
            request.selected,
            request.resolved_timeframes,
            request.resolved_tick_flags,
            request.fallback_start,
            request.end,
            deduplicate=deduplicate,
            create_rate_views=create_rate_views,
            with_views=with_views,
            include_account_events=include_account_events,
        )

update_history_with_config

update_history_with_config(
    *,
    output: Path | str,
    symbols: Sequence[str],
    config: Mt5Config | None = None,
    datasets: set[Dataset] | None = None,
    timeframes: Sequence[int | str] | None = None,
    flags: int | str = "ALL",
    lookback_hours: float = 24.0,
    date_to: datetime | str | None = None,
    deduplicate: bool = True,
    create_rate_views: bool = True,
    with_views: bool = False,
    include_account_events: bool = True,
) -> None

Incrementally append MT5 history, opening and closing the MT5 connection.

Convenience wrapper around :func:update_history for standalone use.

Source code in mt5cli/sdk.py
def update_history_with_config(  # noqa: PLR0913
    *,
    output: Path | str,
    symbols: Sequence[str],
    config: Mt5Config | None = None,
    datasets: set[Dataset] | None = None,
    timeframes: Sequence[int | str] | None = None,
    flags: int | str = "ALL",
    lookback_hours: float = 24.0,
    date_to: datetime | str | None = None,
    deduplicate: bool = True,
    create_rate_views: bool = True,
    with_views: bool = False,
    include_account_events: bool = True,
) -> None:
    """Incrementally append MT5 history, opening and closing the MT5 connection.

    Convenience wrapper around :func:`update_history` for standalone use.
    """
    request = _resolve_update_history_request(
        output=output,
        symbols=symbols,
        datasets=datasets,
        timeframes=timeframes,
        flags=flags,
        lookback_hours=lookback_hours,
        date_to=date_to,
    )
    if request is None:
        return
    mt5_config = config or build_config()
    with _connected_client(mt5_config) as client:
        update_history(
            client=client,
            output=output,
            symbols=symbols,
            datasets=datasets,
            timeframes=timeframes,
            flags=flags,
            lookback_hours=lookback_hours,
            date_to=date_to,
            deduplicate=deduplicate,
            create_rate_views=create_rate_views,
            with_views=with_views,
            include_account_events=include_account_events,
        )

version

version(*, config: Mt5Config | None = None) -> DataFrame

Return MetaTrader5 version information.

Source code in mt5cli/sdk.py
def version(*, config: Mt5Config | None = None) -> pd.DataFrame:
    """Return MetaTrader5 version information."""
    return _make_client(config=config).version()