NAIF NEW BOT

Expert Advisor type
NAIF NEW BOT
Type
EA
Platform
Not specified
Version
Not specified
Category
Expert Advisor type
Date
10/18/2026
Pricing
70000 Coins

Description

enum ENUM_NRISK  { NR_LOW = 0, NR_MEDIUM = 1, NR_HIGH = 2 };
enum ENUM_NDIR   { ND_BOTH = 0, ND_BUY_ONLY = 1, ND_SELL_ONLY = 2 };
enum ENUM_NTREND { NT_FOLLOW = 0, NT_REVERSE = 1 };
enum ENUM_NRED   { NRED_MONEY = 0, NRED_PERCENT = 1 };

input group "=== RISK / LOT ==="
input ENUM_NRISK InpRisk          = NR_MEDIUM; // risk level: LOW 0.005 / MEDIUM 0.01 / HIGH 0.02 lot per 1000 of balance
input double InpLotSizeMultiplier = 1.0;       // multiply the auto lot
input double InpLotSize           = 0.0;       // FIXED first lot (0 = auto by risk level)
input double InpMaxAutoLot        = 1.0;       // max first lot in auto mode
input double InpCustomBalance     = 0.0;       // calculate lot as if balance = this (0 = real balance)
input int    InpMaxSpread         = 0;         // max spread in points to open (0 = off)

input group "=== RECOVERY CHAIN ==="
input int    InpRecovery          = 8;         // max trades in one chain (1 = no recovery)
input int    InpFixDistance       = 0;         // fixed distance between trades in points (0 = auto ATR)
input double InpAtrDistFactor     = 1.0;       // auto distance = ATR(H1,14) x this
input int    InpMinDistance       = 0;         // min distance points (0 = off)
input int    InpMaxDistance       = 0;         // max distance points (0 = off)
input double InpDistMultiplier    = 1.2;       // each next distance x this (1.0 = equal steps)
input double InpRecoveryLotMult   = 1.0;       // each next lot x this (1.0 = same lot, >1 = martingale)
input string InpSpacingList       = "";        // optional custom distances in points, e.g. "300,400,600,900"

input group "=== CHAIN PROFIT EXIT ==="
input double InpMinProfit         = 0.0;       // chain target in money (0 = auto)
input double InpAutoProfitMult    = 1.0;       // auto target = profit of first lot moving half a distance x this
input double InpBreakEvenAfter    = 0;         // after N trades in chain, target = break-even + this money (0 = off)
input int    InpReduceDelayMin    = 240;       // profit reduction: start after N minutes (0 = off)
input int    InpReduceStepMin     = 60;        // reduce every N minutes
input ENUM_NRED InpReduceType     = NRED_PERCENT; // reduce by money or % of the target
input double InpReduceValue       = 15;        // reduce amount per step
input double InpMinNetProfit      = 0.0;       // never reduce below this money (0 = break-even)
input double InpTrailStart        = 0.0;       // basket trailing: start when chain profit >= this money (0 = off)
input double InpTrailDist         = 0.0;       // basket trailing: close if profit falls this money from its peak

input group "=== PROTECTION ==="
input double InpMaxChainDDPct     = 20;        // close a chain when its loss reaches x% of balance (0 = off)
input int    InpPauseAfterChainDD = 120;       // minutes without new chains after that (0 = none)
input int    InpChainStopPoints   = 0;         // close chain if price is x points against the FIRST entry (0 = off)
input double InpDailyLossPct      = 10;        // daily loss % -> close all, stop today (0 = off)
input double InpWeeklyLossPct     = 20;        // weekly loss % -> close all, stop this week (0 = off)
input double InpHardStopPct       = 35;        // equity x% below peak balance -> close all (0 = off)
input bool   InpPauseOnHardStop   = true;      // after hard stop: stop until EA restart
input double InpEquityStop        = 0;         // equity below this money -> close all + stop (0 = off)
input bool   InpOneChainAtATime   = true;      // only one chain (buy OR sell) at a time
input int    InpMaxChainsPerDay   = 0;         // max new chains per day (0 = off)
input double InpDailyTargetMoney  = 0;         // daily profit target money -> no new chains today (0 = off)
input double InpDailyTargetPct    = 0;         // daily profit target % -> no new chains today (0 = off)

