Command-line tool for MetaTrader 5
Project description
mt5cli
Command-line tool for exporting MetaTrader 5 data to CSV, JSON, Parquet, and SQLite3.
Built on top of pdmt5, a pandas-based data handler for MetaTrader 5.
Architecture
- pdmt5 — canonical MT5 client, DataFrame/trading primitives, and MT5 constant parsing (
TIMEFRAME_*,COPY_TICKS_*, order types). - mt5cli — CLI commands, CSV/JSON/Parquet/SQLite export, SQLite history collection, rate views, and local batch/automation SDK helpers built on pdmt5.
- mt5api — sibling HTTP adapter for remote MT5 access; not a dependency of mt5cli.
Features
- Multi-format export: CSV, JSON, Parquet, and SQLite3 output formats
- Auto-detection: Format detection from file extensions
- Comprehensive data access: Rates, ticks, account info, symbols, orders, positions, and trading history
- Flexible timeframes: Named timeframes (M1, H1, D1, etc.) and numeric values
- Connection management: Optional credentials, server, and timeout configuration
- SQLite rate loading: Load mt5cli-managed rate tables/views for offline workflows
Installation
pip install -U mt5cli MetaTrader5
Usage
# Export account information to CSV
mt5cli -o account.csv account-info
# Export EURUSD M1 rates to Parquet
mt5cli -o rates.parquet rates-from --symbol EURUSD --timeframe M1 \
--date-from 2024-01-01 --count 1000
# Export ticks to JSON
mt5cli -o ticks.json ticks-from --symbol EURUSD \
--date-from 2024-01-01 --count 500 --flags ALL
# Export symbols to SQLite3 with custom table name
mt5cli -o data.db --table symbols symbols --group "*USD*"
# Export with connection credentials
mt5cli --login 12345 --password mypass --server MyBroker-Demo \
-o positions.csv positions
Run as a Python module:
python -m mt5cli -o account.csv account-info
Commands
| Command | Description |
|---|---|
rates-from |
Export rates from a start date |
rates-from-pos |
Export rates from a start position |
latest-rates |
Export latest rates from a start position |
rates-range |
Export rates for a date range |
ticks-from |
Export ticks from a start date |
ticks-range |
Export ticks for a date range |
ticks-recent |
Export ticks from a recent trailing window |
account-info |
Export account information |
terminal-info |
Export terminal information |
version |
Export MetaTrader 5 version information |
last-error |
Export the last error information |
symbols |
Export symbol list |
symbol-info |
Export symbol details |
symbol-info-tick |
Export the last tick for a symbol |
minimum-margins |
Export minimum-volume buy and sell margin requirements |
market-book |
Export market depth (order book) |
orders |
Export active orders |
positions |
Export open positions |
history-orders |
Export historical orders |
history-deals |
Export historical deals |
recent-history-deals |
Export historical deals from a recent trailing window |
mt5-summary |
Export terminal/account status summary |
order-check |
Check funds sufficiency for a trade request |
order-send |
Send a trade request to the trade server (--yes required) |
collect-history |
Bundle rates, ticks, history-orders, and history-deals for one or more symbols into a single SQLite database |
Use order-check to validate a request payload before running order-send --yes.
collect-history
Collect several historical datasets per symbol into one SQLite database in a single MT5 session. Pick datasets with repeatable --dataset (default: all four), choose conflict behavior with --if-exists append|replace|fail (default: fail), and optionally derive cash_events / positions_reconstructed views from history_deals via --with-views.
mt5cli -o history.db collect-history \
--symbol EURUSD --symbol GBPUSD \
--date-from 2024-01-01 --date-to 2024-02-01 \
--dataset rates --dataset history-deals \
--timeframe M1 --flags ALL --if-exists append --with-views
History orders and deals are fetched per symbol and concatenated, so the symbol filter is applied consistently across all datasets. The cash_events view is derived from symbol-filtered history_deals, so account-level cash events with empty or non-matching symbols may be excluded. The rates table records the requested timeframe so appended runs at different timeframes remain distinguishable. The positions_reconstructed view aggregates trade deals by position_id, excludes positions without closing-side entries, and uses volume-weighted open/close prices; reversal deals (DEAL_ENTRY_INOUT) are reported via volume_reversal / reversal_count columns.
Incremental history SDK
For automated pipelines, use the importable incremental API instead of re-fetching fixed date ranges:
from pdmt5 import Mt5Config, Mt5DataClient
from mt5cli import Dataset, update_history, update_history_with_config
# Reuse an already-connected pdmt5 client (does not open/close MT5)
client = Mt5DataClient(config=Mt5Config(login=12345))
client.initialize_and_login_mt5()
try:
update_history(
client=client,
output="history.db",
symbols=["EURUSD", "GBPUSD"],
datasets={Dataset.rates, Dataset.history_deals},
timeframes=["M1", "H1"], # default: all fixed MT5 timeframes
lookback_hours=24,
create_rate_views=True,
with_views=True,
include_account_events=True,
)
finally:
client.shutdown()
# Standalone wrapper that opens and closes MT5 for you
update_history_with_config(
output="history.db",
symbols=["EURUSD"],
config=Mt5Config(login=12345),
)
collect-history: explicit date-range export into SQLite.update_history: incremental append based on existing SQLiteMAX(time)per symbol (and timeframe for rates); account-level deals use a separate cursor wheninclude_account_events=True.ratestable: normalized storage withsymbolandtimeframecolumns.- Rate compatibility views: mt5cli manages all
rate_*views. Naming israte_<symbol>__<timeframe>when a symbol has one timeframe, otherwiserate_<symbol>__<granularity>_<timeframe>(for examplerate_EURUSD__M1_1). Stalerate_*views are dropped and recreated when rates change for offline tools such as mteor optimize. - Rate view resolution: use
resolve_rate_view_name()/resolve_rate_view_names()to map symbols and granularities to existing SQLite compatibility views without creating databases. Both acceptNone(or a missing path) and return deterministic default names unlessrequire_existing=True. - Rate view loading: use
load_rate_data()/load_rate_data_from_connection()to load a SQLite rate table or view into aDatetimeIndexDataFrame. - Multi-series rate loading: use
build_rate_targets()to build neutralRateTarget(symbol, timeframe)pairs,resolve_rate_tables()to map them to table/view names (passrequire_existing=Truefor strict resolution), andload_rate_series_from_sqlite()to load them into a mapping keyed by(symbol, integer timeframe). The loader requires existing managed views unlessexplicit_tablesis supplied, and rejects duplicate(symbol, timeframe)targets. - Multi-account latest rates: use
collect_latest_rates_for_accounts()withAccountSpecto read the latest bars for several account groups, merged into a(symbol, integer timeframe)mapping. For long-running pollers,collect_latest_rates_for_accounts_with_retries()adds bounded exponential backoff that retries onlypdmt5.Mt5TradingError/pdmt5.Mt5RuntimeErrorand re-raises onceretry_countis exhausted. - Latest closed bars: use
collect_latest_closed_rates_for_accounts()when downstream logic must exclude the still-forming current bar. It fetchescount + 1bars atstart_pos=0, drops the last row withdrop_forming_rate_bar(), and validates each series is non-empty.collect_latest_closed_rates_by_granularity()returns the same data keyed by(symbol, granularity_name)such as("EURUSD", "M1").
from mt5cli import AccountSpec, collect_latest_closed_rates_by_granularity
rates = collect_latest_closed_rates_by_granularity(
[AccountSpec(symbols=["EURUSD", "GBPUSD"], login=12345)],
["M1", "H1"],
count=500,
retry_count=3,
)
eurusd_m1 = rates["EURUSD", "M1"] # closed bars only
- Credential resolution: use
resolve_account_spec()/resolve_account_specs()to merge explicit override values overAccountSpecfields and expand${ENV_VAR}placeholders (viasubstitute_env_placeholders()), raisingValueErrorfor missing variables. This keeps secrets out of plan/config files without coupling to any strategy code. - Throttled history updates: use
ThrottledHistoryUpdaterto wrapupdate_history()with a minimuminterval_secondsbetween successful runs (monotonic clock). Callshould_update()/update(client, symbols)from an application loop; errors propagate by default, or passsuppress_errors=Trueto swallow recoverableMt5*Error,sqlite3.Error,ValueError,OSError, and MT5 client capability errors for history API methods without advancing the throttle (otherAttributeError/TypeErrorvalues always propagate). - Trading session helpers: use
mt5_trading_session()for a trading-capablepdmt5.Mt5TradingClientthat initializes/logs in viaMt5Config.pathand always shuts down safely. Pair withdetect_position_side(),calculate_margin_and_volume(), anddetermine_order_limits()for generic position and sizing utilities. The read-onlymt5_session()/Mt5CliClientSDK is unchanged. - Granularity-keyed rate loading:
load_rate_series_by_granularity()builds targets withbuild_rate_targets(), loads them withload_rate_series_from_sqlite(), and returns a mapping keyed by(symbol | None, granularity_name)such as("EURUSD", "M1")to reduce downstream boilerplate. - MT5 session helper: use the
mt5_session()context manager to attach to (or, whenMt5Config.pathis set, launch) an MT5 terminal, log in, and yield a connectedMt5CliClientthat shuts down on exit. - SQLite export helpers: use
export_dataframe_to_sqlite()for append mode, optional index export, and post-write deduplication by key columns. - Recent ticks and margins:
recent_ticks()andminimum_margins()SDK helpers (and matching CLI commands) cover common downstream read-only queries.
Requirements
- Python 3.11+
- Windows OS (MetaTrader 5 requirement)
- MetaTrader 5 platform installed
Migration note for mteor
Replace local MT5 lifecycle and trading helper code with mt5cli imports:
# Before (local mteor helpers)
# with local_mt5_trading_session(config) as client:
# side = local_detect_position_side(client, symbol)
# sizing = local_calculate_margin_and_volume(client, symbol, unit_ratio, preserved_ratio)
# limits = local_determine_order_limits(client, symbol, side, sl_ratio, tp_ratio)
# After (mt5cli shared layer)
from pdmt5 import Mt5Config
from mt5cli import (
calculate_margin_and_volume,
detect_position_side,
determine_order_limits,
mt5_trading_session,
)
with mt5_trading_session(
Mt5Config(path=terminal_path, login=login), retry_count=2
) as client:
side = detect_position_side(client, symbol)
sizing = calculate_margin_and_volume(
client, symbol, unit_margin_ratio=0.5, preserved_margin_ratio=0.2
)
if side is not None:
limits = determine_order_limits(
client,
symbol,
side,
stop_loss_limit_ratio=0.01,
take_profit_limit_ratio=0.02,
)
Throttled history updates use a separate read-only session:
from pdmt5 import Mt5Config, Mt5DataClient
from mt5cli import ThrottledHistoryUpdater
updater = ThrottledHistoryUpdater(
output="history.db", interval_seconds=60, suppress_errors=True
)
client = Mt5DataClient(config=Mt5Config(login=login))
client.initialize_and_login_mt5()
try:
updater.update(client, ["EURUSD"])
finally:
client.shutdown()
Read-only collectors can keep using mt5_session() and Mt5CliClient without changes.
Development
git clone https://github.com/dceoy/mt5cli.git
cd mt5cli
uv sync
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mt5cli-0.7.0.tar.gz.
File metadata
- Download URL: mt5cli-0.7.0.tar.gz
- Upload date:
- Size: 149.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
738472bfb0fe4821e7ba683310fd4664ef66366eaa65fe812a5a06d9f796f544
|
|
| MD5 |
6bd95ca5adc1367de57dda7799b99d59
|
|
| BLAKE2b-256 |
85a2e5ba62012cca25cd18ceecad9b470f0e69b0d20740e4232ace63ecde7a99
|
Provenance
The following attestation bundles were made for mt5cli-0.7.0.tar.gz:
Publisher:
release.yml on dceoy/mt5cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mt5cli-0.7.0.tar.gz -
Subject digest:
738472bfb0fe4821e7ba683310fd4664ef66366eaa65fe812a5a06d9f796f544 - Sigstore transparency entry: 1790556771
- Sigstore integration time:
-
Permalink:
dceoy/mt5cli@0fad55d609d4e1db98f90006c755606dde5abeae -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/dceoy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0fad55d609d4e1db98f90006c755606dde5abeae -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file mt5cli-0.7.0-py3-none-any.whl.
File metadata
- Download URL: mt5cli-0.7.0-py3-none-any.whl
- Upload date:
- Size: 42.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d4c58d83df821190f8f558a503d51cac24d7ca5a2909d66d36b71e471b2e3077
|
|
| MD5 |
e3e30363fff98ebf93a28bf633cfd857
|
|
| BLAKE2b-256 |
ace4028d17b030ddd8fa659f35db736934ba247e41a57690abcadbbaaf716187
|
Provenance
The following attestation bundles were made for mt5cli-0.7.0-py3-none-any.whl:
Publisher:
release.yml on dceoy/mt5cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mt5cli-0.7.0-py3-none-any.whl -
Subject digest:
d4c58d83df821190f8f558a503d51cac24d7ca5a2909d66d36b71e471b2e3077 - Sigstore transparency entry: 1790556817
- Sigstore integration time:
-
Permalink:
dceoy/mt5cli@0fad55d609d4e1db98f90006c755606dde5abeae -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/dceoy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@0fad55d609d4e1db98f90006c755606dde5abeae -
Trigger Event:
workflow_dispatch
-
Statement type: