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

hedge fixed version.mq5

Вы автор или правообладатель?

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

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

О программе

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

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

Советник использует торговые функции MetaTrader 5 через класс CTrade, поддерживает настройку магического номера, отклонения и объема. Все параметры вынесены во входные переменные, что позволяет адаптировать поведение под конкретные условия рынка. Важно отметить, что советник не гарантирует прибыль и требует тестирования на исторических данных.

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

НастройкаОписание
InpSymbol Торговый инструмент, с которым работает советник.
InpLots Объем лота для открываемых позиций.
InpDeviationPoints Максимально допустимое отклонение цены в пунктах при открытии и закрытии позиций.
InpMagic Уникальный идентификатор (магический номер) для позиций, открываемых советником.
InpOnlyM1 Если включено, советник работает только на таймфрейме M1. На других таймфреймах торговля не ведется.
InpVerbose Если включено, советник выводит подробные сообщения о своих действиях в журнал.
InpReentryRetracePips Количество пунктов отката цены от экстремума, необходимое для повторного входа после закрытия одной из позиций.
InpCloseTargetPips Целевое движение цены в пунктах, при достижении которого советник закрывает соответствующую позицию (BUY при движении вниз, SELL при движении вверх).
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 double InpReentryRetracePips        = 10.0; 

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;

double   g_pendingBuy_LowestAsk = 0.0;
double   g_pendingSell_HighestBid = 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_pendingBuy_LowestAsk = 0.0;
   g_pendingSell_HighestBid = 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 closed_side)
{

   double bid = 0.0, ask = 0.0;
   GetBidAsk(bid, ask);

   if(closed_side == POSITION_TYPE_BUY)
   {

      g_pendingBuy = true;
      g_pendingBuy_LowestAsk = ask; 
   }
   else if(closed_side == POSITION_TYPE_SELL)
   {

      g_pendingSell = true;
      g_pendingSell_HighestBid = bid;
   }
}

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_pendingBuy_LowestAsk = 0.0;
   }
   else
   {
      g_pendingSell = false;
      g_pendingSell_HighestBid = 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)
         Print("CloseManagedTicket failed ticket=", ticket,
               " retcode=", trade.ResultRetcode(),
               " desc=", trade.ResultRetcodeDescription());
      return false;

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

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

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

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

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

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

Стоимость полного кода
1 263,40₽ ≈ $15.44