Skip to content

CLI Module

mt5cli.cli

Command-line interface for MetaTrader 5 data export.

DATETIME_TYPE module-attribute

DATETIME_TYPE = _DateTimeType()

TICK_FLAGS_TYPE module-attribute

TICK_FLAGS_TYPE = _TickFlagsType()

TICK_FLAG_MAP module-attribute

TICK_FLAG_MAP: dict[str, int] = {
    "ALL": 1,
    "INFO": 2,
    "TRADE": 4,
}

TIMEFRAME_MAP module-attribute

TIMEFRAME_MAP: dict[str, int] = {
    "M1": 1,
    "M2": 2,
    "M3": 3,
    "M4": 4,
    "M5": 5,
    "M6": 6,
    "M10": 10,
    "M12": 12,
    "M15": 15,
    "M20": 20,
    "M30": 30,
    "H1": 16385,
    "H2": 16386,
    "H3": 16387,
    "H4": 16388,
    "H6": 16390,
    "H8": 16392,
    "H12": 16396,
    "D1": 16408,
    "W1": 32769,
    "MN1": 49153,
}

TIMEFRAME_TYPE module-attribute

TIMEFRAME_TYPE = _TimeframeType()

app module-attribute

app = Typer(
    name="mt5cli",
    help="Export MetaTrader5 data to CSV, JSON, Parquet, or SQLite3.",
)

logger module-attribute

logger = getLogger(__name__)

LogLevel

Bases: StrEnum

Logging verbosity levels.

DEBUG class-attribute instance-attribute

DEBUG = 'DEBUG'

ERROR class-attribute instance-attribute

ERROR = 'ERROR'

INFO class-attribute instance-attribute

INFO = 'INFO'

WARNING class-attribute instance-attribute

WARNING = 'WARNING'

OutputFormat

Bases: StrEnum

Supported output file formats.

csv class-attribute instance-attribute

csv = 'csv'

json class-attribute instance-attribute

json = 'json'

parquet class-attribute instance-attribute

parquet = 'parquet'

sqlite3 class-attribute instance-attribute

sqlite3 = 'sqlite3'

account_info

account_info(ctx: Context) -> None

Export account information.

Source code in mt5cli/cli.py
@app.command()
def account_info(ctx: typer.Context) -> None:
    """Export account information."""
    _execute_export(ctx, lambda c: c.account_info_as_df())

detect_format

detect_format(
    output_path: Path, explicit_format: str | None = None
) -> str

Detect the output format from a file extension or explicit format string.

Parameters:

Name Type Description Default
output_path Path

Path to the output file.

required
explicit_format str | None

Explicitly specified format, if any.

None

Returns:

Type Description
str

The detected format string.

Raises:

Type Description
ValueError

If the format cannot be determined.

Source code in mt5cli/cli.py
def detect_format(
    output_path: Path,
    explicit_format: str | None = None,
) -> str:
    """Detect the output format from a file extension or explicit format string.

    Args:
        output_path: Path to the output file.
        explicit_format: Explicitly specified format, if any.

    Returns:
        The detected format string.

    Raises:
        ValueError: If the format cannot be determined.
    """
    if explicit_format is not None:
        return explicit_format
    suffix = output_path.suffix.lower()
    if suffix in _FORMAT_EXTENSIONS:
        return _FORMAT_EXTENSIONS[suffix]
    msg = (
        f"Cannot detect format from extension '{suffix}'."
        " Use --format to specify the output format."
    )
    raise ValueError(msg)

export_dataframe

export_dataframe(
    df: DataFrame,
    output_path: Path,
    output_format: str,
    table_name: str = "data",
) -> None

Export a pandas DataFrame to the specified file format.

Parameters:

Name Type Description Default
df DataFrame

DataFrame to export.

required
output_path Path

Path to the output file.

required
output_format str

Output format (csv, json, parquet, or sqlite3).

required
table_name str

Table name for SQLite3 output.

'data'

Raises:

Type Description
ValueError

If the output format is not supported.

Source code in mt5cli/cli.py
def export_dataframe(
    df: pd.DataFrame,
    output_path: Path,
    output_format: str,
    table_name: str = "data",
) -> None:
    """Export a pandas DataFrame to the specified file format.

    Args:
        df: DataFrame to export.
        output_path: Path to the output file.
        output_format: Output format (csv, json, parquet, or sqlite3).
        table_name: Table name for SQLite3 output.

    Raises:
        ValueError: If the output format is not supported.
    """
    if output_format == "csv":
        df.to_csv(output_path, index=False)
    elif output_format == "json":
        df.to_json(
            output_path,
            orient="records",
            date_format="iso",
            indent=2,
        )
    elif output_format == "parquet":
        df.to_parquet(output_path, index=False)
    elif output_format == "sqlite3":
        with sqlite3.connect(output_path) as conn:
            df.to_sql(  # type: ignore[reportUnknownMemberType]
                table_name,
                conn,
                if_exists="replace",
                index=False,
            )
    else:
        msg = f"Unsupported output format: {output_format}"
        raise ValueError(msg)

history_deals

history_deals(
    ctx: Context,
    date_from: Annotated[
        datetime | None,
        Option(
            click_type=DATETIME_TYPE, help="Start date."
        ),
    ] = None,
    date_to: Annotated[
        datetime | None,
        Option(click_type=DATETIME_TYPE, help="End date."),
    ] = None,
    group: Annotated[
        str | None, Option(help="Group filter.")
    ] = None,
    symbol: Annotated[
        str | None, Option(help="Symbol filter.")
    ] = None,
    ticket: Annotated[
        int | None, Option(help="Order ticket.")
    ] = None,
    position: Annotated[
        int | None, Option(help="Position ticket.")
    ] = None,
) -> None

Export historical deals.

Source code in mt5cli/cli.py
@app.command()
def history_deals(
    ctx: typer.Context,
    date_from: Annotated[
        datetime | None,
        typer.Option(click_type=DATETIME_TYPE, help="Start date."),
    ] = None,
    date_to: Annotated[
        datetime | None,
        typer.Option(click_type=DATETIME_TYPE, help="End date."),
    ] = None,
    group: Annotated[str | None, typer.Option(help="Group filter.")] = None,
    symbol: Annotated[str | None, typer.Option(help="Symbol filter.")] = None,
    ticket: Annotated[int | None, typer.Option(help="Order ticket.")] = None,
    position: Annotated[int | None, typer.Option(help="Position ticket.")] = None,
) -> None:
    """Export historical deals."""
    _execute_export(
        ctx,
        lambda c: c.history_deals_get_as_df(
            date_from=date_from,
            date_to=date_to,
            group=group,
            symbol=symbol,
            ticket=ticket,
            position=position,
        ),
    )

history_orders

history_orders(
    ctx: Context,
    date_from: Annotated[
        datetime | None,
        Option(
            click_type=DATETIME_TYPE, help="Start date."
        ),
    ] = None,
    date_to: Annotated[
        datetime | None,
        Option(click_type=DATETIME_TYPE, help="End date."),
    ] = None,
    group: Annotated[
        str | None, Option(help="Group filter.")
    ] = None,
    symbol: Annotated[
        str | None, Option(help="Symbol filter.")
    ] = None,
    ticket: Annotated[
        int | None, Option(help="Order ticket.")
    ] = None,
    position: Annotated[
        int | None, Option(help="Position ticket.")
    ] = None,
) -> None

Export historical orders.

Source code in mt5cli/cli.py
@app.command()
def history_orders(
    ctx: typer.Context,
    date_from: Annotated[
        datetime | None,
        typer.Option(click_type=DATETIME_TYPE, help="Start date."),
    ] = None,
    date_to: Annotated[
        datetime | None,
        typer.Option(click_type=DATETIME_TYPE, help="End date."),
    ] = None,
    group: Annotated[str | None, typer.Option(help="Group filter.")] = None,
    symbol: Annotated[str | None, typer.Option(help="Symbol filter.")] = None,
    ticket: Annotated[int | None, typer.Option(help="Order ticket.")] = None,
    position: Annotated[int | None, typer.Option(help="Position ticket.")] = None,
) -> None:
    """Export historical orders."""
    _execute_export(
        ctx,
        lambda c: c.history_orders_get_as_df(
            date_from=date_from,
            date_to=date_to,
            group=group,
            symbol=symbol,
            ticket=ticket,
            position=position,
        ),
    )

main

main() -> None

Run the mt5cli CLI.

Source code in mt5cli/cli.py
def main() -> None:
    """Run the mt5cli CLI."""
    app()

orders

orders(
    ctx: Context,
    symbol: Annotated[
        str | None, Option(help="Symbol filter.")
    ] = None,
    group: Annotated[
        str | None, Option(help="Group filter.")
    ] = None,
    ticket: Annotated[
        int | None, Option(help="Ticket filter.")
    ] = None,
) -> None

Export active orders.

Source code in mt5cli/cli.py
@app.command()
def orders(
    ctx: typer.Context,
    symbol: Annotated[str | None, typer.Option(help="Symbol filter.")] = None,
    group: Annotated[str | None, typer.Option(help="Group filter.")] = None,
    ticket: Annotated[int | None, typer.Option(help="Ticket filter.")] = None,
) -> None:
    """Export active orders."""
    _execute_export(
        ctx,
        lambda c: c.orders_get_as_df(
            symbol=symbol,
            group=group,
            ticket=ticket,
        ),
    )

parse_datetime

parse_datetime(value: str) -> datetime

Parse an ISO 8601 datetime string to a timezone-aware datetime.

Parameters:

Name Type Description Default
value str

ISO 8601 datetime string (e.g., '2024-01-01' or '2024-01-01T12:00:00+00:00').

required

Returns:

Type Description
datetime

Parsed datetime with UTC timezone if no timezone is specified.

Raises:

Type Description
ValueError

If the string cannot be parsed.

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

parse_tick_flags

parse_tick_flags(value: str) -> int

Parse tick flags string or integer value.

Parameters:

Name Type Description Default
value str

Tick flag name (ALL, INFO, TRADE) or integer value.

required

Returns:

Type Description
int

Integer tick flag value.

Raises:

Type Description
ValueError

If the flag is invalid.

Source code in mt5cli/cli.py
def parse_tick_flags(value: str) -> int:
    """Parse tick flags string or integer value.

    Args:
        value: Tick flag name (ALL, INFO, TRADE) or integer value.

    Returns:
        Integer tick flag value.

    Raises:
        ValueError: If the flag is invalid.
    """
    upper = value.upper()
    if upper in TICK_FLAG_MAP:
        return TICK_FLAG_MAP[upper]
    try:
        return int(value)
    except ValueError:
        valid = ", ".join(TICK_FLAG_MAP)
        msg = f"Invalid tick flags: '{value}'. Use one of: {valid}, or an integer."
        raise ValueError(msg) from None

parse_timeframe

parse_timeframe(value: str) -> int

Parse a timeframe string or integer value.

Parameters:

Name Type Description Default
value str

Timeframe name (e.g., 'M1', 'H1', 'D1') or integer value.

required

Returns:

Type Description
int

Integer timeframe value.

Raises:

Type Description
ValueError

If the timeframe is invalid.

