TradeMux как Quant Backbone: Подключение институциональных Python-пайплайнов к разным терминалам и брокерам
Введение
Профессиональный quant-разработчик пишет на MQL5 и Python — и каждый язык решает свою задачу. Python — среда исследования: данные, модели, бэктесты, факторные пайплайны, риск-расчёты. MQL5 и MetaTrader 5 — среда исполнения: брокерский коннект, торговый сервер, нативная скорость обработки ордеров. Задача одна: соединить их чисто и надёжно, не дублируя логику на двух сторонах.
TradeMux — инфраструктурный мост между Python-пайплайном и терминалом MetaTrader 5. Он не подменяет ни исследовательскую экосистему Python, ни MQL5-движок исполнения MetaTrader 5 — он устраняет операционный разрыв между ними. Python генерирует сигнал, TradeMux доставляет его в терминал, MetaTrader 5 исполняет ордер у брокера. Помимо этого, TradeMux берёт на себя кросс-брокерную нормализацию: один и тот же Python-код работает через RoboForex, IC Markets, Alpari и OANDA без единого изменения в логике.
После прочтения статьи в вашем распоряжении окажется полноценный Python-сервис исполнения (execution service). Он включает:
- подключение к MetaTrader 5 через TradeMux Python SDK с единственным API-ключом;
- чтение состояния счёта и открытых позиций через нормализованный интерфейс;
- генерацию сигналов из Python-пайплайна с интеграцией CatBoost-модели на L1-признаках;
- исполнение рыночных ордеров с предторговым риск-контролем в Python;
- мониторинг открытых позиций и аварийное закрытие через kill_switch();
- мультисчётный broadcast одного сигнала на несколько терминалов MetaTrader 5;
- supervisor-паттерн с автоматическим перезапуском после аварийных событий.
Две среды — два назначения
Python и MetaTrader 5 решают разные задачи, и это разделение не случайно — оно отражает реальную структуру quant-разработки.
Python — среда исследования и расчётов. pandas и numpy обеспечивают векторизованную обработку временных рядов: загрузку 45 000 баров H1 по 29 инструментам, каузальную (без look-ahead) L1-фильтрацию через ADMM и построение пространства признаков. Всё это можно реализовать в одном пайплайне. scikit-learn, CatBoost, LightGBM и PyTorch дополняются Optuna (байесовская оптимизация) и SHAP (интерпретируемость). Экосистема ML-инструментов постоянно обновляется. Backtesting-фреймворки, walk-forward validation с purge+embargo по López de Prado, параметрическая VaR-аллокация на мультиинструментальный портфель — всё это Python-нативные задачи, решаемые в рамках единого исследовательского стека.
MetaTrader 5 — среда исполнения сделок. MetaTrader 5 обеспечивает прямой коннект к торговому серверу брокера, нативную скорость обработки ордеров, встроенное управление позициями и полный доступ к котировочному потоку. Это зрелая, проверенная платформа с широчайшим брокерским покрытием, которую используют миллионы трейдеров по всему миру.
TradeMux — мост между этими двумя средами. Он позволяет Python-системе управлять терминалом MetaTrader 5 через нормализованный SDK, не требуя дублирования исследовательской логики на стороне терминала. Python считает, TradeMux доставляет, MetaTrader 5 исполняет.
Практическая архитектура
Производственная архитектура для Python-нативной quant-системы состоит из четырёх слоёв с чёткими зонами ответственности.
Слой 1: Research & Signal Engine (Python). Jupyter-ноутбуки и Python-скрипты, где живут данные, модели и бэктесты. Этот слой генерирует торговые решения: {symbol: direction, lot, confidence}. Он работает с историческими данными, строит признаки, обучает модели и производит все расчёты — от L1-фильтрации до VaR-аллокации лотов.
Слой 2: Execution Service (Python). Лёгкий Python-процесс, который принимает сигналы от signal engine и управляет жизненным циклом позиций. Он инкапсулирует предторговые риск-проверки, логику входа и выхода, мониторинг открытых позиций и аварийные защиты. Весь этот код — Python, под полным инженерным контролем разработчика.
Слой 3: TradeMux SDK/API (мост). Нормализованный интерфейс между execution service и терминалом MetaTrader 5. Python вызывает методы SDK — TradeMux транслирует их в команды для EA. Этот слой абстрагирует брокерскую специфику: символьные суффиксы, минимальные лоты, шаг лота, режимы исполнения. Один и тот же Python-код работает с любым подключённым брокером.
Слой 4: MetaTrader 5 Terminal + TradeMux EA (исполнение). MetaTrader 5 с прикреплённым TradeMux EA на любом графике. EA принимает команды через цикл WebRequest и исполняет их нативными торговыми функциями MetaTrader 5. Zero-DLL архитектура: никаких сторонних библиотек, никаких проблем с безопасностью на VPS.
# Схема архитектуры
#
# ┌─────────────────────────────────────────────────────┐
# │ PYTHON — Research / Signal Engine │
# │ pandas · CatBoost · L1 Filter · VaR Alloc │
# └──────────────────────┬──────────────────────────────┘
# │ {symbol, direction, lots}
# ┌──────────────────────▼──────────────────────────────┐
# │ PYTHON — Execution Service │
# │ pre-trade risk · monitor · kill_switch() │
# └──────────────────────┬──────────────────────────────┘
# │ SDK calls
# ┌──────────────────────▼──────────────────────────────┐
# │ TRADEMUX — SDK / API Bridge │
# │ normalized schemas · broker abstraction │
# └──────────────────────┬──────────────────────────────┘
# │ WebRequest loop (zero DLL)
# ┌──────────────────────▼──────────────────────────────┐
# │ MetaTrader 5 — Terminal + TradeMux EA │
# │ native execution · full broker connectivity │
# └──────────────────────┬──────────────────────────────┘
# │
# ┌──────────────────────▼──────────────────────────────┐
# │ Broker A / Broker B / Broker C │
# │ RoboForex · IC Markets · Alpari · OANDA · … │
# └─────────────────────────────────────────────────────┘
Настройка на стороне MetaTrader 5: один EA, ноль торговой логики
На стороне MetaTrader 5 настройка состоит из трёх шагов. Первый: скачать и установить TradeMux EA из маркетплейса или с официального сайта. Второй: в настройках MetaTrader 5 разрешить WebRequest для домена TradeMux API — Tools → Options → Expert Advisors → Allow WebRequest for listed URL. Третий: прикрепить EA к любому графику и ввести API-ключ в параметрах входа.
TradeMux EA выполняет ровно одну функцию: принимает команды от Python через цикл WebRequest и передаёт их нативным торговым функциям MetaTrader 5. Мост работает полностью без DLL-зависимостей — это ключевое архитектурное решение, которое обеспечивает безопасность на VPS и совместимость с любыми брокерскими конфигурациями. Вся стратегическая логика — расчёты, модели, риск-контроль — остаётся в Python.
Подключение и чтение состояния счёта
Инициализация клиента — единственная точка входа в TradeMux SDK. Метод get_account_info() возвращает нормализованную структуру: поля одинаковы для MetaTrader 4/MetaTrader 5 и не зависят от брокера (в т.ч. OANDA). Это принципиально важно для мультисчётных операций — один и тот же Python-код читает счёт в RoboForex и IC Markets без каких-либо изменений.
import time import logging import numpy as np import pandas as pd from trademux import TradeMuxClient # ─── Конфигурация ──────────────────────────────────────────────── API_KEY = "tm_live_xxxxxxxxxxxxxxxxxxxx" ACCOUNT_ID = "RBF-123456" BASE_URL = "https://api.trademux.io/v1" MAX_DRAWDOWN_USD = 300.0 # абсолютный стоп на просадку счёта MAX_OPEN_LOTS = 2.0 # суммарный лот по всем позициям EQUITY_HIGH_MARK = 0.0 # обновляется после первого чтения счёта SYMBOLS = [ "EURUSD", "GBPUSD", "USDJPY", "USDCHF", "AUDUSD", "USDCAD", "NZDUSD", "EURGBP", ] logging.basicConfig( level=logging.INFO, format="%(asctime)s | %(levelname)-8s | %(message)s", datefmt="%Y-%m-%d %H:%M:%S", ) log = logging.getLogger("trademux_service") def init_client() -> TradeMuxClient: """Создаёт клиент TradeMux и выводит начальное состояние счёта.""" client = TradeMuxClient( api_key=API_KEY, account_id=ACCOUNT_ID, base_url=BASE_URL, ) info = client.get_account_info() log.info( "Connected | Balance=%.2f %s | Equity=%.2f | Margin=%.1f%%", info["balance"], info["currency"], info["equity"], info["margin_level"], ) return client def snapshot_account(client: TradeMuxClient) -> dict: """Возвращает текущий снимок счёта и открытых позиций.""" info = client.get_account_info() positions = client.get_positions() open_lots = sum(p["lots"] for p in positions) float_pnl = sum(p["profit"] for p in positions) return { "balance" : info["balance"], "equity" : info["equity"], "margin_level": info["margin_level"], "open_lots" : open_lots, "float_pnl" : float_pnl, "positions" : positions, "n_positions" : len(positions), }
Метод get_positions() возвращает список словарей с полями ticket, symbol, type, lots, open_price, profit — нормализованный формат, одинаковый для всех брокеров. Это позволяет строить мониторинг и риск-логику в Python один раз и применять её к любому подключённому терминалу без адаптации.
Загрузка рыночных данных через SDK
Метод get_ohlc() возвращает исторические бары из MetaTrader 5 напрямую в Python-процесс. TradeMux транслирует запрос через EA и возвращает нормализованный массив OHLCV. Таймфрейм, количество баров и символ — параметры SDK. Полученный DataFrame передаётся непосредственно в функцию генерации признаков: Python получает данные из MetaTrader 5 и тут же применяет к ним полный исследовательский пайплайн.
def fetch_ohlc_dataframe( client: TradeMuxClient, symbol: str, timeframe: str = "H1", bars: int = 200, ) -> pd.DataFrame: """Загружает OHLC из MetaTrader 5 через TradeMux SDK и возвращает DataFrame.""" raw = client.get_ohlc(symbol=symbol, timeframe=timeframe, bars=bars) df = pd.DataFrame(raw, columns=["time", "open", "high", "low", "close", "volume"]) df["time"] = pd.to_datetime(df["time"], unit="s", utc=True) df.set_index("time", inplace=True) return df
Если сигнальная логика построена на L1 Trend Filter, следующий шаг — каузальная (без look-ahead) фильтрация скользящим окном на полученных ценах закрытия, затем построение признаков и предсказание CatBoost-модели. Вся эта цепочка остаётся в Python. MetaTrader 5 предоставляет данные котировок через TradeMux и принимает команды на исполнение — это его роль в архитектуре.
Сигнальная логика: Python считает, MetaTrader 5 исполняет
Генерация торгового сигнала происходит полностью внутри Python. Расчётная часть — ML-модель, L1-фильтр, факторный пайплайн — не покидает Python-процесс. TradeMux принимает уже готовое торговое решение и доставляет его в MetaTrader 5. Ниже показан пример momentum-сигнала на основе OHLC-данных; в production-системе здесь стоит CatBoost с L1-фильтрованными признаками — интерфейс функции остаётся тем же.
def compute_signal(df: pd.DataFrame) -> str: """ Momentum-сигнал на основе MACD + наклона тренда. В production: заменить на ML-предсказание CatBoost. Возвращает: 'BUY' | 'SELL' | 'HOLD' """ close = df["close"] ema_fast = close.ewm(span=12, adjust=False).mean() ema_slow = close.ewm(span=26, adjust=False).mean() macd = ema_fast - ema_slow signal = macd.ewm(span=9, adjust=False).mean() # Фильтр направления тренда за последние 20 баров slope_20 = (close.iloc[-1] - close.iloc[-21]) / close.iloc[-21] macd_val = macd.iloc[-1] sig_val = signal.iloc[-1] cross_up = macd_val > sig_val and macd.iloc[-2] <= signal.iloc[-2] cross_dn = macd_val < sig_val and macd.iloc[-2] >= signal.iloc[-2] if cross_up and slope_20 > 0: return "BUY" elif cross_dn and slope_20 < 0: return "SELL" return "HOLD" def generate_signals( client: TradeMuxClient, symbols: list[str], ) -> dict[str, str]: """Генерирует сигналы по всему списку символов.""" signals = {} for sym in symbols: try: df = fetch_ohlc_dataframe(client, sym) signals[sym] = compute_signal(df) except Exception as e: log.warning("Signal error %s: %s", sym, e) signals[sym] = "HOLD" return signals
Интеграция CatBoost-модели: drop-in замена сигнальной функции
В production-системе функция compute_signal заменяется на вызов предобученной модели. Класс-обёртка ниже имеет идентичный интерфейс — DataFrame на входе, строка на выходе. Модель загружается один раз при старте сервиса; пересчёт признаков происходит на каждом сигнальном цикле на свежих данных из get_ohlc(). Веса модели, инженерия признаков, пороги уверенности — всё это остаётся в Python-коде под полным контролем разработчика.
from catboost import CatBoostClassifier, Pool import joblib class CatBoostSignalEngine: """ Production-wrapper для CatBoost-модели на L1-признаках. Drop-in замена для compute_signal() — тот же интерфейс. """ FEATURE_COLS = [ "ret_1", "ret_3", "ret_5", "ret_10", "ret_20", "l1_slope", "l1_accel", "l1_trend_up", "l1_trend_chg", "deviation", "dev_pct", "vol_5", "vol_10", "vol_20", "rsi_l1_14", "rsi_close_14", "bb_pos_10", "bb_pos_20", ] LONG_THR = 0.58 # порог уверенности для BUY SHORT_THR = 0.58 # порог уверенности для SELL def __init__(self, model_path: str): self.model: CatBoostClassifier = joblib.load(model_path) log.info("CatBoost model loaded from %s", model_path) def __call__(self, df: pd.DataFrame) -> str: """Возвращает 'BUY' | 'SELL' | 'HOLD' по последней строке DataFrame.""" row = df[self.FEATURE_COLS].iloc[[-1]].fillna(0) proba = self.model.predict_proba(Pool(row))[0] p_up, p_dn = proba[1], proba[0] if p_up >= self.LONG_THR: return "BUY" elif p_dn >= self.SHORT_THR: return "SELL" else: return "HOLD" # Использование — одна строка вместо compute_signal: # signal_fn = CatBoostSignalEngine("models/eurusd_l1_catboost.cbm")
Исполнение ордеров и предторговый риск-контроль
Предторговые проверки выполняются в Python до вызова SDK. Логика валидации — margin level, суммарный лот, drawdown от high-water mark — написана один раз и работает для любого брокера, подключённого через TradeMux. Методы buy_market() и sell_market() принимают нормализованный лот; TradeMux на своей стороне валидирует его против актуальных спецификаций брокера и округляет до допустимого шага. MetaTrader 5 получает уже выверенную команду и исполняет её нативными средствами.
def pre_trade_checks(snap: dict, lots: float) -> tuple[bool, str]: """ Набор предторговых проверок в Python. Возвращает (ok: bool, reason: str). """ # 1. Уровень маржи if snap["margin_level"] < 200.0: return False, f"Margin level {snap['margin_level']:.1f}% < 200%" # 2. Суммарный открытый лот if snap["open_lots"] + lots > MAX_OPEN_LOTS: return False, f"Lots limit: {snap['open_lots']:.2f} + {lots:.2f} > {MAX_OPEN_LOTS}" # 3. Просадка equity от high-water mark global EQUITY_HIGH_MARK EQUITY_HIGH_MARK = max(EQUITY_HIGH_MARK, snap["equity"]) drawdown = EQUITY_HIGH_MARK - snap["equity"] if drawdown > MAX_DRAWDOWN_USD: return False, f"Drawdown ${drawdown:.2f} > limit ${MAX_DRAWDOWN_USD:.2f}" return True, "ok" def execute_signal( client: TradeMuxClient, snap: dict, symbol: str, direction: str, lots: float, ) -> None: """ Передаёт торговое решение из Python в MetaTrader 5 через TradeMux SDK. Перед исполнением: предторговые проверки в Python. """ if direction == "HOLD": return # Позиция в том же направлении уже открыта — пропускаем existing = [ p for p in snap["positions"] if p["symbol"] == symbol and p["type"] == direction ] if existing: log.debug("Skip %s %s — position already open", direction, symbol) return ok, reason = pre_trade_checks(snap, lots) if not ok: log.warning("Pre-trade BLOCK %s %s: %s", direction, symbol, reason) return try: # Python → TradeMux SDK → TradeMux EA → MetaTrader 5 → Broker if direction == "BUY": result = client.buy_market(symbol=symbol, lots=lots) else: result = client.sell_market(symbol=symbol, lots=lots) log.info( "ORDER | %s %s %.2f lots | ticket=%s | fill=%.5f", direction, symbol, lots, result.get("ticket", "?"), result.get("fill_price", 0.0), ) except Exception as e: log.error("Order FAILED %s %s: %s", direction, symbol, e)
Мониторинг позиций и kill switch
Execution service непрерывно отслеживает состояние открытых позиций через get_positions(). Самый важный защитный механизм — kill switch: аварийное закрытие всех позиций при нарушении критических условий. kill_switch() отправляет одну атомарную команду через TradeMux API — EA передаёт её нативным торговым функциям MetaTrader 5, которые закрывают все позиции немедленно. Логика принятия решения о срабатывании kill switch полностью остаётся в Python и может быть изменена без касания терминала.
def monitor_and_protect(client: TradeMuxClient, snap: dict) -> bool: """ Риск-мониторинг в Python. При срабатывании — kill_switch() закрывает позиции через MetaTrader 5. Возвращает True если kill_switch() сработал. """ global EQUITY_HIGH_MARK equity = snap["equity"] balance = snap["balance"] margin = snap["margin_level"] EQUITY_HIGH_MARK = max(EQUITY_HIGH_MARK, equity) drawdown = EQUITY_HIGH_MARK - equity reasons = [] # Критическая просадка equity if drawdown > MAX_DRAWDOWN_USD: reasons.append(f"equity drawdown ${drawdown:.2f}") # Опасно низкий уровень маржи if margin < 120.0: reasons.append(f"margin level {margin:.1f}%") # Убыток превысил 5% баланса за сессию session_loss = balance - equity if session_loss > balance * 0.05: reasons.append(f"session loss ${session_loss:.2f}") if reasons: log.critical("KILL SWITCH triggered: %s", ", ".join(reasons)) try: # Атомарная команда: Python → TradeMux → MetaTrader 5 result = client.kill_switch() log.critical( "kill_switch() confirmed: closed %d positions, PnL=%.2f", result.get("closed_positions", 0), result.get("realized_pnl", 0.0), ) except Exception as e: log.critical("kill_switch() FAILED: %s — manual action required", e) return True return False def log_portfolio_status(snap: dict) -> None: """Выводит текущее состояние портфеля в лог.""" log.info( "Portfolio | Equity=%.2f | Float=%.2f | Pos=%d | Lots=%.2f | Margin=%.1f%%", snap["equity"], snap["float_pnl"], snap["n_positions"], snap["open_lots"], snap["margin_level"], ) for p in snap["positions"]: log.info( " → %s %s %.2f lots | open=%.5f | profit=%.2f", p["type"], p["symbol"], p["lots"], p["open_price"], p["profit"], )
Главный цикл execution service
Все компоненты собираются в единый event-loop. Python управляет расписанием: пересчитывает сигналы каждые SIGNAL_INTERVAL секунд, проверяет портфель каждую минуту и обрабатывает сигналы разворота (reverse signals). Каждый раз, когда принимается решение, оно передаётся в MetaTrader 5 через TradeMux SDK одним вызовом. MetaTrader 5 исполняет, Python наблюдает через нормализованный feedback.
SIGNAL_INTERVAL = 3600 # пересчёт сигналов раз в час MONITOR_INTERVAL = 60 # проверка портфеля каждую минуту DEFAULT_LOTS = 0.01 # базовый лот (переопределяется VaR-аллокацией) def run_execution_service() -> None: """Главный цикл: Python считает, TradeMux доставляет, MetaTrader 5 исполняет.""" client = init_client() snap = snapshot_account(client) global EQUITY_HIGH_MARK EQUITY_HIGH_MARK = snap["equity"] last_signal_ts = 0.0 last_monitor_ts = 0.0 current_signals: dict[str, str] = {} log.info("Execution service started. HWM: %.2f", EQUITY_HIGH_MARK) while True: now = time.time() # ── Python: пересчёт сигналов ──────────────────────── if now - last_signal_ts >= SIGNAL_INTERVAL: log.info("--- Signal update cycle ---") current_signals = generate_signals(client, SYMBOLS) last_signal_ts = now snap = snapshot_account(client) if monitor_and_protect(client, snap): log.critical("Kill switch fired — service stopped") break # Передаём решения из Python в MetaTrader 5 через TradeMux for symbol, direction in current_signals.items(): execute_signal(client, snap, symbol, direction, DEFAULT_LOTS) snap = snapshot_account(client) # читаем актуальное состояние из MetaTrader 5 # ── Python: мониторинг портфеля ────────────────────── if now - last_monitor_ts >= MONITOR_INTERVAL: snap = snapshot_account(client) log_portfolio_status(snap) if monitor_and_protect(client, snap): log.critical("Kill switch fired during monitor — service stopped") break last_monitor_ts = now # ── Python: обработка сигналов разворота ───────────── if current_signals: snap = snapshot_account(client) for pos in snap["positions"]: new_dir = current_signals.get(pos["symbol"], "HOLD") if new_dir not in ("HOLD", pos["type"]): log.info( "Reverse signal: closing %s %s → sending to MetaTrader 5", pos["type"], pos["symbol"], ) try: client.close_position(ticket=pos["ticket"]) except Exception as e: log.error("Close failed %s: %s", pos["ticket"], e) time.sleep(10) # базовый тик цикла — 10 секунд
TradeMux как кросс-брокерный мост
Важное практическое преимущество TradeMux — нормализация брокерной специфики. Разные брокеры используют разные символьные суффиксы: EURUSD.raw, EURUSD.pro, EURUSDi — одна и та же пара, разные обозначения. Шаг лота у одного брокера 0.01, у другого 0.1. Режим исполнения — instant у одного, market у другого. TradeMux абстрагирует все эти различия: Python-код вызывает buy_market("EURUSD", 0.10), а TradeMux на своей стороне транслирует это в корректный запрос для конкретного брокера.
ACCOUNTS = {
"RBF-123456": TradeMuxClient(api_key=API_KEY, account_id="RBF-123456", base_url=BASE_URL),
"ICM-789012": TradeMuxClient(api_key=API_KEY, account_id="ICM-789012", base_url=BASE_URL),
"ALP-DEMO01": TradeMuxClient(api_key=API_KEY, account_id="ALP-DEMO01", base_url=BASE_URL),
}
def broadcast_signal(
clients: dict[str, TradeMuxClient],
symbol: str,
direction: str,
lot_map: dict[str, float],
) -> None:
"""
Один сигнал из Python → несколько брокеров через TradeMux.
TradeMux нормализует брокерную специфику для каждого счёта.
lot_map: {account_id: lots}
"""
for acc_id, client in clients.items():
lots = lot_map.get(acc_id, 0.01)
log.info("[%s] %s %s %.2f lots → MetaTrader 5 via TradeMux", acc_id, direction, symbol, lots)
try:
if direction == "BUY":
client.buy_market(symbol=symbol, lots=lots)
elif direction == "SELL":
client.sell_market(symbol=symbol, lots=lots)
except Exception as e:
log.error("[%s] Broadcast failed: %s", acc_id, e)
Это открывает архитектуру мультисчётных операций: один Python-сервис управляет счётами у нескольких брокеров одновременно. Каждый терминал MetaTrader 5 запускает один и тот же TradeMux EA. Python-логика единая. TradeMux нормализует коммуникацию с каждым брокером независимо.
Supervisor-паттерн: автоматический рестарт
Производственная система должна корректно обрабатывать сетевые сбои и нештатные ситуации. После срабатывания kill switch сервис выдерживает recovery-паузу и перезапускается с теми же параметрами. Ограничение числа перезапусков защищает от бесконечного цикла при системной проблеме.
import sys RECOVERY_WAIT_SECONDS = 3600 # пауза после kill switch — 1 час MAX_KILL_EVENTS = 3 # после 3 событий — полная остановка def supervised_run() -> None: """ Supervisor-обёртка над run_execution_service(). Перезапускает сервис с ограничением числа попыток. """ kill_count = 0 while kill_count < MAX_KILL_EVENTS: try: run_execution_service() log.info("Service completed normally.") sys.exit(0) except KeyboardInterrupt: log.info("Manual shutdown.") sys.exit(0) except Exception as e: kill_count += 1 log.critical( "Service crashed (%d/%d): %s — waiting %ds", kill_count, MAX_KILL_EVENTS, e, RECOVERY_WAIT_SECONDS, ) if kill_count >= MAX_KILL_EVENTS: log.critical("Max kill events reached — full stop.") sys.exit(1) time.sleep(RECOVERY_WAIT_SECONDS) if __name__ == "__main__": supervised_run()
Путь масштабирования: от PoC к fund-style операциям
Описанный execution service запускается на одном счёте и одном терминале MetaTrader 5. Та же Python-архитектура масштабируется без переписывания торговой логики — изменяется только конфигурация подключения.
Первый этап — proof of concept на демо-счёте. Прикрепить TradeMux EA, создать API-ключ, запустить execution service с DEFAULT_LOTS = 0.01. За 1–2 дня вся цепочка проверяется в реальных условиях: Python генерирует сигнал → TradeMux доставляет команду → MetaTrader 5 исполняет ордер → Python читает feedback через get_positions(). Бесплатный developer workflow позволяет пройти этот этап полностью до перехода на live-счёт.
Второй этап — VPS-деплой на live-счёт. Python-сервис разворачивается на VPS рядом с терминалом MetaTrader 5. Латентность к TradeMux API минимальна. Тот же код, та же логика — меняется одна строка: ACCOUNT_ID и размер лотов.
Третий этап — несколько счётов MetaTrader 5. Словарь clients в broadcast_signal() расширяется до нужного числа счётов. Python-логика единая. Каждый терминал MetaTrader 5 запускает один и тот же TradeMux EA — только с другим account_id.
Четвёртый этап — кросс-платформенный охват. Тот же Python-код работает через TradeMux с MetaTrader 4-терминалами и OANDA. Диверсификация по брокерам снижает инфраструктурный риск: если один брокер временно недоступен, остальные продолжают работу. На каждом из этих этапов Python-логика не меняется. TradeMux обеспечивает единообразие интерфейса для всех брокеров и платформ.
Дальнейшие шаги: от статьи к live-торговле
Архитектуру можно проверить за четыре шага:
- прикрепить TradeMux EA к любому графику в MetaTrader 5, разрешить WebRequest для домена API;
- создать API-ключ — бесплатный developer workflow позволяет проверить полную цепочку на демо-счёте без ограничений по функциональности;
- запустить execution service и убедиться, что get_account_info(), get_positions(), buy_market() и kill_switch() работают корректно;
- подключить собственную signal-логику — CatBoost-модель с L1-фильтрованными признаками, мультипарный пайплайн, VaR-аллокацию лотов — и перейти на live.
Переход от демо к live — смена одного параметра ACCOUNT_ID. Логика, код, архитектура — не меняются.
Что касается самого пайплайна как торговой системы, то OOS без утечек данных показывает такой результат:

