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? После подтверждения оплаты файл сохранится в кабинете на этот email. Если аккаунта ещё нет, мы создадим его и пришлём ссылку для задания пароля. Если аккаунт уже есть, покупка добавится в него. Укажите адрес, к которому у вас есть доступ.
Чтобы оформить заказ, введите email и перейдите к оплате.