スマートフォンから1つのメッセージを送信し、それが複数のMetaTrader 4端末でリアルタイムのトレードとして即座に実行される — それがApexCopierの仕組みです。この記事では、システムの構築方法、アーキテクチャの背後にある意思決定、そして動作の核となるコードを解説します。
既製ソリューションの問題点 #
市場に出回っているTelegramからMT4へのコピーツールのほとんどは、コンパイル済みのブラックボックスとして提供されています — ソースコードなし、カスタマイズ不可の .exe コネクターと .ex4 EA です。何か問題が発生したり、シグナル形式を変更したい場合でも、手の打ちようがありません。
私たちが求めたのは異なるものです。エンド・ツー・エンドで完全にコントロールできる、透明性の高いミニマルなシステムです。不要な依存関係なし、バックグラウンドで動く謎のファイルなし — Pythonスクリプト、CSVファイル、そして指示通りに動くMQL4 Expert Advisorだけです。
パート1 — コネクター:TelegramからファイルへのブリッジRecibir #
コネクターはMT4と並行して動作するPythonスクリプトで、TelegramチャンネルとMT4端末の橋渡しをします。Telegram Bot APIを使用します — @BotFatherでボットを作成し、プライベートチャンネルに管理者として追加すると、そのチャンネルに投稿されたすべてのメッセージをリアルタイムで受信できます。
@bot.channel_post_handler(func=lambda msg: True)
def on_channel_post(message):
text = message.text or message.caption or ""
signal = sig_parser.parse(text)
if signal is None:
print(f"[skip] Not a valid signal: {repr(text)}")
return
sig_id = writer.append(signal, MT4_FILES_PATHS, COUNTER_FILE)
メッセージが届くと、パーサーに渡されます。有効なシグナルはMT4のサンドボックス環境内の MQL4/Files/ フォルダーにある signals.csv に行として書き込まれます。無効なメッセージは静かにスキップされます。
シグナル形式は人間に使いやすく、素早く入力できるよう設計されており、様々なニーズに合わせてカスタマイズできます:
| メッセージ | アクション |
|---|---|
L |
ロングポジション |
S |
ショートポジション |
C |
全ポジションクローズ |
EURUSD BUY MARKET TP:1.0950 SL:1.0800 |
成行注文(フル) |
EURUSD SELL LIMIT 1.0820 TP:1.0750 SL:1.0870 |
指値注文 |
私たちのパーサーは、1文字のシンプルなシグナルと、シンボル・方向・エントリータイプ・価格レベルを含む完全な構造化シグナルの両方を、メッセージテキスト以外の外部依存なしで単一の関数で処理します。
重要なアーキテクチャの注意点:MT4を動かす各マシンには専用のボットトークンが必要です。Telegram Bot APIはトークンごとに1つのアクティブなポーリング接続しか許可しないため、2台のマシンで同じトークンを使用すると409コンフリクトが発生します。解決策はシンプルです — 2つ目のボットを作成し、同じチャンネルに管理者として追加し、2台目のマシンに割り当てます。両方のボットが各シグナルを独立して受信します。
パート2 — IPCブリッジ:CSVファイルとしてのシグナル #
MT4はサンドボックス環境です。Expert Advisorは自身の MQL4/Files/ フォルダー内のファイルしか読み書きできません。外部プロセスから実行中のEAに直接データをプッシュする方法はありません。標準的な解決策はファイルベースのプロセス間通信であり、CSVは最も読みやすいフォーマットです。
コネクターによって書き込まれた各シグナルは1行になります:
id, timestamp, type, symbol, direction, entry_type, entry_price, sl, tp
1, 2026-04-20 23:15:00, SIMPLE, , BUY, MARKET, 0.00000, 0.00000, 0.00000
2, 2026-04-20 23:31:00, FULL, EURUSD, SELL, MARKET, 0.00000, 1.08700, 1.07500
コネクターは行を追加するだけで、既存の行を変更しません。EAは処理した最後のシグナルIDを別ファイル last_processed.txt に記録します — タイマーティックごとに未処理の行のみを読み込み、実行し、ポインターを更新します。これにより、どちら側が再起動しても安全です:EAがシグナルを二重実行することはなく、コネクターが履歴を上書きすることもありません。
同一マシン上の複数のMT4インスタンスに対しては、コネクターが同じ行を複数のパスに同時に書き込みます:
for path in MT4_FILES_PATHS:
signals_file = os.path.join(path, "signals.csv")
try:
_write_row(signals_file, row, header)
except OSError as e:
print(f"[warn] Could not write to {signals_file}: {e}")
各端末は自身のファイルコピーから完全に独立して読み込みます。
パート3 — Expert Advisor:MT4内での実行 #
EAは意図的にシンプルに設計されています。独自のトレードロジックは持たず、シグナルを読み込んで実行するだけです。OnTick() の代わりに1秒タイマーを使用し、CPUの使用を最小限に抑え、価格更新ごとの不要な処理を避けます。
void OnTimer() { ProcessSignals(); }
フルシグナルのロットサイズ計算はEAの入力パラメーターで制御される3つのモードをサポートします:固定ロット、口座エクイティのパーセンテージ、または固定ドルリスク額。リスクベースのモードが有効な場合、ストップロスにヒットしたときに正確に指定された額のコストがかかるようにロットが計算されます:
double slPoints = MathAbs(entryPrice - sl) / MarketInfo(symbol, MODE_POINT);
double tickValue = MarketInfo(symbol, MODE_TICKVALUE);
double lot = NormalizeDouble(riskAmount / (slPoints * tickValue), lotDecimals);
EAは初期化時にカスタムチャートテーマも適用します — 黒背景、白の陽線、そしてTelegramのシグネチャブルー(#2AABEE)の陰線と前景要素 — これにより手動設定なしで一貫したダークな外観が得られます。
シグナルタイプはEAの入力で個別に切り替え可能です。つまり、同じチャンネルが異なる設定の端末に対応できます:パーセンテージリスクのフルシグナルを取引する端末と、固定ロットで L/S/C コマンドのみに応答する端末。各端末は独自のマジックナンバー、ロット設定、有効/無効スイッチを持ちます。
ApexCopierはPythonで約200行、MQL4で約150行 — 完全に理解できるほど小さく、成長できるほど柔軟です。