Source code in mt5cli/cli.py
def parse_timeframe(value: str) -> 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.
    """
    upper = value.upper()
    if upper in TIMEFRAME_MAP:
        return TIMEFRAME_MAP[upper]
    try:
        return int(value)
    except ValueError:
        valid = ", ".join(TIMEFRAME_MAP)
        msg = f"Invalid timeframe: '{value}'. Use one of: {valid}, or an integer."
        raise ValueError(msg) from None

positions

positions(
    ctx: Context,
    symbol: Annotated[
        str | None, Option(help="Symbol filter.")
    ] = None,
    group: Annotated[
        str | None, Option(help="Group filter.")
    ] = None,
    ticket: Annotated[
        int | None, Option(help="Ticket filter.")
    ] = None,
) -> None

Export open positions.

Source code in mt5cli/cli.py
@app.command()
def positions(
    ctx: typer.Context,
    symbol: Annotated[str | None, typer.Option(help="Symbol filter.")] = None,
    group: Annotated[str | None, typer.Option(help="Group filter.")] = None,
    ticket: Annotated[int | None, typer.Option(help="Ticket filter.")] = None,
) -> None:
    """Export open positions."""
    _execute_export(
        ctx,
        lambda c: c.positions_get_as_df(
            symbol=symbol,
            group=group,
            ticket=ticket,
        ),
    )

rates_from

rates_from(
    ctx: Context,
    symbol: Annotated[str, Option(help="Symbol name.")],
    timeframe: Annotated[
        int,
        Option(
            click_type=TIMEFRAME_TYPE,
            help="Timeframe (e.g., M1, H1, D1, or integer).",
        ),
    ],
    date_from: Annotated[
        datetime,
        Option(
            click_type=DATETIME_TYPE,
            help="Start date in ISO 8601 format.",
        ),
    ],
    count: Annotated[
        int, Option(help="Number of records.")
    ],
) -> None

Export rates from a start date.

Source code in mt5cli/cli.py
@app.command()
def rates_from(
    ctx: typer.Context,
    symbol: Annotated[str, typer.Option(help="Symbol name.")],
    timeframe: Annotated[
        int,
        typer.Option(
            click_type=TIMEFRAME_TYPE,
            help="Timeframe (e.g., M1, H1, D1, or integer).",
        ),
    ],
    date_from: Annotated[
        datetime,
        typer.Option(
            click_type=DATETIME_TYPE,
            help="Start date in ISO 8601 format.",
        ),
    ],
    count: Annotated[int, typer.Option(help="Number of records.")],
) -> None:
    """Export rates from a start date."""
    _execute_export(
        ctx,
        lambda c: c.copy_rates_from_as_df(
            symbol=symbol,
            timeframe=timeframe,
            date_from=date_from,
            count=count,
        ),
    )

rates_from_pos

rates_from_pos(
    ctx: Context,
    symbol: Annotated[str, Option(help="Symbol name.")],
    timeframe: Annotated[
        int,
        Option(
            click_type=TIMEFRAME_TYPE, help="Timeframe."
        ),
    ],
    start_pos: Annotated[
        int,
        Option(help="Start position (0 = current bar)."),
    ],
    count: Annotated[
        int, Option(help="Number of records.")
    ],
) -> None

Export rates from a start position.

Source code in mt5cli/cli.py
@app.command()
def rates_from_pos(
    ctx: typer.Context,
    symbol: Annotated[str, typer.Option(help="Symbol name.")],
    timeframe: Annotated[
        int,
        typer.Option(
            click_type=TIMEFRAME_TYPE,
            help="Timeframe.",
        ),
    ],
    start_pos: Annotated[int, typer.Option(help="Start position (0 = current bar).")],
    count: Annotated[int, typer.Option(help="Number of records.")],
) -> None:
    """Export rates from a start position."""
    _execute_export(
        ctx,
        lambda c: c.copy_rates_from_pos_as_df(
            symbol=symbol,
            timeframe=timeframe,
            start_pos=start_pos,
            count=count,
        ),
    )

rates_range

rates_range(
    ctx: Context,
    symbol: Annotated[str, Option(help="Symbol name.")],
    timeframe: Annotated[
        int,
        Option(
            click_type=TIMEFRAME_TYPE, help="Timeframe."
        ),
    ],
    date_from: Annotated[
        datetime,
        Option(
            click_type=DATETIME_TYPE, help="Start date."
        ),
    ],
    date_to: Annotated[
        datetime,
        Option(click_type=DATETIME_TYPE, help="End date."),
    ],
) -> None

Export rates for a date range.

Source code in mt5cli/cli.py
@app.command()
def rates_range(
    ctx: typer.Context,
    symbol: Annotated[str, typer.Option(help="Symbol name.")],
    timeframe: Annotated[
        int,
        typer.Option(
            click_type=TIMEFRAME_TYPE,
            help="Timeframe.",
        ),
    ],
    date_from: Annotated[
        datetime,
        typer.Option(click_type=DATETIME_TYPE, help="Start date."),
    ],
    date_to: Annotated[
        datetime,
        typer.Option(click_type=DATETIME_TYPE, help="End date."),
    ],
) -> None:
    """Export rates for a date range."""
    _execute_export(
        ctx,
        lambda c: c.copy_rates_range_as_df(
            symbol=symbol,
            timeframe=timeframe,
            date_from=date_from,
            date_to=date_to,
        ),
    )

symbol_info

symbol_info(
    ctx: Context,
    symbol: Annotated[str, Option(help="Symbol name.")],
) -> None

Export symbol details.

Source code in mt5cli/cli.py
@app.command()
def symbol_info(
    ctx: typer.Context,
    symbol: Annotated[str, typer.Option(help="Symbol name.")],
) -> None:
    """Export symbol details."""
    _execute_export(
        ctx,
        lambda c: c.symbol_info_as_df(symbol=symbol),
    )

symbols

symbols(
    ctx: Context,
    group: Annotated[
        str | None,
        Option(help="Symbol group filter (e.g., *USD*)."),
    ] = None,
) -> None

Export symbol list.

Source code in mt5cli/cli.py
@app.command()
def symbols(
    ctx: typer.Context,
    group: Annotated[
        str | None,
        typer.Option(help="Symbol group filter (e.g., *USD*)."),
    ] = None,
) -> None:
    """Export symbol list."""
    _execute_export(
        ctx,
        lambda c: c.symbols_get_as_df(group=group),
    )

terminal_info

terminal_info(ctx: Context) -> None

Export terminal information.

Source code in mt5cli/cli.py
@app.command()
def terminal_info(ctx: typer.Context) -> None:
    """Export terminal information."""
    _execute_export(ctx, lambda c: c.terminal_info_as_df())

ticks_from

ticks_from(
    ctx: Context,
    symbol: Annotated[str, Option(help="Symbol name.")],
    date_from: Annotated[
        datetime,
        Option(
            click_type=DATETIME_TYPE, help="Start date."
        ),
    ],
    count: Annotated[int, Option(help="Number of ticks.")],
    flags: Annotated[
        int,
        Option(
            click_type=TICK_FLAGS_TYPE,
            help="Tick flags (ALL, INFO, TRADE, or integer).",
        ),
    ],
) -> None

Export ticks from a start date.

Source code in mt5cli/cli.py
@app.command()
def ticks_from(
    ctx: typer.Context,
    symbol: Annotated[str, typer.Option(help="Symbol name.")],
    date_from: Annotated[
        datetime,
        typer.Option(click_type=DATETIME_TYPE, help="Start date."),
    ],
    count: Annotated[int, typer.Option(help="Number of ticks.")],
    flags: Annotated[
        int,
        typer.Option(
            click_type=TICK_FLAGS_TYPE,
            help="Tick flags (ALL, INFO, TRADE, or integer).",
        ),
    ],
) -> None:
    """Export ticks from a start date."""
    _execute_export(
        ctx,
        lambda c: c.copy_ticks_from_as_df(
            symbol=symbol,
            date_from=date_from,
            count=count,
            flags=flags,
        ),
    )

ticks_range

ticks_range(
    ctx: Context,
    symbol: Annotated[str, Option(help="Symbol name.")],
    date_from: Annotated[
        datetime,
        Option(
            click_type=DATETIME_TYPE, help="Start date."
        ),
    ],
    date_to: Annotated[
        datetime,
        Option(click_type=DATETIME_TYPE, help="End date."),
    ],
    flags: Annotated[
        int,
        Option(
            click_type=TICK_FLAGS_TYPE, help="Tick flags."
        ),
    ],
) -> None

Export ticks for a date range.

Source code in mt5cli/cli.py
@app.command()
def ticks_range(
    ctx: typer.Context,
    symbol: Annotated[str, typer.Option(help="Symbol name.")],
    date_from: Annotated[
        datetime,
        typer.Option(click_type=DATETIME_TYPE, help="Start date."),
    ],
    date_to: Annotated[
        datetime,
        typer.Option(click_type=DATETIME_TYPE, help="End date."),
    ],
    flags: Annotated[
        int,
        typer.Option(click_type=TICK_FLAGS_TYPE, help="Tick flags."),
    ],
) -> None:
    """Export ticks for a date range."""
    _execute_export(
        ctx,
        lambda c: c.copy_ticks_range_as_df(
            symbol=symbol,
            date_from=date_from,
            date_to=date_to,
            flags=flags,
        ),
    )