input group "=== SIGNAL ==="
input ENUM_TIMEFRAMES InpSignalTF = PERIOD_M15; // signal timeframe
input bool   InpUseAIScore        = true;      // AI score: weighted model of trend, RSI, MACD, slope, candle
input double InpAIThreshold       = 0.35;      // AI score needed (0..1), higher = fewer, stronger signals
input ENUM_NTREND InpTrendMode    = NT_FOLLOW; // FOLLOW the signal or REVERSE it (fade)
input bool   InpUseSR             = false;     // bounce from support / resistance (last 50 bars)
input bool   InpUseCandle         = false;     // engulfing candle patterns
input bool   InpUseTrend          = false;     // EMA 20 / 50 cross
input bool   InpUsePrice          = false;     // close above / below previous candle range
input ENUM_NDIR InpDirection      = ND_BOTH;   // trade direction

input group "=== SIGNAL CONFIRMATION ==="
input int    InpPullbackPoints    = 0;         // wait for a pullback of x points before entering (0 = enter now)
input int    InpConfirmTimeoutMin = 15;        // cancel the signal after N minutes
input int    InpMaxDriftPoints    = 0;         // cancel if price runs x points away in signal direction (0 = off)

input group "=== NEWS / TIME ==="
input bool   InpHighNews          = true;      // pause new chains around HIGH impact news (live only)
input bool   InpMedNews           = false;     // also MEDIUM impact
input string InpNewsCurrencies    = "USD";     // currencies to watch
input int    InpNewsBuffer        = 60;        // minutes before / after the news
input string InpHours             = "";        // trading hours server time, e.g. "02:00-20:00" (empty = 24h)
input int    InpFridayStopHour    = 20;        // no new chains on Friday after this hour (0 = off)

input group "=== GENERAL ==="
input long   InpMagic             = 777888;    // magic number
input string InpComment           = "NAIF_SR"; // order comment
input bool   InpShowPanel         = true;      // info panel
input bool   InpNotify            = true;      // MT5 push notifications for limits / big events

//------------------------------------------------------------------ globals
CTrade   trade;
int      hAtrH1 = INVALID_HANDLE, hAtrS = INVALID_HANDLE, hEma20 = INVALID_HANDLE, hEma50 = INVALID_HANDLE, hRsi = INVALID_HANDLE, hMacd = INVALID_HANDLE;
datetime gLastBar = 0;
int      gPendDir = 0; double gPendPrice = 0; datetime gPendTime = 0;   // signal waiting for confirmation
double   gDayEq = 0, gWeekEq = 0, gPeakBal = 0;
int      gDayKey = -1, gWeekKey = -1, gChainsToday = 0;
bool     gDayStop = false, gWeekStop = false, gHardStop = false, gEqStop = false;
datetime gPauseUntil = 0;
double   gTrailPeak[2] = {0, 0};
double   gSpacing[]; int gSpacingN = 0;
string   gBlock = "", gLastSignal = "-";
double   gLastScore = 0;
datetime gNewsChk = 0; bool gNewsNow = false; string gNewsTxt = "";

//------------------------------------------------------------------ helpers
double Bid() { return SymbolInfoDouble(_Symbol, SYMBOL_BID); }
double Ask() { return SymbolInfoDouble(_Symbol, SYMBOL_ASK); }
double Buf(int h, int buf, int shift) { double a[]; if(h == INVALID_HANDLE || CopyBuffer(h, buf, shift, 1, a) != 1) return 0; return a[0]; }

double NormLot(double lot)
{
   double st = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP), mn = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN), mx = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   if(st <= 0) st = 0.01;
   lot = MathFloor(lot / st + 1e-9) * st;
   lot = MathMax(mn, MathMin(lot, mx));
   int d = (int)MathMax(0, MathRound(-MathLog10(st)));
   return NormalizeDouble(lot, d);
}

void Notify(string s) { Print("NAIF SR: ", s); if(InpNotify && TerminalInfoInteger(TERMINAL_NOTIFICATIONS_ENABLED)) SendNotification("NAIF SR " + _Symbol + ": " + s); }