Заключение
Python и MetaTrader 5 — две профессиональные среды, каждая из которых сильна в своей области. Python — богатейшая экосистема для исследований, моделирования и расчётов. MetaTrader 5 — надёжная execution-платформа с прямым брокерским коннектом и нативной скоростью обработки ордеров. TradeMux соединяет их в единую production-архитектуру: Python считает и принимает решения, TradeMux доставляет их через нормализованный интерфейс, MetaTrader 5 исполняет у брокера.
Полный торговый цикл описан через шесть методов SDK: get_account_info(), get_positions(), get_ohlc(), buy_market(), sell_market(), kill_switch(). Один и тот же Python-код работает с MetaTrader 4, MetaTrader 5 и OANDA через TradeMux без рефакторинга. При масштабировании на несколько счётов и брокеров меняется конфигурация подключения — торговая и исследовательская логика остаётся неизменной. TradeMux обеспечивает нормализованный кросс-брокерный интерфейс, MetaTrader 5 обеспечивает исполнение, Python обеспечивает интеллект системы.
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Советник для размещения сделок на основе риска с графическим интерфейсом на графике (Часть 1): Проектирование пользовательского интерфейса
Знакомство с языком MQL5 (Часть 42): Руководство для начинающих по работе с файлами в MQL5 (IV)
Разрабатываем пользовательский индикатор рыночных настроений
Разработка инструментария для анализа Price Action (Часть 62): Создание адаптивной системы обнаружения параллельных каналов и пробоев на языке MQL5
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования