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

one shoot ai v4.mq5

Похожие материалы по тегам

indicatorgoldy.pineTradingView · 1 общих теговeatelemetry.mqhMQL4 / MetaTrader 4 · 1 общих теговdrawdownmeter.mq4MQL4 / MetaTrader 4 · 1 общих теговaccountequityanalyzer@lifeindreamsworld.mq4MQL4 / MetaTrader 4 · 1 общих теговaccountequityanalyzer v1.1.mq4MQL4 / MetaTrader 4 · 1 общих теговgeniusv101-ecn.mq4MQL4 / MetaTrader 4 · 1 общих тегов
Вы автор или правообладатель?

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

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

О программе

Встроенный дашборд отображает текущие параметры работы, статистику прибыли и убытков, количество открытых и отложенных позиций. Советник поддерживает работу с несколькими символами, нормализует цены и объёмы под требования брокера, а также ведёт подробный лог операций при включённом режиме детализации.

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

НастройкаОписание
TrailingCheckMs Период проверки трейлинга — Интервал в миллисекундах между проверками состояния трейлинг-стопа и управления позициями.
FlippingMoney Переключатель расчёта маржи — При включении расчёт размера позиции ведётся от баланса, при выключении — от эквити.
FlippingFrame Рамка переключения — Параметр, используемый при формировании ключей идентификации точек разворота.
DuplicateOrderFilter Фильтр дубликатов ордеров — Блокирует размещение нового отложенного ордера, если рядом уже есть аналогичный.
DashboardShow Показ панели — Включает или отключает отображение информационной панели на графике.
GMTOffset Смещение GMT — Часовой сдвиг для расчёта времени истечения ордеров и праздничных проверок.
AutoLot Автоматический лот — Включает автоматический расчёт размера позиции на основе риска и текущего уровня маржи.
RiskManagement Управление риском — Режим или коэффициент, влияющий на расчёт допустимого размера позиции.
S1Enabled Включён символ 1 — Активирует торговлю на основном символе.
S1MagicNumber Магический номер символа 1 — Уникальный идентификатор ордеров и позиций для основного символа.
S1MaxSpread Макс. спред символа 1 — Максимально допустимый спред в пунктах для размещения ордеров на основном символе.
S1MaxSlippage Макс. проскальзывание символа 1 — Максимально допустимое проскальзывание в пунктах при исполнении ордеров.
S1InitialLot Начальный лот символа 1 — Базовый размер лота для ручного режима или минимальный размер при автоматическом расчёте.
S1SymbolManual Символ вручную символа 1 — Имя символа для ручного указания торгового инструмента; если пусто, используется текущий.
S2Enabled Включён символ 2 — Активирует торговлю на втором символе (зарезервирован, требует отдельного экземпляра).
S2MagicNumber Магический номер символа 2 — Уникальный идентификатор ордеров и позиций для второго символа.
S2MaxSpread Макс. спред символа 2 — Максимально допустимый спред в пунктах для второго символа.
S2MaxSlippage Макс. проскальзывание символа 2 — Максимально допустимое проскальзывание в пунктах при исполнении ордеров на втором символе.
S2InitialLot Начальный лот символа 2 — Базовый размер лота для второго символа.
S2SymbolManual Символ вручную символа 2 — Имя символа для ручного указания торгового инструмента второго экземпляра.
S3Enabled Включён символ 3 — Активирует торговлю на третьем символе (зарезервирован, требует отдельного экземпляра).
S3MagicNumber Магический номер символа 3 — Уникальный идентификатор ордеров и позиций для третьего символа.
S3MaxSpread Макс. спред символа 3 — Максимально допустимый спред в пунктах для третьего символа.
S3MaxSlippage Макс. проскальзывание символа 3 — Максимально допустимое проскальзывание в пунктах при исполнении ордеров на третьем символе.
S3InitialLot Начальный лот символа 3 — Базовый размер лота для третьего символа.
S3SymbolManual Символ вручную символа 3 — Имя символа для ручного указания торгового инструмента третьего экземпляра.
InpSignalTimeframe Таймфрейм сигнала — Таймфрейм, на котором анализируются точки разворота для формирования сигналов.
InpPivotWing Размах крыла пивота — Количество баров по обе стороны от кандидата, проверяемых при определении точки разворота.
InpFreshPivotBars Баров свежих пивотов — Максимальное количество баров назад, в которых ищутся новые точки разворота.
InpMaximumPendingPerSide Макс. отложенных на сторону — Лимит отложенных ордеров на одну сторону (покупка или продажа) для одного символа.
InpEntryBufferPrice Буфер цены входа — Дополнительный ценовой буфер при размещении отложенного ордера относительно уровня пивота.
InpInitialStopPrice Начальная цена стопа — Расстояние в ценовых единицах от точки входа до начального стоп-лосса.
InpFridayExpiration Истечение в пятницу — Включает автоматическое закрытие и удаление ордеров в пятницу по заданному времени.
InpExpirationHour Час истечения — Час срабатывания автоматического закрытия позиций и удаления ордеров в пятницу.
InpExpirationMinute Минута истечения — Минута срабатывания автоматического закрытия позиций и удаления ордеров в пятницу.
InpUseTrendQualityFilter Фильтр качества тренда — Включает дополнительную проверку направления тренда через скользящую среднюю перед размещением ордера.
InpTrendEMAPeriod Период EMA фильтра — Период экспоненциальной скользящей средней, используемой в фильтре качества тренда.
InpEnableIntrabarEngine Включить внутрибарный движок — Активирует дополнительный анализ на более коротком таймфрейме для ускоренного входа в сделку.
InpIntrabarTimeframe Внутрибарный таймфрейм — Таймфрейм, используемый внутрибарным движком для поиска точек разворота внутри основного бара.
InpIntrabarPivotWing Размах крыла внутрибарного пивота — Размах проверки точки разворота на внутрибарном таймфрейме.
InpIntrabarRangeBars Баров диапазона внутрибарного — Количество баров, анализируемых для определения ценового диапазона при внутрибарном сигнале.
InpIntrabarMinimumRangePrice Мин. диапазон цены внутрибарного — Минимальный ценовой диапазон, необходимый для подтверждения внутрибарного сигнала.
InpIntrabarRangeATRMultiplier Множитель ATR диапазона — Множитель ATR, определяющий минимальный требуемый диапазон для внутрибарного сигнала.
InpIntrabarCooldownMinutes Кулдаун минут внутрибарного — Минимальный интервал в минутах между последовательными внутрибарными сигналами одной стороны.
InpIntrabarUseM30TrendBias Использовать смещение тренда M30 — При включении внутрибарный сигнал учитывает направление тренда на основном M30.
InpIntrabarRequireFreshExtreme Требовать свежий экстремум — При включении требует, чтобы экстремум на внутрибарном таймфрейме был свежим и не перекрывался старыми.
InpIntrabarExtremeLookback Просмотр экстремума внутрибарного — Количество баров назад для поиска предыдущего экстремума при проверке свежести.
InpReframeCrossedLevels Переопределение пересечённых уровней — При включении позволяет скорректировать цену ордера, если она пересекла допустимый уровень, вместо отказа.
InpMaximumPositionsTotal Макс. всего позиций — Глобальный лимит одновременно открытых позиций для основного символа.
InpMaximumAggregateRiskPercent Макс. совокупный риск % — Максимальный допустимый процент эквити, который может быть подвержен риску по всем открытым позициям.
InpTrailArmPrice Цена активации трейла — Ценовое расстояние от входа, при достижении которого начинается активация трейлинг-стопа.
InpTrailDistancePrice Расстояние трейла цена — Ценовое расстояние от текущей цены до уровня трейлинг-стопа.
InpTrailStepPrice Шаг трейла цена — Минимальное ценовое смещение, при котором трейлинг-стоп перемещается дальше.
InpUseVirtualBrokerFallback Виртуальный брокер-фолбэк — При включении использует виртуальный уровень стопа в глобальных переменных как дополнительную защиту.
InpMaximumCloseAttempts Макс. попыток закрытия — Максимальное количество попыток закрытия позиции при неудачном исполнении.
InpHolidayFlatProtection Праздничная защита плоскости — При включении принудительно закрывает все позиции и удаляет ордера в праздничные дни.
InpHolidayCloseHour Час закрытия праздника — Час, начиная с которого включается праздничная защита и закрытие позиций.
InpStrategyPoint Пункт стратегии — Базовая ценовая единица, используемая для нормализации расчётов под требования брокера.
InpMaximumFillGapPrice Макс. разрыв заполнения — Максимально допустимая разница между ценой заявки и ценой заполнения сделки.
InpRejectInsteadOfDistortEntry Отказ вместо искажения входа — При включении отклоняет сигнал, если цена пересекла уровень, вместо того чтобы смещать вход.
InpVerboseLog Подробный лог — Включает детальное логирование операций в журнал эксперта.
InpDashboardCorner Угол дашборда — Угол экрана, в котором будет размещена информационная панель.
InpDashboardX Позиция X дашборда — Горизонтальное смещение панели от выбранного угла в пикселях.
InpDashboardY Позиция Y дашборда — Вертикальное смещение панели от выбранного угла в пикселях.
InpDashboardWidth Ширина дашборда — Ширина информационной панели в пикселях.
InpDashboardFontSize Размер шрифта дашборда — Базовый размер шрифта текста на информационной панели.
Получить полный код

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