double FirstLot()
{
   if(InpLotSize > 0) return NormLot(InpLotSize);
   double per = (InpRisk == NR_LOW ? 0.005 : InpRisk == NR_MEDIUM ? 0.01 : 0.02);
   double bal = (InpCustomBalance > 0 ? InpCustomBalance : AccountInfoDouble(ACCOUNT_BALANCE));
   double lot = bal / 1000.0 * per * InpLotSizeMultiplier;
   if(InpMaxAutoLot > 0) lot = MathMin(lot, InpMaxAutoLot);
   return NormLot(lot);
}

//------------------------------------------------------------------ chain info (read from open positions, survives restarts)
struct Chain
{
   int      n;
   double   lots, profit, firstPrice, lastPrice, firstLot, lastLot;
   datetime firstTime;
};

void ReadChain(int dir, Chain &c)   // dir 1 = buy, -1 = sell
{
   c.n = 0; c.lots = 0; c.profit = 0; c.firstPrice = 0; c.lastPrice = 0; c.firstLot = 0; c.lastLot = 0; c.firstTime = 0;
   datetime lastT = 0;
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      ulong t = PositionGetTicket(i);
      if(t == 0 || PositionGetString(POSITION_SYMBOL) != _Symbol || PositionGetInteger(POSITION_MAGIC) != InpMagic) continue;
      bool buy = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY);
      if((dir == 1) != buy) continue;
      datetime ot = (datetime)PositionGetInteger(POSITION_TIME);
      double vol = PositionGetDouble(POSITION_VOLUME), op = PositionGetDouble(POSITION_PRICE_OPEN);
      c.n++; c.lots += vol; c.profit += PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP);
      if(c.firstTime == 0 || ot < c.firstTime) { c.firstTime = ot; c.firstPrice = op; c.firstLot = vol; }
      if(ot >= lastT) { lastT = ot; c.lastPrice = op; c.lastLot = vol; }
   }
}

void CloseChain(int dir, string why)
{
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      ulong t = PositionGetTicket(i);
      if(t == 0 || PositionGetString(POSITION_SYMBOL) != _Symbol || PositionGetInteger(POSITION_MAGIC) != InpMagic) continue;
      bool buy = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY);
      if(dir == 0 || (dir == 1) == buy) trade.PositionClose(t, 100);
   }
   if(dir != 0) gTrailPeak[dir == 1 ? 0 : 1] = 0; else { gTrailPeak[0] = 0; gTrailPeak[1] = 0; }
   Print("NAIF SR: chain closed (", (dir == 1 ? "BUY" : dir == -1 ? "SELL" : "ALL"), ") - ", why);
}

//------------------------------------------------------------------ distances
double BaseDistance()   // price units
{
   double d;
   if(InpFixDistance > 0) d = InpFixDistance * _Point;
   else d = Buf(hAtrH1, 0, 1) * InpAtrDistFactor;
   if(InpMinDistance > 0) d = MathMax(d, InpMinDistance * _Point);
   if(InpMaxDistance > 0) d = MathMin(d, InpMaxDistance * _Point);
   if(d <= 0) d = 300 * _Point;
   return d;
}

double StepDistance(int k)   // distance before trade number k+1 (k = trades already open, 1..)
{
   if(gSpacingN > 0) return gSpacing[MathMin(k - 1, gSpacingN - 1)] * _Point;
   return BaseDistance() * MathPow(InpDistMultiplier, k - 1);
}

//------------------------------------------------------------------ chain target
double ChainTarget(const Chain &c)
{
   double target = InpMinProfit;
   if(target <= 0)
   {
      double p = 0, half = BaseDistance() * 0.5;
      if(!OrderCalcProfit(ORDER_TYPE_BUY, _Symbol, c.firstLot, Bid(), Bid() + half, p)) p = 0;
      target = MathMax(p * InpAutoProfitMult, 0.01);
   }
   if(InpBreakEvenAfter > 0 && c.n >= (int)InpBreakEvenAfter) target = MathMin(target, MathMax(InpMinNetProfit, 0.01));
   if(InpReduceDelayMin > 0 && InpReduceStepMin > 0)
   {
      long mins = (long)(TimeCurrent() - c.firstTime) / 60;
      if(mins >= InpReduceDelayMin)
      {
         long steps = 1 + (mins - InpReduceDelayMin) / InpReduceStepMin;
         double t0 = target;
         if(InpReduceType == NRED_MONEY) target -= steps * InpReduceValue;
         else target -= t0 * MathMin(1.0, steps * InpReduceValue / 100.0);
         target = MathMax(target, InpMinNetProfit);
      }
   }
   return target;
}

