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