#property strict
#property version   "4.0"

#property description "Enhanced clean-room multi-frame swing-breakout engine for MT5"
#property description "Broker-normalized execution, portfolio risk control, and ultra-fast trailing"

#include <Trade/Trade.mqh>

input group "OBSERVED PRESET INTERFACE"
input uint   TrailingCheckMs=1;
input bool   FlippingMoney=false;
input int    FlippingFrame=1;
input bool   DuplicateOrderFilter=false;
input bool   DashboardShow=true;
input int    GMTOffset=3;
input bool   AutoLot=true;
input int    RiskManagement=1;

input group "SYMBOL 1"
input bool   S1Enabled=true;
input ulong  S1MagicNumber=111101;
input int    S1MaxSpread=65;
input int    S1MaxSlippage=65;
input double S1InitialLot=0.01;
input string S1SymbolManual="";

input group "SYMBOL 2 (RESERVED; ATTACH A SECOND INSTANCE)"
input bool   S2Enabled=false;
input ulong  S2MagicNumber=111102;
input int    S2MaxSpread=65;
input int    S2MaxSlippage=65;
input double S2InitialLot=0.01;
input string S2SymbolManual="";

input group "SYMBOL 3 (RESERVED; ATTACH A THIRD INSTANCE)"
input bool   S3Enabled=false;
input ulong  S3MagicNumber=111103;
input int    S3MaxSpread=65;
input int    S3MaxSlippage=65;
input double S3InitialLot=0.01;
input string S3SymbolManual="";

