Динамический Мартингейл с учетом корреляции пар в MQL4

Динамический Мартингейл с учетом корреляции пар в MQL4 КРЕДИТЫ, ИПОТЕКА и БАНКИ
Пошаговое руководство по созданию советника на MQL4 с алгоритмом динамического усреднения (мартингейла), адаптирующегося под корреляцию валютных пар. Полный код и разбор параметров.
Суть: Классический мартингейл уязвим при одновременной просадке по коррелирующим парам (например, EURUSD и GBPUSD). Данное решение динамически расширяет шаг сетки (Grid Step) на основе коэффициента корреляции Пирсона, рассчитываемого в реальном времени, что снижает нагрузку на депозит и предотвращает маржин-колл.

Исходный код

Ниже представлен готовый код советника для MetaTrader 4. Алгоритм рассчитывает корреляцию между текущим инструментом и вспомогательным символом. Если корреляция превышает заданный порог, советник автоматически увеличивает шаг между ордерами сетки, защищая баланс от системных рисков.

Перед открытием первого колена сетки критически важно проверять текущие рыночные условия. Рекомендуем внедрить Фильтр максимального спреда в MQL4: Защита ночного скальпера, чтобы избежать открытия позиций в моменты низкой ликвидности и аномального расширения спреда.

//+------------------------------------------------------------------+
//|                                           CorrelationMarty.mq4   |
//|                                                   Senior Quant   |
//+------------------------------------------------------------------+
#property copyright "Finfluct"
#property link      "https://finfluct.com"
#property version   "1.00"
#property strict

// Настройки сетки и лотности
input double   BaseLot         = 0.01;       // Начальный лот
input double   LotMultiplier   = 1.5;        // Множитель лота (мартингейл)
input int      BaseGridStep    = 200;        // Базовый шаг сетки (в пунктах)
input int      MaxOrders       = 10;         // Максимальное количество колен
input int      TakeProfitPoints= 150;        // Общий Тейк-Профит (в пунктах)

// Настройки корреляции
input string   CorrelatedSymbol= "GBPUSD";   // Коррелируемый символ
input int      CorrPeriod      = 50;         // Период расчета корреляции (баров)
input double   CorrThreshold   = 0.75;       // Порог высокой корреляции
input double   StepExpansion   = 2.0;        // Коэффициент расширения шага
input int      MagicNumber     = 888111;     // Уникальный ID советника

// Глобальные переменные
double PipSize;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit() {
    PipSize = Point;
    if(Digits == 3 || Digits == 5) PipSize = Point * 10;
    
    // Проверка доступности коррелируемого символа в обзоре рынка
    if(SymbolName(CorrelatedSymbol, false) == "") {
        Print("Ошибка: Символ ", CorrelatedSymbol, " не найден в Обзоре рынка!");
        return(INIT_FAILED);
    }
    
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick() {
    double corr = CalculateCorrelation(_Symbol, CorrelatedSymbol, CorrPeriod);
    int activeOrders = CountOrders();
    
    if(activeOrders == 0) {
        // Открываем стартовый ордер сетки на покупку при отсутствии позиций
        SendOrder(OP_BUY, BaseLot);
    } else {
        // Управление сеткой ордеров с учетом корреляции
        ManageGrid(corr);
    }
}

//+------------------------------------------------------------------+
//| Расчет коэффициента корреляции Пирсона                           |
//+------------------------------------------------------------------+
double CalculateCorrelation(string sym1, string sym2, int period) {
    double sum_x = 0, sum_y = 0, sum_xy = 0;
    double sum_x2 = 0, sum_y2 = 0;
    
    int limit = period;
    int copied1 = iBars(sym1, PERIOD_CURRENT);
    int copied2 = iBars(sym2, PERIOD_CURRENT);
    int maxBars = MathMin(limit, MathMin(copied1, copied2));
    
    if(maxBars < period) return 0.0;
    
    for(int i = 0; i < maxBars; i++) {
        double x = iClose(sym1, PERIOD_CURRENT, i);
        double y = iClose(sym2, PERIOD_CURRENT, i);
        
        sum_x += x;
        sum_y += y;
        sum_xy += x * y;
        sum_x2 += x * x;
        sum_y2 += y * y;
    }
    
    double numerator = maxBars * sum_xy - sum_x * sum_y;
    double denominator = MathSqrt((maxBars * sum_x2 - sum_x * sum_x) * (maxBars * sum_y2 - sum_y * sum_y));
    
    if(denominator == 0) return 0.0;
    return numerator / denominator;
}

//+------------------------------------------------------------------+
//| Подсчет открытых ордеров советника                               |
//+------------------------------------------------------------------+
int CountOrders() {
    int count = 0;
    for(int i = OrdersTotal() - 1; i >= 0; i--) {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
            if(OrderSymbol() == _Symbol && OrderMagicNumber() == MagicNumber) {
                count++;
            }
        }
    }
    return count;
}