//------------------------------------------------------------------ signals
int SigAI(double &score)
{
   double atr = Buf(hAtrS, 0, 1); score = 0;
   if(atr <= 0) return 0;
   double c1 = iClose(_Symbol, InpSignalTF, 1), o1 = iOpen(_Symbol, InpSignalTF, 1);
   double e20 = Buf(hEma20, 0, 1), e20b = Buf(hEma20, 0, 6), e50 = Buf(hEma50, 0, 1);
   double rsi = Buf(hRsi, 0, 1), mh = Buf(hMacd, 0, 1) - Buf(hMacd, 1, 1);
   double f1 = MathMax(-3, MathMin(3, (c1 - e50) / atr));        // position vs trend
   double f2 = (rsi - 50.0) / 50.0;                               // momentum
   double f3 = MathMax(-3, MathMin(3, mh / atr * 4));             // MACD histogram
   double f4 = MathMax(-3, MathMin(3, (e20 - e20b) / atr));       // slope
   double f5 = MathMax(-2, MathMin(2, (c1 - o1) / atr));          // last candle
   double z = 0.45 * f1 + 1.10 * f2 + 0.50 * f3 + 0.60 * f4 + 0.30 * f5;
   score = (MathExp(z) - MathExp(-z)) / (MathExp(z) + MathExp(-z)); // tanh -> -1..+1
   if(score >= InpAIThreshold) return 1;
   if(score <= -InpAIThreshold) return -1;
   return 0;
}

int SigSR()
{
   int lb = 50;
   int ih = iHighest(_Symbol, InpSignalTF, MODE_HIGH, lb, 2), il = iLowest(_Symbol, InpSignalTF, MODE_LOW, lb, 2);
   if(ih < 0 || il < 0) return 0;
   double hi = iHigh(_Symbol, InpSignalTF, ih), lo = iLow(_Symbol, InpSignalTF, il), atr = Buf(hAtrS, 0, 1);
   double l1 = iLow(_Symbol, InpSignalTF, 1), h1 = iHigh(_Symbol, InpSignalTF, 1), c1 = iClose(_Symbol, InpSignalTF, 1), o1 = iOpen(_Symbol, InpSignalTF, 1);
   if(l1 <= lo + atr * 0.2 && c1 > o1 && c1 > lo) return 1;
   if(h1 >= hi - atr * 0.2 && c1 < o1 && c1 < hi) return -1;
   return 0;
}

int SigCandle()
{
   double o1 = iOpen(_Symbol, InpSignalTF, 1), c1 = iClose(_Symbol, InpSignalTF, 1), o2 = iOpen(_Symbol, InpSignalTF, 2), c2 = iClose(_Symbol, InpSignalTF, 2);
   if(c2 < o2 && c1 > o1 && c1 >= o2 && o1 <= c2) return 1;    // bullish engulfing
   if(c2 > o2 && c1 < o1 && c1 <= o2 && o1 >= c2) return -1;   // bearish engulfing
   return 0;
}

int SigTrend()
{
   double a1 = Buf(hEma20, 0, 1), b1 = Buf(hEma50, 0, 1), a2 = Buf(hEma20, 0, 2), b2 = Buf(hEma50, 0, 2);
   if(a2 <= b2 && a1 > b1) return 1;
   if(a2 >= b2 && a1 < b1) return -1;
   return 0;
}

int SigPrice()
{
   double c1 = iClose(_Symbol, InpSignalTF, 1), h2 = iHigh(_Symbol, InpSignalTF, 2), l2 = iLow(_Symbol, InpSignalTF, 2);
   if(c1 > h2) return 1;
   if(c1 < l2) return -1;
   return 0;
}