input group "CLEAN-ROOM BREAKOUT MODEL"
input ENUM_TIMEFRAMES InpSignalTimeframe=PERIOD_M30;
input int             InpPivotWing=2;
input int             InpFreshPivotBars=96;
input int             InpMaximumPendingPerSide=8;
input double          InpEntryBufferPrice=0.01;
input double          InpInitialStopPrice=5.00;
input bool            InpFridayExpiration=true;
input int             InpExpirationHour=20;
input int             InpExpirationMinute=55;
input bool            InpUseTrendQualityFilter=false;
input int             InpTrendEMAPeriod=34;

input group "ENHANCED INTRABAR HUNT ENGINE"
input bool            InpEnableIntrabarEngine=false;
input ENUM_TIMEFRAMES InpIntrabarTimeframe=PERIOD_M1;
input int             InpIntrabarPivotWing=2;
input int             InpIntrabarRangeBars=16;
input double          InpIntrabarMinimumRangePrice=1.80;
input double          InpIntrabarRangeATRMultiplier=2.40;
input int             InpIntrabarCooldownMinutes=45;
input bool            InpIntrabarUseM30TrendBias=true;
input bool            InpIntrabarRequireFreshExtreme=true;
input int             InpIntrabarExtremeLookback=30;
input bool            InpReframeCrossedLevels=false;
input int             InpMaximumPositionsTotal=10;
input double          InpMaximumAggregateRiskPercent=120.0;

input group "ULTRA-FAST EXIT ENGINE"
input double InpTrailArmPrice=0.28;
input double InpTrailDistancePrice=0.05;
input double InpTrailStepPrice=0.01;
input bool   InpUseVirtualBrokerFallback=true;
input int    InpMaximumCloseAttempts=3;
input bool   InpHolidayFlatProtection=false;
input int    InpHolidayCloseHour=18;

input group "CROSS-BROKER NORMALIZATION"
input double InpStrategyPoint=0.01;
input double InpMaximumFillGapPrice=0.0;
input bool   InpRejectInsteadOfDistortEntry=true;
input bool   InpVerboseLog=false;

input group "MATCHING DASHBOARD"
input ENUM_BASE_CORNER InpDashboardCorner=CORNER_LEFT_UPPER;
input int              InpDashboardX=18;
input int              InpDashboardY=35;
input int              InpDashboardWidth=610;
input int              InpDashboardFontSize=11;

CTrade g_trade;
string g_symbol="";
datetime g_lastSignalBar=0;
datetime g_lastIntrabarBar=0;
datetime g_lastIntrabarBuy=0;
datetime g_lastIntrabarSell=0;
long g_seenPivots[];
int g_ema=INVALID_HANDLE;
int g_intrabarATR=INVALID_HANDLE;
string g_uiPrefix="OSV4_UI_";
ulong g_lastDashboardMs=0;
double g_peakEquity=0.0;

double SymPoint()
  {
   double value=SymbolInfoDouble(g_symbol,SYMBOL_POINT);
   return (value>0.0 ? value : 0.00001);
  }

double TickSize()
  {
   double value=SymbolInfoDouble(g_symbol,SYMBOL_TRADE_TICK_SIZE);
   return (value>0.0 ? value : SymPoint());
  }

double PriceFloor(const double value)
  {
   double tick=TickSize();
   return NormalizeDouble(MathFloor((value+1e-10)/tick)*tick,(int)SymbolInfoInteger(g_symbol,SYMBOL_DIGITS));
  }

