HedgeCycleEA v7
Сообщите нам, если считаете, что материал размещён без разрешения.
Сообщить о материале
Обращение по товару «hedge combo.mq5» отправится на рассмотрение. Укажите контакт для ответа и опишите причину.
О программе
HedgeCycleEA v7 — торговый советник для MetaTrader 5, работающий по стратегии хеджирования. Он открывает парные позиции BUY и SELL на одном символе, ожидает достижения заданного ценового движения в пунктах, затем определяет прибыльное направление и управляет циклами сделок. Советник использует конечный автомат с четырьмя состояниями: ожидание, мониторинг, закрытие и простой.
Встроены средства управления рисками: аварийное закрытие по проигрышу в пунктах, ограничение дневного убытка, контроль максимальной просадки от пика капитала, блокировка фиксации плавающей прибыли и ограничение убытка по циклу. Также реализован мониторинг плавающего P&L во время паузы — при достижении целевого значения позиции закрываются даже при приостановке советника.
Советник отображает информационную панель с 20 строками, показывающую текущее состояние, открытые позиции, плавающую прибыль, целевые значения, дневной P&L, просадку и баланс. Все торговые операции выполняются через стандартные классы CTrade и CPositionInfo платформы MetaTrader 5.
Настройки программы
| Настройка | Описание |
|---|---|
| LotSize | Размер лота для каждой открытой позиции в паре BUY/SELL. |
| Slippage | Допустимое отклонение цены исполнения в пунктах при открытии и закрытии позиций. |
| MaxSpreadPoints | Допустимое значение спреда в пунктах. При превышении советник не открывает новые позиции. |
| MagicBase | Базовое число магического идентификатора для присвоения открытым позициям. |
| WaitPips | Количество пунктов ценового движения, которое необходимо набрать перед первой оценкой и принятием решения по циклу. |
| FirstTargetUSD | Целевая чистая прибыль в долларах после достижения ценового движения в WaitPips. При достижении запускается закрытие. |
| RecoveryExtraUSD | Дополнительная величина сверх заблокированного убытка, формирующая целевой порог восстановления в долларах. |
| MaxCycles | Максимальное количество торговых циклов до принудительного закрытия всех позиций. |
| EmergencyLossPips | Максимальное допустимое движение цены в пунктах от цены входа. При превышении происходит аварийное закрытие всех позиций. |
| UseRoundCap | Переключатель ограничения убытка по циклу. При активации при достижении убытка MaxRoundLossUSD текущий цикл закрывается. |
| MaxRoundLossUSD | Максимальный убыток по текущему циклу в долларах. При превышении запускается закрытие цикла. |
| UseFloatLock | Переключатель механизма фиксации плавающей прибыли. При активации советник отслеживает пик прибыли и закрывает позиции при заданном падении. |
| FloatLockMinUSD | Минимальный пик плавающей прибыли в долларах, при котором активируется механизм фиксации прибыли. |
| FloatLockDropUSD | Допустимое снижение плавающей прибыли от пика в долларах. При падении плавающей прибыли ниже пика на эту величину происходит закрытие для защиты. |
| UseHWM | Переключатель контроля максимальной просадки от исторического пика капитала (High Water Mark). При превышении заданного процента советник приостанавливается. |
| MaxDDFromPeakPct | Максимальная просадка капитала от пика в процентах. При превышении советник приостанавливается. |
| UseDailyLimit | Переключатель дневного лимита убытка. При активации контролируется дневной P&L и при превышении лимита советник приостанавливается. |
| DailyLossLimitUSD | Дневной лимит убытка в долларах. При превышении убытка за торговый день советник приостанавливается до следующего дня. |
| MonitorDuringPause | Переключатель мониторинга плавающей прибыли во время паузы. При активации советник продолжает проверять плавающий P&L и закрывает позиции при достижении целевого значения. |
| PauseFloatTargetUSD | Целевое значение плавающей прибыли в долларах для закрытия позиций при паузе, если до этого целевой порог ещё не был установлен. |
| ShowPanel | Переключатель отображения информационной панели на графике. |
| PanelX | Горизонтальная позиция панели на графике в пикселях от левого верхнего угла. |
| PanelY | Вертикальная позиция панели на графике в пикселях от левого верхнего угла. |
Поиск по коду файла
#property version "7.00"
#property strict
#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
input group "=== Trade ==="
input double LotSize = 0.11;
input int Slippage = 50;
input double MaxSpreadPoints = 30.0;
input int MagicBase = 90000;
input group "=== 40-Pip Rule ==="
input double WaitPips = 40.0;
input group "=== Profit Targets ==="
input double FirstTargetUSD = 15.0;
input double RecoveryExtraUSD = 15.0;
input group "=== Hard Limits ==="
input int MaxCycles = 4;
input double EmergencyLossPips = 200.0;
input group "=== Round Loss Cap ==="
input bool UseRoundCap = true;
input double MaxRoundLossUSD = 45.0;
input group "=== Float Profit Lock ==="
input bool UseFloatLock = true;
input double FloatLockMinUSD = 5.0;
input double FloatLockDropUSD = 3.0;
input group "=== Account Protection ==="
input bool UseHWM = true;
input double MaxDDFromPeakPct = 10.0;
input bool UseDailyLimit = true;
input double DailyLossLimitUSD = 30.0;
input group "=== Pause Float Monitor ==="
input bool MonitorDuringPause = true;
input double PauseFloatTargetUSD = 10.0;
input group "=== Panel ==="
input bool ShowPanel = true;
input int PanelX = 10;
input int PanelY = 30;
enum EState
{
S_IDLE = 0,
S_WAITING = 1,
S_MONITOR = 2,
S_CLOSING = 3,
};
struct SCycle
{
int magicBuy;
int magicSell;
int winnerMagic;
double lossLocked;
bool decided;
};
CTrade g_trade;
CPositionInfo g_pos;
EState g_state = S_IDLE;
double g_startPrice = 0.0;
double g_highPrice = 0.0;
double g_lowPrice = 0.0;
double g_totalLocked = 0.0;
int g_cycleCount = 0;
double g_roundStartBal = 0.0;
int g_rounds = 0;
double g_totalProfit = 0.0;
bool g_firstRun = true;
SCycle g_cycles[];
double g_initialBalance = 0.0;
double g_floatPeak = 0.0;
double g_highWaterMark = 0.0;
double g_dayStartBalance = 0.0;
datetime g_lastDayReset = 0;
bool g_paused = false;
string g_pauseReason = "";
string g_status = "Starting...";
#define PN "HC7_"
#define PANEL_ROWS 20
int OnInit()
{
// код доступен только после оплаты
}
void OnDeinit(const int reason)
{
for(int i = ObjectsTotal(0,0,-1)-1; i >= 0; i--)
{
string name = ObjectName(0,i,0,-1);
if(StringFind(name,PN) == 0) ObjectDelete(0,name);
}
}
void OnTick()
{
// код доступен только после оплаты
}
void HandleIdle()
{
if(HasAnyPosition()) { CloseAllOurs(); return; }
ArrayResize(g_cycles, 0);
g_totalLocked = 0.0;
g_cycleCount = 0;
g_roundStartBal = AccountInfoDouble(ACCOUNT_BALANCE);
g_floatPeak = 0.0;
if(!OpenNewCycle()) return;
g_startPrice = MidPrice();
g_highPrice = g_startPrice;
g_lowPrice = g_startPrice;
g_state = S_WAITING;
g_rounds++;
g_status = StringFormat("Round #%d opened | Entry=%.5f | Waiting %.0f pips...",
g_rounds, g_startPrice, WaitPips);
Print("v7: Round #", g_rounds, " opened. Entry=", g_startPrice);
}
void HandleWaiting()
{
double mid = MidPrice();
if(mid > g_highPrice) g_highPrice = mid;
if(mid < g_lowPrice) g_lowPrice = mid;
double pip = GetPipSize();
double rangeUp = (g_highPrice - g_startPrice) / pip;
double rangeDn = (g_startPrice - g_lowPrice) / pip;
double pipsMoved = MathMax(rangeUp, rangeDn);
if(pipsMoved < WaitPips)
{
double buyPnl = SidePnl(g_cycles[0].magicBuy);
double sellPnl = SidePnl(g_cycles[0].magicSell);
g_status = StringFormat("WAITING %.1f/%.0f pips | BUY=%+.2f SELL=%+.2f Net=%+.2f",
pipsMoved, WaitPips, buyPnl, sellPnl, buyPnl + sellPnl);
return;
}
double buyPnl = SidePnl(g_cycles[0].magicBuy);
double sellPnl = SidePnl(g_cycles[0].magicSell);
double netPnl = buyPnl + sellPnl;
Print("v7: 40 pips (", DoubleToString(pipsMoved,1), "). BUY=", buyPnl,
" SELL=", sellPnl, " Net=", netPnl);
if(netPnl >= FirstTargetUSD)
{
g_status = StringFormat("40-pip TARGET HIT! Net=%.2f >= $%.0f. Closing.", netPnl, FirstTargetUSD);
Print("v7: First target hit. Closing all.");
g_state = S_CLOSING;
return;
}
if(g_cycleCount >= MaxCycles)
{
g_status = StringFormat("MAX %d CYCLES at first decision. Closing all.", MaxCycles);
Print("v7: Max cycles at first decision. Closing.");
g_state = S_CLOSING;
return;
}
int winnerMagic, loserMagic;
double winnerPnl, loserPnl;
if(buyPnl >= sellPnl)
{
winnerMagic = g_cycles[0].magicBuy; winnerPnl = buyPnl;
loserMagic = g_cycles[0].magicSell; loserPnl = sellPnl;
}
else
{
winnerMagic = g_cycles[0].magicSell; winnerPnl = sellPnl;
loserMagic = g_cycles[0].magicBuy; loserPnl = buyPnl;
}
double lossAmt = MathAbs(loserPnl);
g_totalLocked += lossAmt;
g_cycles[0].winnerMagic = winnerMagic;
g_cycles[0].decided = true;
Print("v7: Closing loser ", MagicLabel(loserMagic), " P&L=", loserPnl,
" | Keeping ", MagicLabel(winnerMagic), " | TotalLocked=", g_totalLocked);
CloseByMagic(loserMagic);
if(!OpenNewCycle())
{
g_status = "New cycle open FAILED. Closing all.";
g_state = S_CLOSING;
return;
}
g_state = S_MONITOR;
g_status = StringFormat("Loser closed (-%.2f). Winner kept (+%.2f). Cycle %d/%d.",
lossAmt, winnerPnl, g_cycleCount, MaxCycles);
}
void HandleMonitor()
{
double totalPnl = TotalAllFloatingPnl();
double target = g_totalLocked + RecoveryExtraUSD;
if(UseFloatLock)
{
if(totalPnl > g_floatPeak) g_floatPeak = totalPnl;
if(g_floatPeak >= FloatLockMinUSD &&
totalPnl <= g_floatPeak - FloatLockDropUSD)
{
g_status = StringFormat(
"FLOAT LOCK: peak=%.2f now=%.2f dropped %.2f. Closing to protect.",
g_floatPeak, totalPnl, g_floatPeak - totalPnl);
Print("v7: ", g_status);
g_state = S_CLOSING;
return;
}
}
if(totalPnl >= target)
{
Print("v7: MONITOR target hit! TotalPnl=", totalPnl, " Target=", target);
g_status = StringFormat("RECOVERY HIT! P&L=%.2f >= %.2f. Closing ALL!", totalPnl, target);
g_state = S_CLOSING;
return;
}
double worstPnl = -RecoveryExtraUSD;
int worstMagic = 0;
for(int i = PositionsTotal()-1; i >= 0; i--)
{
if(!g_pos.SelectByIndex(i)) continue;
if(g_pos.Symbol() != _Symbol) continue;
if(!IsOurMagic((int)g_pos.Magic())) continue;
double p = g_pos.Profit() + g_pos.Swap();
if(p < worstPnl)
{
worstPnl = p;
worstMagic = (int)g_pos.Magic();
}
}
if(worstMagic != 0 && totalPnl < 0.0)
{
if(g_cycleCount < MaxCycles)
{
double lossAmt = MathAbs(worstPnl);
g_totalLocked += lossAmt;
Print("v7: Monitor re-eval. Closing worst leg ", MagicLabel(worstMagic),
" P&L=", worstPnl,
" | NewLocked=", g_totalLocked,
" | NewTarget=", g_totalLocked + RecoveryExtraUSD);
CloseByMagic(worstMagic);
if(!OpenNewCycle())
{
g_status = "Monitor recovery open FAILED. Closing all.";
g_state = S_CLOSING;
return;
}
g_status = StringFormat("Monitor: closed worst (%.2f). New pair open. Cycle %d/%d. Target=%.2f",
worstPnl, g_cycleCount, MaxCycles,
g_totalLocked + RecoveryExtraUSD);
return;
}
else
{
g_status = StringFormat("MAX %d CYCLES in monitor. Closing all.", MaxCycles);
Print("v7: Max cycles in monitor. Closing.");
g_state = S_CLOSING;
return;
}
}
string allStr = "";
for(int i = 0; i < ArraySize(g_cycles); i++)
{
if(g_cycles[i].decided)
{
if(SideHasPos(g_cycles[i].winnerMagic))
allStr += StringFormat("C%dW=%+.1f ", i+1, SidePnl(g_cycles[i].winnerMagic));
}
else
{
if(SideHasPos(g_cycles[i].magicBuy))
allStr += StringFormat("C%dB=%+.1f ", i+1, SidePnl(g_cycles[i].magicBuy));
if(SideHasPoПоказано первые 50% кода (символов: 19305)
Открыть по тарифу
Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.
Разовая покупка файла
На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.
Зачем нужен email? После подтверждения оплаты файл сохранится в кабинете на этот email. Если аккаунта ещё нет, мы создадим его и пришлём ссылку для задания пароля. Если аккаунт уже есть, покупка добавится в него. Укажите адрес, к которому у вас есть доступ.
Чтобы оформить заказ, введите email и перейдите к оплате.