int GetSignal()   // combines enabled strategies; conflicting votes = no trade
{
   int buy = 0, sell = 0, s;
   if(InpUseAIScore) { s = SigAI(gLastScore); if(s > 0) buy++; if(s < 0) sell++; }
   if(InpUseSR)     { s = SigSR();     if(s > 0) buy++; if(s < 0) sell++; }
   if(InpUseCandle) { s = SigCandle(); if(s > 0) buy++; if(s < 0) sell++; }
   if(InpUseTrend)  { s = SigTrend();  if(s > 0) buy++; if(s < 0) sell++; }
   if(InpUsePrice)  { s = SigPrice();  if(s > 0) buy++; if(s < 0) sell++; }
   int d = (buy > 0 && sell == 0) ? 1 : (sell > 0 && buy == 0) ? -1 : 0;
   if(InpTrendMode == NT_REVERSE) d = -d;
   if(InpDirection == ND_BUY_ONLY && d < 0) d = 0;
   if(InpDirection == ND_SELL_ONLY && d > 0) d = 0;
   return d;
}

//------------------------------------------------------------------ filters
bool InHours(const MqlDateTime &dt)
{
   string h = InpHours; StringTrimLeft(h); StringTrimRight(h);
   if(h == "") return true;
   string p[]; if(StringSplit(h, '-', p) != 2) return true;
   string a[], b[];
   if(StringSplit(p[0], ':', a) < 1 || StringSplit(p[1], ':', b) < 1) return true;
   int s = (int)StringToInteger(a[0]) * 60 + (ArraySize(a) > 1 ? (int)StringToInteger(a[1]) : 0);
   int e = (int)StringToInteger(b[0]) * 60 + (ArraySize(b) > 1 ? (int)StringToInteger(b[1]) : 0);
   int m = dt.hour * 60 + dt.min;
   return (s <= e) ? (m >= s && m < e) : (m >= s || m < e);
}

void CheckNews()
{
   if(TimeCurrent() - gNewsChk < 60) return;
   gNewsChk = TimeCurrent(); gNewsNow = false; gNewsTxt = "";
   if(MQLInfoInteger(MQL_TESTER) || (!InpHighNews && !InpMedNews)) return;
   datetime now = TimeTradeServer();
   MqlCalendarValue v[];
   if(CalendarValueHistory(v, now - InpNewsBuffer * 60, now + InpNewsBuffer * 60) <= 0) return;
   for(int i = 0; i < ArraySize(v); i++)
   {
      MqlCalendarEvent ev; MqlCalendarCountry co;
      if(!CalendarEventById(v[i].event_id, ev) || !CalendarCountryById(ev.country_id, co)) continue;
      if(StringFind(InpNewsCurrencies, co.currency) < 0) continue;
      if(ev.importance == CALENDAR_IMPORTANCE_HIGH || (InpMedNews && ev.importance == CALENDAR_IMPORTANCE_MODERATE))
      { gNewsNow = true; gNewsTxt = co.currency + " " + ev.name + " " + TimeToString(v[i].time, TIME_MINUTES); return; }
   }
}

bool CanStartChain(const MqlDateTime &dt)
{
   gBlock = "";
   if(gHardStop) { gBlock = "HARD STOP"; return false; }
   if(gEqStop)   { gBlock = "EQUITY STOP"; return false; }
   if(gWeekStop) { gBlock = "weekly loss limit"; return false; }
   if(gDayStop)  { gBlock = "daily loss limit"; return false; }
   if(TimeCurrent() < gPauseUntil) { gBlock = "pause after chain drawdown"; return false; }
   if(dt.day_of_week == 0 || dt.day_of_week == 6) { gBlock = "weekend"; return false; }
   if(InpFridayStopHour > 0 && dt.day_of_week == 5 && dt.hour >= InpFridayStopHour) { gBlock = "Friday stop"; return false; }
   if(!InHours(dt)) { gBlock = "outside hours"; return false; }
   if(InpMaxChainsPerDay > 0 && gChainsToday >= InpMaxChainsPerDay) { gBlock = "max chains today"; return false; }
   double eq = AccountInfoDouble(ACCOUNT_EQUITY);
   if(InpDailyTargetMoney > 0 && gDayEq > 0 && eq - gDayEq >= InpDailyTargetMoney) { gBlock = "daily target reached"; return false; }
   if(InpDailyTargetPct > 0 && gDayEq > 0 && (eq / gDayEq - 1) * 100 >= InpDailyTargetPct) { gBlock = "daily target reached"; return false; }
   if(InpMaxSpread > 0 && (Ask() - Bid()) / _Point > InpMaxSpread) { gBlock = "spread high"; return false; }
   CheckNews();
   if(gNewsNow) { gBlock = "news: " + gNewsTxt; return false; }
   return true;
}