double PriceCeil(const double value)
  {
   double tick=TickSize();
   return NormalizeDouble(MathCeil((value-1e-10)/tick)*tick,(int)SymbolInfoInteger(g_symbol,SYMBOL_DIGITS));
  }

double NormalizeVolume(const double requested)
  {
   double minimum=SymbolInfoDouble(g_symbol,SYMBOL_VOLUME_MIN);
   double maximum=SymbolInfoDouble(g_symbol,SYMBOL_VOLUME_MAX);
   double step=SymbolInfoDouble(g_symbol,SYMBOL_VOLUME_STEP);
   if(step<=0.0) step=minimum;
   if(step<=0.0) return 0.0;
   double volume=MathFloor((MathMin(maximum,MathMax(minimum,requested))+1e-12)/step)*step;
   int digits=0;
   double probe=step;
   while(digits<8 && MathAbs(probe-MathRound(probe))>1e-9) { probe*=10.0; digits++; }
   return NormalizeDouble(volume,digits);
  }

double BrokerMinimumDistance()
  {
   long stops=SymbolInfoInteger(g_symbol,SYMBOL_TRADE_STOPS_LEVEL);
   long freeze=SymbolInfoInteger(g_symbol,SYMBOL_TRADE_FREEZE_LEVEL);
   return MathMax((double)stops,(double)freeze)*SymPoint()+TickSize();
  }

string ResolveSymbol(const string requested)
  {
   if(requested=="") return _Symbol;
   bool custom=false;
   if(SymbolExist(requested,custom) && SymbolSelect(requested,true)) return requested;
   if(StringFind(_Symbol,requested)==0) return _Symbol;
   int total=SymbolsTotal(false);
   for(int i=0;i<total;i++)
     {
      string candidate=SymbolName(i,false);
      if(StringFind(candidate,requested)==0 && SymbolSelect(candidate,true)) return candidate;
     }
   total=SymbolsTotal(true);
   for(int i=0;i<total;i++)
     {
      string candidate=SymbolName(i,true);
      if(StringFind(candidate,requested)==0) return candidate;
     }
   return "";
  }

bool SpreadAllowed()
  {
   MqlTick tick;
   if(!SymbolInfoTick(g_symbol,tick) || tick.ask<=0.0 || tick.bid<=0.0) return false;
   double unit=(InpStrategyPoint>0.0 ? InpStrategyPoint : SymPoint());
   return (tick.ask-tick.bid)<=S1MaxSpread*unit+TickSize()*0.5;
  }

bool IsPivotHighTF(const ENUM_TIMEFRAMES timeframe,const int wing,const int shift)
  {
   double value=iHigh(g_symbol,timeframe,shift);
   if(value<=0.0) return false;
   for(int i=1;i<=wing;i++)
      if(iHigh(g_symbol,timeframe,shift-i)>=value || iHigh(g_symbol,timeframe,shift+i)>value) return false;
   return true;
  }

bool IsPivotLowTF(const ENUM_TIMEFRAMES timeframe,const int wing,const int shift)
  {
   double value=iLow(g_symbol,timeframe,shift);
   if(value<=0.0) return false;
   for(int i=1;i<=wing;i++)
      if(iLow(g_symbol,timeframe,shift-i)<=value || iLow(g_symbol,timeframe,shift+i)<value) return false;
   return true;
  }

bool IsPivotHigh(const int shift)
  {
   return IsPivotHighTF(InpSignalTimeframe,InpPivotWing,shift);
  }

bool IsPivotLow(const int shift)
  {
   return IsPivotLowTF(InpSignalTimeframe,InpPivotWing,shift);
  }

long PivotKey(const datetime pivotTime,const bool buy,const int engine)
  {
   return (long)pivotTime*4+(long)engine*2+(buy ? 1 : 0);
  }

bool PivotWasSeen(const long key)
  {
   for(int i=0;i<ArraySize(g_seenPivots);i++) if(g_seenPivots[i]==key) return true;
   return false;
  }

void MarkPivotSeen(const long key)
  {
   if(PivotWasSeen(key)) return;
   int size=ArraySize(g_seenPivots);
   ArrayResize(g_seenPivots,size+1);
   g_seenPivots[size]=key;
   if(ArraySize(g_seenPivots)>2000)
     {
      for(int i=500;i<ArraySize(g_seenPivots);i++) g_seenPivots[i-500]=g_seenPivots[i];
      ArrayResize(g_seenPivots,1500);
     }
  }