//+------------------------------------------------------------------+
//| Управление сеткой ордеров                                        |
//+------------------------------------------------------------------+
void ManageGrid(double correlation) {
    double currentStep = BaseGridStep * PipSize;
    
    // Если корреляция выше порогового значения, динамически расширяем шаг сетки
    if(MathAbs(correlation) > CorrThreshold) {
        currentStep = BaseGridStep * StepExpansion * PipSize;
    }
    
    double lastOpenPrice = 0;
    double lastLot = 0;
    int lastType = -1;
    
    // Поиск параметров последнего открытого ордера
    for(int i = OrdersTotal() - 1; i >= 0; i--) {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
            if(OrderSymbol() == _Symbol && OrderMagicNumber() == MagicNumber) {
                lastOpenPrice = OrderOpenPrice();
                lastLot = OrderLots();
                lastType = OrderType();
                break;
            }
        }
    }
    
    if(lastType == OP_BUY) {
        // Если цена ушла ниже последнего ордера на величину шага
        if(Ask < lastOpenPrice - currentStep && CountOrders() < MaxOrders) {
            double nextLot = NormalizeDouble(lastLot * LotMultiplier, 2);
            SendOrder(OP_BUY, nextLot);
        }
    }
}

//+------------------------------------------------------------------+
//| Отправка торгового приказа                                       |
//+------------------------------------------------------------------+
void SendOrder(int type, double lot) {
    double price = (type == OP_BUY) ? Ask : Bid;
    int ticket = OrderSend(_Symbol, type, lot, price, 3, 0, 0, "CorrMartingale", MagicNumber, 0, clrBlue);
    if(ticket > 0) {
        ModifyTakeProfit(type);
    }
}

//+------------------------------------------------------------------+
//| Модификация общего Тейк-Профита для всей сетки                   |
//+------------------------------------------------------------------+
void ModifyTakeProfit(int type) {
    double sumLots = 0;
    double sumPriceLots = 0;
    
    for(int i = OrdersTotal() - 1; i >= 0; i--) {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
            if(OrderSymbol() == _Symbol && OrderMagicNumber() == MagicNumber && OrderType() == type) {
                sumLots += OrderLots();
                sumPriceLots += OrderOpenPrice() * OrderLots();
            }
        }
    }
    
    if(sumLots == 0) return;
    double avgPrice = sumPriceLots / sumLots;
    double tpPrice = 0;
    
    if(type == OP_BUY) {
        tpPrice = NormalizeDouble(avgPrice + TakeProfitPoints * PipSize, Digits);
    } else {
        tpPrice = NormalizeDouble(avgPrice - TakeProfitPoints * PipSize, Digits);
    }
    
    for(int i = OrdersTotal() - 1; i >= 0; i--) {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
            if(OrderSymbol() == _Symbol && OrderMagicNumber() == MagicNumber && OrderType() == type) {
                if(MathAbs(OrderTakeProfit() - tpPrice) > Point) {
                    bool res = OrderModify(OrderTicket(), OrderOpenPrice(), OrderStopLoss(), tpPrice, 0, clrNone);
                }
            }
        }
    }
}

Разбор параметров

  • BaseLot: Объем первой сделки в сетке. Рекомендуется использовать минимальный лот (0.01) для безопасного тестирования.
  • LotMultiplier: Коэффициент геометрического увеличения лота для каждого последующего колена сетки.
  • BaseGridStep: Минимальное расстояние в пунктах между ордерами при отсутствии сильной корреляции.
  • CorrelatedSymbol: Валютная пара, с которой рассчитывается взаимосвязь (например, для EURUSD это может быть GBPUSD или USDCHF).
  • CorrThreshold: Порог коэффициента Пирсона (от -1.0 до 1.0), при превышении которого активируется защитное расширение шага сетки.
  • StepExpansion: Множитель, на который увеличивается шаг сетки BaseGridStep, если корреляция превысила установленный порог.

Как запустить

Для запуска советника выполните следующие шаги:

1. Откройте MetaTrader 4 и перейдите в редактор MetaEditor (клавиша F4).

2. Создайте новый советник (Expert Advisor) и скопируйте туда представленный код.

3. Скомпилируйте код (клавиша F7). Убедитесь, что в панели ошибок нет предупреждений.

4. Вернитесь в терминал MT4, перетащите советник из окна ‘Навигатор’ на график выбранной валютной пары (например, EURUSD).

5. В настройках обязательно укажите коррелирующий символ в параметре CorrelatedSymbol и добавьте этот символ в окно ‘Обзор рынка’ (Market Watch), иначе функция iClose не сможет получить исторические данные для расчета.

Для построения более сложных прогнозных моделей на основе машинного обучения вы можете изучить наше руководство Нейросетевой предиктор на ALGLIB в MQL5: Руководство.

При работе с историей сделок и анализе закрытых сеток в MQL5 часто возникают проблемы с кэшированием данных. О том, как их избежать, читайте в статье Обход лимитов HistorySelect в MQL5: Пошаговое руководство.

Оцените статью
FinFluct