//------------------------------------------------------------------ protections
void Protect()
{
   MqlDateTime dt; TimeToStruct(TimeCurrent(), dt);
   double eq = AccountInfoDouble(ACCOUNT_EQUITY), bal = AccountInfoDouble(ACCOUNT_BALANCE);
   int dk = dt.year * 1000 + dt.day_of_year;
   if(dk != gDayKey) { gDayKey = dk; gDayEq = eq; gDayStop = false; gChainsToday = 0; }
   int wk = dt.year * 100 + (dt.day_of_year - dt.day_of_week + 7) / 7;
   if(wk != gWeekKey) { gWeekKey = wk; gWeekEq = eq; gWeekStop = false; }
   if(bal > gPeakBal) gPeakBal = bal;
   if(InpDailyLossPct > 0 && !gDayStop && gDayEq > 0 && eq <= gDayEq * (1 - InpDailyLossPct / 100))
   { gDayStop = true; CloseChain(0, "daily loss limit"); Notify("daily loss limit hit - stopped until tomorrow"); }
   if(InpWeeklyLossPct > 0 && !gWeekStop && gWeekEq > 0 && eq <= gWeekEq * (1 - InpWeeklyLossPct / 100))
   { gWeekStop = true; CloseChain(0, "weekly loss limit"); Notify("weekly loss limit hit - stopped until next week"); }
   if(InpHardStopPct > 0 && !gHardStop && gPeakBal > 0 && eq <= gPeakBal * (1 - InpHardStopPct / 100))
   { CloseChain(0, "hard stop"); Notify("HARD STOP hit"); if(InpPauseOnHardStop) gHardStop = true; else gPeakBal = bal; }
   if(InpEquityStop > 0 && !gEqStop && eq <= InpEquityStop)
   { gEqStop = true; CloseChain(0, "equity stop"); Notify("EQUITY STOP hit - EA stopped"); }
}

//------------------------------------------------------------------ chain management
void ManageChain(int dir)
{
   Chain c; ReadChain(dir, c);
   int ix = (dir == 1 ? 0 : 1);
   if(c.n == 0) { gTrailPeak[ix] = 0; return; }
   double bal = AccountInfoDouble(ACCOUNT_BALANCE);
   // 1) chain loss limit
   if(InpMaxChainDDPct > 0 && c.profit <= -bal * InpMaxChainDDPct / 100)
   {
      CloseChain(dir, "chain drawdown " + DoubleToString(InpMaxChainDDPct, 1) + "%");
      if(InpPauseAfterChainDD > 0) gPauseUntil = TimeCurrent() + InpPauseAfterChainDD * 60;
      Notify("chain closed at max drawdown " + DoubleToString(c.profit, 2));
      return;
   }
   if(InpChainStopPoints > 0)
   {
      double adverse = (dir == 1 ? c.firstPrice - Bid() : Ask() - c.firstPrice) / _Point;
      if(adverse >= InpChainStopPoints) { CloseChain(dir, "chain stop points"); return; }
   }
   // 2) profit exit + basket trailing
   double target = ChainTarget(c);
   if(InpTrailStart > 0 && InpTrailDist > 0)
   {
      if(c.profit >= InpTrailStart) gTrailPeak[ix] = MathMax(gTrailPeak[ix], c.profit);
      if(gTrailPeak[ix] > 0 && c.profit <= gTrailPeak[ix] - InpTrailDist && c.profit > 0) { CloseChain(dir, "basket trailing"); return; }
      if(gTrailPeak[ix] > 0) return;   // trailing is running, let it ride
   }
   if(c.profit >= target) { CloseChain(dir, "target " + DoubleToString(target, 2) + " reached"); return; }
   // 3) add a recovery trade
   if(c.n >= InpRecovery || gHardStop || gEqStop || gDayStop || gWeekStop) return;
   double dist = StepDistance(c.n);
   bool add = (dir == 1 ? Ask() <= c.lastPrice - dist : Bid() >= c.lastPrice + dist);
   if(!add) return;
   if(InpMaxSpread > 0 && (Ask() - Bid()) / _Point > InpMaxSpread) return;
   double lot = NormLot(c.lastLot * InpRecoveryLotMult);
   string cm = InpComment + "_R" + IntegerToString(c.n + 1);
   bool ok = (dir == 1 ? trade.Buy(lot, _Symbol, 0, 0, 0, cm) : trade.Sell(lot, _Symbol, 0, 0, 0, cm));
   if(ok) Print("NAIF SR: recovery #", c.n + 1, " ", (dir == 1 ? "BUY " : "SELL "), DoubleToString(lot, 2), "  distance ", DoubleToString(dist / _Point, 0), " pts");
}