int PendingCount(const bool buy)
  {
   int count=0;
   for(int i=OrdersTotal()-1;i>=0;i--)
     {
      ulong ticket=OrderGetTicket(i);
      if(ticket==0 || !OrderSelect(ticket)) continue;
      if(OrderGetString(ORDER_SYMBOL)!=g_symbol || (ulong)OrderGetInteger(ORDER_MAGIC)!=S1MagicNumber) continue;
      long type=OrderGetInteger(ORDER_TYPE);
      if((buy && type==ORDER_TYPE_BUY_STOP) || (!buy && type==ORDER_TYPE_SELL_STOP)) count++;
     }
   return count;
  }

bool PendingNear(const bool buy,const double price)
  {
   double tolerance=MathMax(TickSize(),InpEntryBufferPrice)*1.5;
   for(int i=OrdersTotal()-1;i>=0;i--)
     {
      ulong ticket=OrderGetTicket(i);
      if(ticket==0 || !OrderSelect(ticket)) continue;
      if(OrderGetString(ORDER_SYMBOL)!=g_symbol || (ulong)OrderGetInteger(ORDER_MAGIC)!=S1MagicNumber) continue;
      long type=OrderGetInteger(ORDER_TYPE);
      if((buy && type!=ORDER_TYPE_BUY_STOP) || (!buy && type!=ORDER_TYPE_SELL_STOP)) continue;
      if(MathAbs(OrderGetDouble(ORDER_PRICE_OPEN)-price)<=tolerance) return true;
     }
   return false;
  }

int ManagedPositionCount()
  {
   int count=0;
   for(int i=PositionsTotal()-1;i>=0;i--)
     {
      ulong ticket=PositionGetTicket(i);
      if(ticket==0 || !PositionSelectByTicket(ticket)) continue;
      if(PositionGetString(POSITION_SYMBOL)==g_symbol && (ulong)PositionGetInteger(POSITION_MAGIC)==S1MagicNumber) count++;
     }
   return count;
  }

double LossAtStop(const ENUM_ORDER_TYPE type,const double volume,const double open,const double stop)
  {
   if(volume<=0.0 || open<=0.0 || stop<=0.0) return 0.0;
   double result=0.0;
   if(!OrderCalcProfit(type,g_symbol,volume,open,stop,result)) return 0.0;
   return MathMax(0.0,-result);
  }

double AggregateOpenRiskMoney()
  {
   double risk=0.0;
   for(int i=PositionsTotal()-1;i>=0;i--)
     {
      ulong ticket=PositionGetTicket(i);
      if(ticket==0 || !PositionSelectByTicket(ticket)) continue;
      if(PositionGetString(POSITION_SYMBOL)!=g_symbol || (ulong)PositionGetInteger(POSITION_MAGIC)!=S1MagicNumber) continue;
      bool buy=PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY;
      double open=PositionGetDouble(POSITION_PRICE_OPEN);
      double sl=PositionGetDouble(POSITION_SL);
      risk+=LossAtStop((buy ? ORDER_TYPE_BUY : ORDER_TYPE_SELL),PositionGetDouble(POSITION_VOLUME),open,sl);
     }
   for(int i=OrdersTotal()-1;i>=0;i--)
     {
      ulong ticket=OrderGetTicket(i);
      if(ticket==0 || !OrderSelect(ticket)) continue;
      if(OrderGetString(ORDER_SYMBOL)!=g_symbol || (ulong)OrderGetInteger(ORDER_MAGIC)!=S1MagicNumber) continue;
      long type=OrderGetInteger(ORDER_TYPE);
      if(type!=ORDER_TYPE_BUY_STOP && type!=ORDER_TYPE_SELL_STOP) continue;
      risk+=LossAtStop((type==ORDER_TYPE_BUY_STOP ? ORDER_TYPE_BUY : ORDER_TYPE_SELL),OrderGetDouble(ORDER_VOLUME_CURRENT),OrderGetDouble(ORDER_PRICE_OPEN),OrderGetDouble(ORDER_SL));
     }
   return risk;
  }

bool AggregateRiskAllows(const bool buy,const double volume,const double entry,const double stop)
  {
   if(InpMaximumAggregateRiskPercent<=0.0) return true;
   double equity=AccountInfoDouble(ACCOUNT_EQUITY);
   double newRisk=LossAtStop((buy ? ORDER_TYPE_BUY : ORDER_TYPE_SELL),volume,entry,stop);
   return AggregateOpenRiskMoney()+newRisk<=equity*InpMaximumAggregateRiskPercent/100.0+0.01;
  }

datetime ExpirationTime()
  {
   if(!InpFridayExpiration) return 0;
   datetime now=TimeCurrent();
   MqlDateTime dt;
   TimeToStruct(now,dt);
   int days=(5-dt.day_of_week+7)%7;
   if(days==0 && (dt.hour>InpExpirationHour || (dt.hour==InpExpirationHour && dt.min>=InpExpirationMinute))) days=7;
   datetime target=now+days*86400;
   TimeToStruct(target,dt);
   dt.hour=InpExpirationHour; dt.min=InpExpirationMinute; dt.sec=0;
   return StructToTime(dt);
  }

