← К каталогу
Исходный код · ID 4492

hedge re-entry system

hedge re-entry system.mq5
Вы автор или правообладатель?

Сообщите нам, если считаете, что материал размещён без разрешения.

Краткий обзор

О программе

Данный советник работает на платформе MetaTrader 5 и реализует стратегию хеджирования с одновременными позициями BUY и SELL на одном символе. Основная особенность — механизм закрытия одной из сторон хеджа при чистом движении цены на заданное количество пунктов без отката, после чего возможно повторное открытие позиции.

Советник поддерживает систему ре-энтри: после закрытия позиции он отслеживает улучшение цены и повторно открывает сторону хеджа по истечении минимальной задержки или принудительно по таймеру. Доступна фильтрация по таймфрейму M1, настройка объёма, допустимого отклонения и магического номера для управления позициями.

Параметры закрытия включают целевое количество пунктов, величину отката и шаг уровней, а также автоматическое определение размера пункта для разных символов. Предусмотрены режимы подробного логирования для отладки работы механизмов закрытия и ре-энтри.

Настройки программы

НастройкаОписание
InpSymbol Символ инструмента, на котором работает советник.
InpLots Объём лота для открытия и закрытия позиций.
InpDeviationPoints Допустимое отклонение цены в пунктах при выполнении торговых операций (открытие и закрытие позиций).
InpMagic Магический номер, используемый для идентификации позиций, управляемых данным советником.
InpOnlyM1 Переключатель, ограничивающий работу советника только таймфреймом M1. При активации на других таймфреймах советник не выполняет операции.
InpVerbose Включает подробное логирование основных операций советника (открытие, закрытие, ре-энтри) в журнал.
InpReentryMinDelaySec Минимальная задержка в секундах после закрытия позиции, в течение которой ре-энтри невозможен.
InpReentryForceSec Время в секундах после закрытия позиции, по истечении которого ре-энтри выполняется принудительно без ожидания улучшения цены.
InpReentryGapAbs Абсолютный минимальный разрыв в цене, необходимый для ре-энтри при улучшении цены.
InpReentryGapSpreadMult Множитель текущего спреда, используемый для расчёта динамического минимального разрыва ре-энтри. Итоговый разрыв выбирается как максимум из абсолютного значения и произведения спреда на этот множитель.
InpCloseTargetPips Целевое количество пунктов чистого движения цены, при достижении которого происходит закрытие противоположной стороны хеджа.
InpCloseRetracePips Величина отката в пунктах. Если цена откатилась на это значение после чистого движения, текущий уровень пересчитывается и отслеживание продолжается.
InpCloseLevelStepPips Шаг уровней в пунктах, используемый для поэтапного пересчёта базовых уровней при отслеживании движения цены и отката.
InpCloseAutoPipSize Включает автоматическое определение размера пункта для расчёта условий закрытия. При отключении используется значение из параметра InpClosePipSize.
InpClosePipSize Размер пункта в ценовых единицах символа, используемый при ручном режиме определения размера пункта.
InpVerboseCloseDebug Включает детальный отладочный вывод механизма закрытия, включая информацию о базовых уровнях, пиках и расчётах движения цены.
Получить полный код

Поиск по коду файла

#property strict
#property description "Original entry / re-entry preserved."
#property description "Exit replaced with: close the opposite trade after a 40-pip move with no 10-pip retracement."

#include <Trade/Trade.mqh>

input string InpSymbol                    = "XAUUSD.s";
input double InpLots                      = 0.01;
input int    InpDeviationPoints           = 50;
input long   InpMagic                     = 260320264;
input bool   InpOnlyM1                    = true;
input bool   InpVerbose                   = true;

input int    InpReentryMinDelaySec        = 8;
input int    InpReentryForceSec           = 45;
input double InpReentryGapAbs             = 0.45;
input double InpReentryGapSpreadMult      = 1.25;

input double InpCloseTargetPips           = 40.0;
input double InpCloseRetracePips          = 10.0;
input double InpCloseLevelStepPips        = 10.0;
input bool   InpCloseAutoPipSize          = true;
input double InpClosePipSize              = 0.10;
input bool   InpVerboseCloseDebug         = false;

CTrade trade;

bool     g_pendingBuy = false;
bool     g_pendingSell = false;
datetime g_pendingBuyTime = 0;
datetime g_pendingSellTime = 0;
double   g_pendingBuyClosePrice = 0.0;
double   g_pendingSellClosePrice = 0.0;

struct SidePos
{
   bool     ok;
   ulong    ticket;
   datetime open_time;
   double   open_price;
   double   pnl;
   double   volume;
   ENUM_POSITION_TYPE type;
};

struct CloseTracker
{
   bool   initialized;

   double up_base;     // active start level being tested (40, then 41, then 42...)
   double up_peak;     // highest ASK reached since initialization

   double down_base;   // active start level being tested (40, then 39, then 38...)
   double down_low;    // lowest BID reached since initialization
};

CloseTracker g_closeTracker;

enum CloseSignal
{
   CLOSE_SIGNAL_NONE = 0,
   CLOSE_SIGNAL_BUY  = 1,  // close BUY because price moved down cleanly
   CLOSE_SIGNAL_SELL = 2   // close SELL because price moved up cleanly
};

void ResetRuntimeState()
{
   g_pendingBuy = false;
   g_pendingSell = false;
   g_pendingBuyTime = 0;
   g_pendingSellTime = 0;
   g_pendingBuyClosePrice = 0.0;
   g_pendingSellClosePrice = 0.0;

   g_closeTracker.initialized = false;
   g_closeTracker.up_base = 0.0;
   g_closeTracker.up_peak = 0.0;
   g_closeTracker.down_base = 0.0;
   g_closeTracker.down_low = 0.0;
}

int DigitsForSymbol()
{
   return (int)SymbolInfoInteger(InpSymbol, SYMBOL_DIGITS);
}

double NormalizePrice(const double price)
{
   return NormalizeDouble(price, DigitsForSymbol());
}

double EffectivePipSize()
{
   if(!InpCloseAutoPipSize)
      return InpClosePipSize;

   double point = 0.0;
   if(!SymbolInfoDouble(InpSymbol, SYMBOL_POINT, point) || point <= 0.0)
      return InpClosePipSize;

   int digits = DigitsForSymbol();

   if(digits == 5 || digits == 3 || digits == 2)
      return point * 10.0;

   return point;
}

double PriceEpsilon()
{
   double point = 0.0;
   if(!SymbolInfoDouble(InpSymbol, SYMBOL_POINT, point) || point <= 0.0)
      point = 0.00001;
   return point * 0.5;
}

double StepFloor(const double price, const double step)
{
   if(step <= 0.0)
      return NormalizePrice(price);
   return NormalizePrice(MathFloor((price + 1e-12) / step) * step);
}

double StepCeil(const double price, const double step)
{
   if(step <= 0.0)
      return NormalizePrice(price);
   return NormalizePrice(MathCeil((price - 1e-12) / step) * step);
}

bool GetBidAsk(double &bid, double &ask)
{
   MqlTick tick;
   if(!SymbolInfoTick(InpSymbol, tick))
      return false;

   bid = NormalizePrice(tick.bid);
   ask = NormalizePrice(tick.ask);
   return (bid > 0.0 && ask > 0.0);
}

void ResetCloseTracker(const double bid, const double ask)
{
   double pip_price = EffectivePipSize();
   double step_price = InpCloseLevelStepPips * pip_price;
   if(step_price <= 0.0)
      step_price = pip_price;

   g_closeTracker.initialized = true;
   g_closeTracker.up_base = StepFloor(ask, step_price);
   g_closeTracker.up_peak = ask;
   g_closeTracker.down_base = StepCeil(bid, step_price);
   g_closeTracker.down_low = bid;

   if(InpVerbose || InpVerboseCloseDebug)
   {
      Print("Close tracker reset | bid=", DoubleToString(bid, DigitsForSymbol()),
            " ask=", DoubleToString(ask, DigitsForSymbol()),
            " up_base=", DoubleToString(g_closeTracker.up_base, DigitsForSymbol()),
            " down_base=", DoubleToString(g_closeTracker.down_base, DigitsForSymbol()));
   }
}

int CountManaged(const ENUM_POSITION_TYPE side)
{
   int count = 0;
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0)
         continue;
      if(!PositionSelectByTicket(ticket))
         continue;
      if(PositionGetString(POSITION_SYMBOL) != InpSymbol)
         continue;
      if((long)PositionGetInteger(POSITION_MAGIC) != InpMagic)
         continue;
      if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) != side)
         continue;
      count++;
   }
   return count;
}

bool GetManagedSide(const ENUM_POSITION_TYPE side, SidePos &out_pos)
{
   out_pos.ok = false;
   out_pos.ticket = 0;
   out_pos.open_time = 0;
   out_pos.open_price = 0.0;
   out_pos.pnl = 0.0;
   out_pos.volume = 0.0;
   out_pos.type = side;

   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0)
         continue;
      if(!PositionSelectByTicket(ticket))
         continue;
      if(PositionGetString(POSITION_SYMBOL) != InpSymbol)
         continue;
      if((long)PositionGetInteger(POSITION_MAGIC) != InpMagic)
         continue;
      if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) != side)
         continue;

      datetime tm = (datetime)PositionGetInteger(POSITION_TIME);
      if(!out_pos.ok || tm < out_pos.open_time)
      {
         out_pos.ok = true;
         out_pos.ticket = ticket;
         out_pos.open_time = tm;
         out_pos.open_price = PositionGetDouble(POSITION_PRICE_OPEN);
         out_pos.pnl = PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP);
         out_pos.volume = PositionGetDouble(POSITION_VOLUME);
         out_pos.type = side;
      }
   }

   return out_pos.ok;
}

void RegisterPendingReentry(const ENUM_POSITION_TYPE side, const double close_price)
{
   if(side == POSITION_TYPE_BUY)
   {
      g_pendingBuy = true;
      g_pendingBuyTime = TimeCurrent();
      g_pendingBuyClosePrice = close_price;
   }
   else if(side == POSITION_TYPE_SELL)
   {
      g_pendingSell = true;
      g_pendingSellTime = TimeCurrent();
      g_pendingSellClosePrice = close_price;
   }
}

bool OpenSide(const ENUM_POSITION_TYPE side)
{
   trade.SetExpertMagicNumber(InpMagic);
   trade.SetDeviationInPoints(InpDeviationPoints);

   bool ok = false;
   if(side == POSITION_TYPE_BUY)
      ok = trade.Buy(InpLots, InpSymbol, 0.0, 0.0, 0.0, "hedge_buy");
   else
      ok = trade.Sell(InpLots, InpSymbol, 0.0, 0.0, 0.0, "hedge_sell");

   if(!ok)
   {
      if(InpVerbose)
         Print("OpenSide failed side=", EnumToString(side),
               " retcode=", trade.ResultRetcode(),
               " desc=", trade.ResultRetcodeDescription());
      return false;
   }

   if(side == POSITION_TYPE_BUY)
   {
      g_pendingBuy = false;
      g_pendingBuyTime = 0;
      g_pendingBuyClosePrice = 0.0;
   }
   else
   {
      g_pendingSell = false;
      g_pendingSellTime = 0;
      g_pendingSellClosePrice = 0.0;
   }

   if(InpVerbose)
      Print("Opened ", EnumToString(side),
            " deal=", trade.ResultDeal(),
            " order=", trade.ResultOrder(),
            " ret=", trade.ResultRetcodeDescription());

   return true;
}

bool CloseManagedTicket(const ulong ticket)
{
   if(ticket == 0)
      return false;
   if(!PositionSelectByTicket(ticket))
      return false;
   if(PositionGetString(POSITION_SYMBOL) != InpSymbol)
      return false;
   if((long)PositionGetInteger(POSITION_MAGIC) != InpMagic)
      return false;

   ENUM_POSITION_TYPE side = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

   double close_price = 0.0;
   if(side == POSITION_TYPE_BUY)
      SymbolInfoDouble(InpSymbol, SYMBOL_BID, close_price);
   else
      SymbolInfoDouble(InpSymbol, SYMBOL_ASK, close_price);

   trade.SetExpertMagicNumber(InpMagic);
   trade.SetDeviationInPoints(InpDeviationPoints);

   bool ok = trade.PositionClose(ticket, InpDeviationPoints);
   if(!ok)
   {
      if(InpVerbose)
   

Показано первые 50% кода (символов: 12895)

Открыть по тарифу

Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.

Разовая покупка файла

На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.

Чтобы оформить заказ, введите email и перейдите к оплате.

Стоимость полного кода
1 289,50₽ ≈ $15.76