void TryOpen(int dir)
{
   double lot = FirstLot();
   string cm = InpComment + "_R1";
   bool ok = (dir == 1 ? trade.Buy(lot, _Symbol, 0, 0, 0, cm) : trade.Sell(lot, _Symbol, 0, 0, 0, cm));
   if(ok) { gChainsToday++; Print("NAIF SR: new chain ", (dir == 1 ? "BUY " : "SELL "), DoubleToString(lot, 2), "  score ", DoubleToString(gLastScore, 2)); }
}

void Entries()
{
   MqlDateTime dt; TimeToStruct(TimeCurrent(), dt);
   Chain b, s; ReadChain(1, b); ReadChain(-1, s);
   bool newBar = false;
   datetime bt = iTime(_Symbol, InpSignalTF, 0);
   if(bt != gLastBar) { gLastBar = bt; newBar = true; }
   if(newBar)
   {
      int d = GetSignal();
      if(d != 0) { gPendDir = d; gPendPrice = (d == 1 ? Ask() : Bid()); gPendTime = TimeCurrent(); gLastSignal = (d == 1 ? "BUY " : "SELL ") + TimeToString(TimeCurrent(), TIME_MINUTES); }
   }
   if(gPendDir == 0) return;
   if(TimeCurrent() - gPendTime > InpConfirmTimeoutMin * 60 && InpPullbackPoints > 0) { gPendDir = 0; return; }
   if(!CanStartChain(dt)) { if(InpPullbackPoints == 0) gPendDir = 0; return; }
   if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) && !MQLInfoInteger(MQL_TESTER)) return;
   int d = gPendDir;
   if(d == 1 && b.n > 0) { gPendDir = 0; return; }
   if(d == -1 && s.n > 0) { gPendDir = 0; return; }
   if(InpOneChainAtATime && (b.n > 0 || s.n > 0)) { gPendDir = 0; return; }
   if(InpPullbackPoints > 0)
   {
      double px = (d == 1 ? Ask() : Bid());
      double moved = (d == 1 ? gPendPrice - px : px - gPendPrice) / _Point;   // + = pullback
      if(InpMaxDriftPoints > 0 && -moved >= InpMaxDriftPoints) { gPendDir = 0; return; }
      if(moved < InpPullbackPoints) return;
   }
   TryOpen(d);
   gPendDir = 0;
}