double EntryVolume(const bool buy,const double entry,const double stop)
  {
   if(!AutoLot) return NormalizeVolume(S1InitialLot);
   double oneLotLoss=0.0;
   ENUM_ORDER_TYPE type=(buy ? ORDER_TYPE_BUY : ORDER_TYPE_SELL);
   if(!OrderCalcProfit(type,g_symbol,1.0,entry,stop,oneLotLoss) || oneLotLoss>=0.0) return NormalizeVolume(S1InitialLot);

   double riskPercent=MathMax(0.1,(double)RiskManagement*10.0);
   double base=(FlippingMoney ? AccountInfoDouble(ACCOUNT_BALANCE) : AccountInfoDouble(ACCOUNT_EQUITY));
   double volume=(base*riskPercent/100.0)/MathAbs(oneLotLoss);
   return NormalizeVolume(MathMax(S1InitialLot,volume));
  }

bool TrendAllows(const bool buy,const int pivotShift)
  {
   if(!InpUseTrendQualityFilter) return true;
   double ema[1];
   if(g_ema==INVALID_HANDLE || CopyBuffer(g_ema,0,pivotShift,1,ema)!=1) return false;
   double close=iClose(g_symbol,InpSignalTimeframe,pivotShift);
   return (buy ? close>=ema[0] : close<=ema[0]);
  }

bool SubmitPivot(const bool buy,const datetime pivotTime,const double rawPrice,const int pivotShift,const int engine)
  {
   long key=PivotKey(pivotTime,buy,engine);
   if(PivotWasSeen(key)) return false;
   if(engine==0 && !TrendAllows(buy,pivotShift)) { MarkPivotSeen(key); return false; }
   if(InpMaximumPositionsTotal>0 && ManagedPositionCount()>=InpMaximumPositionsTotal) return false;
   if(PendingCount(buy)>=InpMaximumPendingPerSide) return false;
   double entry=(buy ? PriceCeil(rawPrice+InpEntryBufferPrice) : PriceFloor(rawPrice-InpEntryBufferPrice));
   if(DuplicateOrderFilter && PendingNear(buy,entry)) { MarkPivotSeen(key); return false; }

   MqlTick tick;
   if(!SymbolInfoTick(g_symbol,tick)) return false;
   double minimum=BrokerMinimumDistance();
   bool legal=(buy ? entry>=tick.ask+minimum : entry<=tick.bid-minimum);
   if(!legal && InpReframeCrossedLevels)
     {
      entry=(buy ? PriceCeil(tick.ask+minimum) : PriceFloor(tick.bid-minimum));
      legal=(buy ? entry>=tick.ask+minimum-TickSize()*0.5 : entry<=tick.bid-minimum+TickSize()*0.5);
      if(DuplicateOrderFilter && PendingNear(buy,entry)) { MarkPivotSeen(key); return false; }
     }
   if(!legal)
     {

      if(InpRejectInsteadOfDistortEntry) MarkPivotSeen(key);
      return false;
     }
   double stop=(buy ? PriceFloor(entry-InpInitialStopPrice) : PriceCeil(entry+InpInitialStopPrice));
   if(MathAbs(entry-stop)<minimum) stop=(buy ? PriceFloor(entry-minimum) : PriceCeil(entry+minimum));
   double volume=EntryVolume(buy,entry,stop);
   if(volume<=0.0) return false;
   if(!AggregateRiskAllows(buy,volume,entry,stop)) return false;
   datetime expiry=ExpirationTime();
   ENUM_ORDER_TYPE_TIME timeType=(expiry>0 ? ORDER_TIME_SPECIFIED : ORDER_TIME_GTC);
   string comment=(engine==0 ? "OSV4 M30 " : "OSV4 FAST ")+(buy ? "BUY" : "SELL");
   bool sent=(buy ? g_trade.BuyStop(volume,entry,g_symbol,stop,0.0,timeType,expiry,comment)
                  : g_trade.SellStop(volume,entry,g_symbol,stop,0.0,timeType,expiry,comment));
   if(sent)
     {
      MarkPivotSeen(key);
      if(InpVerboseLog) Print("One Shoot CR: armed ",comment," @ ",DoubleToString(entry,(int)SymbolInfoInteger(g_symbol,SYMBOL_DIGITS))," from ",TimeToString(pivotTime));
      return true;
     }
   uint retcode=g_trade.ResultRetcode();
   if(retcode==TRADE_RETCODE_INVALID_EXPIRATION)
     {
      sent=(buy ? g_trade.BuyStop(volume,entry,g_symbol,stop,0.0,ORDER_TIME_GTC,0,comment)
                : g_trade.SellStop(volume,entry,g_symbol,stop,0.0,ORDER_TIME_GTC,0,comment));
      if(sent) { MarkPivotSeen(key); return true; }
     }
   if(InpVerboseLog) Print("One Shoot CR: pending rejected ",g_trade.ResultRetcode()," ",g_trade.ResultRetcodeDescription());
   return false;
  }

