
Description
//+------------------------------------------------------------------+
//| NAIF_Gold_Pro_Lite.mq5 - NAIF APEX ALGO (@najran2015) |
//| Two trend-following engines in one light file: |
//| 1) SWING : breakouts of multi-day H4 highs/lows (4 slots), |
//| SL % of price, TP x R, trailing, max 7 days |
//| 2) ASIA : night range breakout at London open (1 per day) |
//| Same logic as InpSwOn + InpNDaily in The_Gold_Reaper_v4.3_NAIF. |
//+------------------------------------------------------------------+
#property copyright "NAIF APEX ALGO"
#property version "1.00"
#include <Trade/Trade.mqh>
input group "--- Lot ---"
input double InpSwLotPer1000 = 0.005; // SWING lot per 1000 of balance, EACH slot (0.005 -> 20000 = 0.10)
input double InpAsLotPer1000 = 0.005; // ASIA lot per 1000 of balance (0.005 -> 20000 = 0.10)
input double InpMaxLot = 1.0; // max lot per order
input group "--- SWING engine ---"
input bool InpSwOn = true; // SWING engine on
input string InpSwSlots = "30,1.0,4.0,0.3,0.6;60,1.0,4.0,0.3,0.6;100,1.5,2.0,0.6,0.3;30,1.0,2.0,0.3,0.3"; // N H4 bars, SL % of price, TP x R, trail start R, trail dist R
input int InpSwMaxDays = 7; // close a swing trade after N days
input group "--- ASIA engine (server time, Exness = GMT) ---"
input bool InpAsOn = true; // ASIA engine on
input int InpAsStartH = 0; // range start hour
input int InpAsEndH = 8; // range end hour = orders placed
input int InpAsCloseH = 20; // close trades / cancel orders hour
input double InpAsMinAtr = 0.2; // skip day if range < x * ATR(D1)
input double InpAsMaxAtr = 9; // skip day if range > x * ATR(D1)
input double InpAsBuf = 2; // entry buffer (x spread)
input double InpAsTpR = 2.0; // TP = R multiple
input long InpMagicBase = 778000; // magic: ASIA = base, SWING slots = base+1..base+8
#define SWMAX 8
CTrade trade;
int gSwN = 0;
int gSwBars[SWMAX];
double gSwSl[SWMAX], gSwTp[SWMAX], gSwTs[SWMAX], gSwTd[SWMAX], gSwPk[SWMAX];
datetime gSwBar[SWMAX];
ulong gSwTk[SWMAX];
int hAtrD1 = INVALID_HANDLE;
datetime gAsDay = 0; bool gAsValid = false, gAsPlaced = false; double gAsHi = 0, gAsLo = 0;
bool gTester = false, gVisual = false;
uint gLastComment = 0;
double Bid() { return SymbolInfoDouble(_Symbol, SYMBOL_BID); }
double Ask() { return SymbolInfoDouble(_Symbol, SYMBOL_ASK); }
long SwMagic(int i) { return InpMagicBase + 1 + i; }
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, MathMin(mx, InpMaxLot)));
int d = (int)MathMax(0, MathRound(-MathLog10(st)));
return NormalizeDouble(lot, d);
}
ulong FindPos(long mg)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong t = PositionGetTicket(i);
if(t != 0 && PositionGetInteger(POSITION_MAGIC) == mg && PositionGetString(POSITION_SYMBOL) == _Symbol) return t;
}
return 0;
}
bool HasOrders(long mg)
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
ulong t = OrderGetTicket(i);
if(t != 0 && OrderGetInteger(ORDER_MAGIC) == mg && OrderGetString(ORDER_SYMBOL) == _Symbol) return true;
}
return false;
}
void DelOrders(long mg)
{
trade.SetExpertMagicNumber(mg);
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
ulong t = OrderGetTicket(i);
if(t != 0 && OrderGetInteger(ORDER_MAGIC) == mg && OrderGetString(ORDER_SYMBOL) == _Symbol) trade.OrderDelete(t);
}
}
void ParseSlots()
{
gSwN = 0;
string slots[]; int ns = StringSplit(InpSwSlots, ';', slots);
for(int i = 0; i < ns && gSwN < SWMAX; i++)
{
string p[]; StringTrimLeft(slots[i]); StringTrimRight(slots[i]);
if(StringSplit(slots[i], ',', p) < 5) continue;
gSwBars[gSwN] = (int)StringToInteger(p[0]); gSwSl[gSwN] = StringToDouble(p[1]); gSwTp[gSwN] = StringToDouble(p[2]);
gSwTs[gSwN] = StringToDouble(p[3]); gSwTd[gSwN] = StringToDouble(p[4]);
if(gSwBars[gSwN] < 2 || gSwSl[gSwN] <= 0) continue;
gSwBar[gSwN] = 0; gSwTk[gSwN] = 0; gSwPk[gSwN] = 0; gSwN++;
}
Print("SWING: ", gSwN, " slots loaded");
}
//------------------------------------------------------------------ SWING engine
void Swing(const MqlDateTime &dt)
{
bool weekend = (dt.day_of_week == 0 || dt.day_of_week == 6);
datetime h4 = iTime(_Symbol, PERIOD_H4, 0);
double stopLvl = (double)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * _Point;
for(int i = 0; i < gSwN; i++)
{
long mg = SwMagic(i);
trade.SetExpertMagicNumber(mg);
ulong pt = FindPos(mg);
if(pt != 0)
{
if(HasOrders(mg)) DelOrders(mg); // OCO
if(!PositionSelectByTicket(pt)) continue;
if(gSwTk[i] != pt) { gSwTk[i] = pt; gSwPk[i] = 0; }
double op = PositionGetDouble(POSITION_PRICE_OPEN), sl = PositionGetDouble(POSITION_SL), tp = PositionGetDouble(POSITION_TP);
bool isBuy = ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY);
if(InpSwMaxDays > 0 && TimeCurrent() - (datetime)PositionGetInteger(POSITION_TIME) >= InpSwMaxDays * 86400) { trade.PositionClose(pt); continue; }
double R = op * gSwSl[i] / 100.0;
double fav = isBuy ? Bid() - op : op - Ask();
if(fav > gSwPk[i]) gSwPk[i] = fav;
if(gSwTs[i] > 0 && R > 0 && gSwPk[i] >= gSwTs[i] * R)
{
double nsl = NormalizeDouble(isBuy ? op + gSwPk[i] - gSwTd[i] * R : op - gSwPk[i] + gSwTd[i] * R, _Digits);
bool better = isBuy ? (nsl > sl + _Point) : (sl <= 0 || nsl < sl - _Point);
bool valid = isBuy ? (nsl < Bid() - stopLvl) : (nsl > Ask() + stopLvl);
if(better && valid) trade.PositionModify(pt, nsl, tp);
}
continue;
}
if(weekend) { if(HasOrders(mg)) DelOrders(mg); continue; }
bool has = HasOrders(mg);
if(has && gSwBar[i] == h4) continue;
if(has) DelOrders(mg); // new H4 candle -> refresh levels
if(!gTester && (!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) || !MQLInfoInteger(MQL_TRADE_ALLOWED))) continue;
int ih = iHighest(_Symbol, PERIOD_H4, MODE_HIGH, gSwBars[i], 1), il = iLowest(_Symbol, PERIOD_H4, MODE_LOW, gSwBars[i], 1);
if(ih < 0 || il < 0) continue;
double hi = iHigh(_Symbol, PERIOD_H4, ih), lo = iLow(_Symbol, PERIOD_H4, il);
gSwBar[i] = h4;
double lot = NormLot(AccountInfoDouble(ACCOUNT_BALANCE) / 1000.0 * InpSwLotPer1000);
string cm = "SWING" + IntegerToString(i + 1);
double Rb = hi * gSwSl[i] / 100.0, Rs = lo * gSwSl[i] / 100.0;
trade.SetExpertMagicNumber(mg);
if(hi > Ask() + stopLvl)
trade.BuyStop(lot, NormalizeDouble(hi, _Digits), _Symbol, NormalizeDouble(hi - Rb, _Digits), NormalizeDouble(hi + Rb * gSwTp[i], _Digits), ORDER_TIME_GTC, 0, cm);
if(lo < Bid() - stopLvl)
trade.SellStop(lot, NormalizeDouble(lo, _Digits), _Symbol, NormalizeDouble(lo + Rs, _Digits), NormalizeDouble(lo - Rs * gSwTp[i], _Digits), ORDER_TIME_GTC, 0, cm);
}
}
//------------------------------------------------------------------ ASIA engine
void Asia(const MqlDateTime &dt)
{
long mg = InpMagicBase;
trade.SetExpertMagicNumber(mg);
datetime today = TimeCurrent() - (dt.hour * 3600 + dt.min * 60 + dt.sec);
ulong pt = FindPos(mg);
if(dt.hour >= InpAsCloseH)
{
if(HasOrders(mg)) DelOrders(mg);
if(pt != 0) { trade.SetExpertMagicNumber(mg); trade.PositionClose(pt, 100); }
return;
}
if(pt != 0 && HasOrders(mg)) DelOrders(mg); // OCO
if(dt.day_of_week == 0 || dt.day_of_week == 6 || dt.hour < InpAsEndH) return;
if(gAsDay != today)
{
gAsDay = today; gAsValid = false; gAsPlaced = false;
MqlRates r[];
int n = CopyRates(_Symbol, PERIOD_M5, today + InpAsStartH * 3600, today + InpAsEndH * 3600 - 1, r);
if(n < 12) return;
double hi = r[0].high, lo = r[0].low;
for(int i = 1; i < n; i++) { hi = MathMax(hi, r[i].high); lo = MathMin(lo, r[i].low); }
double a[], atrD = 0;
if(hAtrD1 != INVALID_HANDLE && CopyBuffer(hAtrD1, 0, 1, 1, a) == 1) atrD = a[0];
if(atrD > 0 && (hi - lo < atrD * InpAsMinAtr || hi - lo > atrD * InpAsMaxAtr)) return;
gAsHi = hi; gAsLo = lo; gAsValid = true;
}
if(!gAsValid || gAsPlaced || pt != 0 || HasOrders(mg)) return;
if(!gTester && (!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) || !MQLInfoInteger(MQL_TRADE_ALLOWED))) return;
gAsPlaced = true;
double buf = InpAsBuf * (Ask() - Bid());
double stopLvl = (double)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * _Point;
double lot = NormLot(AccountInfoDouble(ACCOUNT_BALANCE) / 1000.0 * InpAsLotPer1000);
double buyP = NormalizeDouble(gAsHi + buf, _Digits), buySL = NormalizeDouble(gAsLo - buf, _Digits);
double sellP = NormalizeDouble(gAsLo - buf, _Digits), sellSL = NormalizeDouble(gAsHi + buf, _Digits);
double R = buyP - buySL;
if(R <= 0) return;
trade.SetExpertMagicNumber(mg);
if(buyP > Ask() + stopLvl) trade.BuyStop(lot, buyP, _Symbol, buySL, NormalizeDouble(buyP + R * InpAsTpR, _Digits), ORDER_TIME_GTC, 0, "ASIA_BUY");
if(sellP < Bid() - stopLvl) trade.SellStop(lot, sellP, _Symbol, sellSL, NormalizeDouble(sellP - R * InpAsTpR, _Digits), ORDER_TIME_GTC, 0, "ASIA_SELL");
}
void Status()
{
if(gTester && !gVisual) return;
uint now = GetTickCount();
if(now - gLastComment < 1000) return;
gLastComment = now;
int sp = 0, so = 0;
for(int i = 0; i < gSwN; i++) { if(FindPos(SwMagic(i)) != 0) sp++; if(HasOrders(SwMagic(i))) so++; }
Comment("NAIF Gold Pro Lite\n",
"SWING: ", sp, " trades | ", so, " slots waiting\n",
"ASIA : ", (FindPos(InpMagicBase) != 0 ? "trade running" : (HasOrders(InpMagicBase) ? "orders waiting" : "waiting for " + IntegerToString(InpAsEndH) + ":00")),
" range ", DoubleToString(gAsLo, _Digits), " - ", DoubleToString(gAsHi, _Digits),
(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) ? "\nALGO TRADING OFF" : ""));
}
int OnInit()
{
hAtrD1 = iATR(_Symbol, PERIOD_D1, 14);
trade.SetDeviationInPoints(100);
trade.SetTypeFillingBySymbol(_Symbol);
trade.LogLevel(LOG_LEVEL_ERRORS);
gTester = (bool)MQLInfoInteger(MQL_TESTER);
gVisual = (bool)MQLInfoInteger(MQL_VISUAL_MODE);
ParseSlots();
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
if(hAtrD1 != INVALID_HANDLE) IndicatorRelease(hAtrD1);
Comment("");
}
void OnTick()
{
MqlDateTime dt; TimeToStruct(TimeCurrent(), dt);
if(InpSwOn) Swing(dt);
if(InpAsOn) Asia(dt);
Status();
}
//+------------------------------------------------------------------+
Tags
to write a review
to purchase