//------------------------------------------------------------------ panel
void Panel()
{
   if(!InpShowPanel || (MQLInfoInteger(MQL_TESTER) && !MQLInfoInteger(MQL_VISUAL_MODE))) return;
   static uint last = 0; if(GetTickCount() - last < 1000) return; last = GetTickCount();
   Chain b, s; ReadChain(1, b); ReadChain(-1, s);
   string t = "NAIF SMART RECOVERY  |  @najran2015\n";
   t += "Balance " + DoubleToString(AccountInfoDouble(ACCOUNT_BALANCE), 2) + "   Equity " + DoubleToString(AccountInfoDouble(ACCOUNT_EQUITY), 2) + "\n";
   t += "Day " + DoubleToString(AccountInfoDouble(ACCOUNT_EQUITY) - gDayEq, 2) + "   chains today " + IntegerToString(gChainsToday) + "\n";
   t += "First lot " + DoubleToString(FirstLot(), 2) + "   base distance " + DoubleToString(BaseDistance() / _Point, 0) + " pts\n";
   if(b.n > 0) t += "BUY chain  " + IntegerToString(b.n) + "/" + IntegerToString(InpRecovery) + "  lots " + DoubleToString(b.lots, 2) + "  P/L " + DoubleToString(b.profit, 2) + "  target " + DoubleToString(ChainTarget(b), 2) + "  next " + DoubleToString(b.lastPrice - StepDistance(b.n), _Digits) + "\n";
   if(s.n > 0) t += "SELL chain " + IntegerToString(s.n) + "/" + IntegerToString(InpRecovery) + "  lots " + DoubleToString(s.lots, 2) + "  P/L " + DoubleToString(s.profit, 2) + "  target " + DoubleToString(ChainTarget(s), 2) + "  next " + DoubleToString(s.lastPrice + StepDistance(s.n), _Digits) + "\n";
   if(b.n == 0 && s.n == 0) t += "no chain - waiting for signal\n";
   t += "AI score " + DoubleToString(gLastScore, 2) + "   last signal " + gLastSignal + (gPendDir != 0 ? "   (waiting pullback)" : "") + "\n";
   if(gBlock != "") t += "BLOCKED: " + gBlock + "\n";
   Comment(t);
}

//------------------------------------------------------------------ events
int OnInit()
{
   trade.SetExpertMagicNumber(InpMagic);
   trade.SetDeviationInPoints(50);
   trade.SetTypeFillingBySymbol(_Symbol);
   hAtrH1 = iATR(_Symbol, PERIOD_H1, 14);
   hAtrS  = iATR(_Symbol, InpSignalTF, 14);
   hEma20 = iMA(_Symbol, InpSignalTF, 20, 0, MODE_EMA, PRICE_CLOSE);
   hEma50 = iMA(_Symbol, InpSignalTF, 50, 0, MODE_EMA, PRICE_CLOSE);
   hRsi   = iRSI(_Symbol, InpSignalTF, 14, PRICE_CLOSE);
   hMacd  = iMACD(_Symbol, InpSignalTF, 12, 26, 9, PRICE_CLOSE);
   if(hAtrH1 == INVALID_HANDLE || hAtrS == INVALID_HANDLE || hEma20 == INVALID_HANDLE || hEma50 == INVALID_HANDLE || hRsi == INVALID_HANDLE || hMacd == INVALID_HANDLE)
      return INIT_FAILED;
   gSpacingN = 0; ArrayResize(gSpacing, 0);
   string p[]; int n = StringSplit(InpSpacingList, ',', p);
   for(int i = 0; i < n; i++) { double v = StringToDouble(p[i]); if(v > 0) { ArrayResize(gSpacing, gSpacingN + 1); gSpacing[gSpacingN++] = v; } }
   gPeakBal = AccountInfoDouble(ACCOUNT_BALANCE);
   gLastBar = iTime(_Symbol, InpSignalTF, 0);   // first signal on the next new candle
   return INIT_SUCCEEDED;
}

void OnDeinit(const int reason)
{
   IndicatorRelease(hAtrH1); IndicatorRelease(hAtrS); IndicatorRelease(hEma20); IndicatorRelease(hEma50); IndicatorRelease(hRsi); IndicatorRelease(hMacd);
   Comment("");
}

void OnTick()
{
   Protect();
   ManageChain(1);
   ManageChain(-1);
   Entries();
   Panel();
}
//+------------------------------------------------------------------+

Tags

Expert Advisor type
Reviews

to write a review

No reviews yet. Be the first to review!
70,000 Coins
Instant download
6 months support
Free updates

to purchase

More by naifhouf_4805