void ScanFreshPivots()
  {
   if(!S1Enabled || !SpreadAllowed()) return;
   int bars=Bars(g_symbol,InpSignalTimeframe);
   if(bars<InpPivotWing*2+20) return;
   int start=InpPivotWing+1;
   int maximum=MathMin(InpFreshPivotBars,bars-InpPivotWing-1);
   bool needBuy=PendingCount(true)<InpMaximumPendingPerSide;
   bool needSell=PendingCount(false)<InpMaximumPendingPerSide;
   for(int shift=start;shift<=maximum && (needBuy || needSell);shift++)
     {
      datetime pivotTime=iTime(g_symbol,InpSignalTimeframe,shift);
      if(pivotTime<=0) continue;
      if(needBuy && IsPivotHigh(shift))
        {
         SubmitPivot(true,pivotTime,iHigh(g_symbol,InpSignalTimeframe,shift),shift,0);
         needBuy=PendingCount(true)<InpMaximumPendingPerSide;
        }
      if(needSell && IsPivotLow(shift))
        {
         SubmitPivot(false,pivotTime,iLow(g_symbol,InpSignalTimeframe,shift),shift,0);
         needSell=PendingCount(false)<InpMaximumPendingPerSide;
        }
     }
  }

double IntrabarATRValue(const int shift)
  {
   double value[1];
   if(g_intrabarATR==INVALID_HANDLE || CopyBuffer(g_intrabarATR,0,shift,1,value)!=1) return 0.0;
   return value[0];
  }

bool IntrabarRangeAllows(const bool buy,const int shift)
  {
   int from=MathMax(1,shift-InpIntrabarPivotWing);
   int count=MathMax(InpIntrabarRangeBars,InpIntrabarPivotWing*2+3);
   int highIndex=iHighest(g_symbol,InpIntrabarTimeframe,MODE_HIGH,count,from);
   int lowIndex=iLowest(g_symbol,InpIntrabarTimeframe,MODE_LOW,count,from);
   if(highIndex<0 || lowIndex<0) return false;
   double pivot=(buy ? iHigh(g_symbol,InpIntrabarTimeframe,shift) : iLow(g_symbol,InpIntrabarTimeframe,shift));
   double opposite=(buy ? iLow(g_symbol,InpIntrabarTimeframe,lowIndex) : iHigh(g_symbol,InpIntrabarTimeframe,highIndex));
   double range=MathAbs(pivot-opposite);
   double required=MathMax(InpIntrabarMinimumRangePrice,IntrabarATRValue(shift)*InpIntrabarRangeATRMultiplier);
   if(range+TickSize()*0.5<required) return false;
   if(InpIntrabarRequireFreshExtreme)
     {
      int olderFrom=shift+InpIntrabarPivotWing+1;
      int lookback=MathMax(5,InpIntrabarExtremeLookback);
      int extreme=(buy ? iHighest(g_symbol,InpIntrabarTimeframe,MODE_HIGH,lookback,olderFrom)
                       : iLowest(g_symbol,InpIntrabarTimeframe,MODE_LOW,lookback,olderFrom));
      if(extreme<0) return false;
      double older=(buy ? iHigh(g_symbol,InpIntrabarTimeframe,extreme) : iLow(g_symbol,InpIntrabarTimeframe,extreme));
      if((buy && pivot<older-TickSize()*0.5) || (!buy && pivot>older+TickSize()*0.5)) return false;
     }
   return true;
  }

bool IntrabarTrendAllows(const bool buy)
  {
   if(!InpIntrabarUseM30TrendBias) return true;
   double ema1[1],ema2[1];
   if(g_ema==INVALID_HANDLE || CopyBuffer(g_ema,0,1,1,ema1)!=1 || CopyBuffer(g_ema,0,2,1,ema2)!=1) return false;
   double close1=iClose(g_symbol,InpSignalTimeframe,1);
   if(close1<=0.0) return false;
   return (buy ? close1>=ema1[0] && ema1[0]>=ema2[0]
               : close1<=ema1[0] && ema1[0]<=ema2[0]);
  }

