從手機發送一則訊息,看著它同時在多個 MetaTrader 4 終端機上作為即時交易執行 — 這正是 ApexCopier 所做的事。本文介紹我們如何建立它、架構背後的設計決策,以及使其運作的關鍵程式碼。
現成解決方案的問題 #
市面上大多數 Telegram 到 MT4 的複製工具都是編譯好的黑盒子 — 沒有原始碼、沒有彈性的 .exe 連接器和 .ex4 EA。如果出現問題或想自訂訊號格式,就束手無策了。
我們想要的是不同的東西:一個完全透明、精簡的系統,建立在我們端對端完全掌控的清晰訊號格式上。沒有不必要的依賴項,沒有在背景執行的神秘檔案 — 只有一個 Python 腳本、一個 CSV 檔案,以及一個完全按照我們指示執行的 MQL4 Expert Advisor。
第一部分 — 連接器:從 Telegram 到檔案 #
連接器是一個與 MT4 並行執行的 Python 腳本,充當 Telegram 頻道和交易終端機之間的橋樑。它使用 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 |
掛單 |
我們的解析器處理簡單的單字母訊號和包含商品、方向、進場類型與價格水準的完整結構化訊號 — 全部在一個函式中完成,除了訊息文字本身外沒有任何外部依賴。
重要的架構說明:每台執行 MT4 的機器都有自己專用的機器人 Token。Telegram Bot API 每個 Token 只允許一個活躍的輪詢連接,因此在兩台機器上使用相同 Token 執行連接器會導致 409 衝突。解決方案很簡單 — 建立第二個機器人,將其添加為同一頻道的管理員,並將其分配給第二台機器。兩個機器人都獨立接收每個訊號。
第二部分 — IPC 橋接:以 CSV 檔案作為訊號 #
MT4 是一個沙盒環境。Expert Advisor 只能在自己的 MQL4/Files/ 資料夾中讀寫檔案 — 外部程序無法直接將資料推送到執行中的 EA。標準解決方案是基於檔案的跨程序通訊,而 CSV 是最易讀的格式。
連接器寫入的每個訊號都成為一行:
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 在獨立的 last_processed.txt 檔案中追蹤最後處理的訊號 ID — 每次計時器觸發時只讀取尚未處理的行,執行它們並更新指標。這意味著任意一側的重啟都是安全的: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}")
每個終端機完全獨立地從自己的檔案副本中讀取。
第三部分 — Expert Advisor:在 MT4 內執行 #
EA 設計得刻意精簡。它沒有自己的交易邏輯 — 只是讀取訊號並執行它們。使用一秒計時器取代 OnTick() 以最小化 CPU 使用率,避免在每次價格更新時進行不必要的處理。
void OnTimer() { ProcessSignals(); }
完整訊號的手數計算支援三種由 EA 輸入控制的模式:固定手數、帳戶權益的百分比或固定美元風險金額。當基於風險的模式啟用時,手數的計算方式是使止損觸發的成本恰好等於指定金額:
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 最終約有 200 行 Python 和 150 行 MQL4 — 小到可以完全理解,靈活到足以持續成長。