one shoot ai v4.mq5
Похожие материалы по тегам
Сообщите нам, если считаете, что материал размещён без разрешения.
Сообщить о материале
Обращение по товару «one shoot ai v4.mq5» отправится на рассмотрение. Укажите контакт для ответа и опишите причину.
О программе
Встроенный дашборд отображает текущие параметры работы, статистику прибыли и убытков, количество открытых и отложенных позиций. Советник поддерживает работу с несколькими символами, нормализует цены и объёмы под требования брокера, а также ведёт подробный лог операций при включённом режиме детализации.
Настройки программы
| Настройка | Описание |
|---|---|
| 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? После подтверждения оплаты файл сохранится в кабинете на этот email. Если аккаунта ещё нет, мы создадим его и пришлём ссылку для задания пароля. Если аккаунт уже есть, покупка добавится в него. Укажите адрес, к которому у вас есть доступ.
Чтобы оформить заказ, введите email и перейдите к оплате.