void ScanIntrabarPivot()
  {
   if(!InpEnableIntrabarEngine || !S1Enabled || !SpreadAllowed()) return;
   int wing=MathMax(1,InpIntrabarPivotWing);
   int shift=wing+1;
   if(Bars(g_symbol,InpIntrabarTimeframe)<InpIntrabarRangeBars+shift+10) return;
   datetime pivotTime=iTime(g_symbol,InpIntrabarTimeframe,shift);
   if(pivotTime<=0) return;
   datetime now=TimeCurrent();
   int cooldown=MathMax(0,InpIntrabarCooldownMinutes)*60;
   if(IsPivotHighTF(InpIntrabarTimeframe,wing,shift) && IntrabarRangeAllows(true,shift) && IntrabarTrendAllows(true) && (cooldown==0 || now-g_lastIntrabarBuy>=cooldown))
     {
      if(SubmitPivot(true,pivotTime,iHigh(g_symbol,InpIntrabarTimeframe,shift),shift,1)) g_lastIntrabarBuy=now;
     }
   if(IsPivotLowTF(InpIntrabarTimeframe,wing,shift) && IntrabarRangeAllows(false,shift) && IntrabarTrendAllows(false) && (cooldown==0 || now-g_lastIntrabarSell>=cooldown))
     {
      if(SubmitPivot(false,pivotTime,iLow(g_symbol,InpIntrabarTimeframe,shift),shift,1)) g_lastIntrabarSell=now;
     }
  }

string VirtualKey(const ulong ticket)
  {
   return "OSCR_"+(string)S1MagicNumber+"_"+(string)ticket;
  }

string GapRejectKey(const ulong identifier)
  {
   return "OSCR_GAP_"+(string)S1MagicNumber+"_"+(string)identifier;
  }

void MarkGapRejected(const ulong identifier)
  {
   GlobalVariableSet(GapRejectKey(identifier),1.0);
  }

bool GapWasRejected(const ulong identifier)
  {
   return GlobalVariableCheck(GapRejectKey(identifier));
  }

void ClearGapRejected(const ulong identifier)
  {
   string key=GapRejectKey(identifier);
   if(GlobalVariableCheck(key)) GlobalVariableDel(key);
  }

double VirtualStop(const ulong ticket)
  {
   string key=VirtualKey(ticket);
   return (GlobalVariableCheck(key) ? GlobalVariableGet(key) : 0.0);
  }

void SetVirtualStop(const ulong ticket,const double value)
  {
   string key=VirtualKey(ticket);
   if(value>0.0) GlobalVariableSet(key,value);
  }

void ClearVirtualStop(const ulong ticket)
  {
   string key=VirtualKey(ticket);
   if(GlobalVariableCheck(key)) GlobalVariableDel(key);
  }

bool ClosePositionFast(const ulong ticket)
  {
   for(int attempt=0;attempt<MathMax(1,InpMaximumCloseAttempts);attempt++)
     {
      if(!PositionSelectByTicket(ticket)) return true;
      if(g_trade.PositionClose(ticket,S1MaxSlippage)) return true;
     }
   if(InpVerboseLog) Print("One Shoot CR: close rejected ",ticket," ",g_trade.ResultRetcode()," ",g_trade.ResultRetcodeDescription());
   return false;
  }

ulong FindPositionTicketByIdentifier(const ulong identifier)
  {
   for(int i=PositionsTotal()-1;i>=0;i--)
     {
      ulong ticket=PositionGetTicket(i);
      if(ticket==0 || !PositionSelectByTicket(ticket)) continue;
      if(PositionGetString(POSITION_SYMBOL)!=g_symbol || (ulong)PositionGetInteger(POSITION_MAGIC)!=S1MagicNumber) continue;
      if((ulong)PositionGetInteger(POSITION_IDENTIFIER)==identifier || ticket==identifier) return ticket;
     }
   return 0;
  }

void AnchorStopToActualFill(const ulong positionIdentifier,const bool buy,const double fillPrice)
  {
   ulong ticket=FindPositionTicketByIdentifier(positionIdentifier);
   if(ticket==0 || !PositionSelectByTicket(ticket)) return;
   MqlTick tick;
   if(!SymbolInfoTick(g_symbol,tick)) return;
   double minimum=BrokerMinimumDistance();
   double desired=(buy ? PriceFloor(fillPrice-InpInitialStopPrice) : PriceCeil(fillPrice+InpInitialStopPrice));
   double current=(buy ? tick.bid : tick.ask);
   if((buy && current<=desired) || (!buy && current>=desired))
     {

      ClosePositionFast(ticket);
      return;
     }
   double legal=(buy ? PriceFloor(MathMin(desired,tick.bid-minimum))
                     : PriceCeil(MathMax(desired,tick.ask+minimum)));
   double tp=PositionGetDouble(POSITION_TP);
   if(!g_trade.PositionModify(ticket,legal,tp))
     {
      if(InpVerboseLog) Print("One Shoot CR: protection attach failed; closing ",ticket," ",g_trade.ResultRetcode()," ",g_trade.ResultRetcodeDescription());
      ClosePositionFast(ticket);
     }
  }

void ManagePositions()
  {
   MqlTick tick;
   if(!Symb

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

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

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

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

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

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

Стоимость полного кода
3 827,20₽ ≈ $46.78