trade-bot/README.md

387 lines
14 KiB
Markdown
Raw Permalink Normal View History

2025-10-31 23:54:15 +00:00
//+------------------------------------------------------------------+
//| LiquidityFibConfluenceEA_PRO.mq5 |
//| 3-4AM & 10-11AM EST | 5M Sweep/FVG → 1M Fib 0.62/0.79 Entry |
//| NAS100 ONLY | Visuals | Push | Screenshot | SL 100 pips |
//+------------------------------------------------------------------+
#property copyright "Houssam El Fayda"
#property link "https://x.ai"
#property version "2.00"
#property strict
#property script_show_inputs
2025-10-31 23:53:21 +00:00
2025-10-31 23:54:15 +00:00
input double LotSize = 0.1;
input int Slippage = 3;
input int MagicNumber = 987654;
input int StopLossPips = 100;
input bool EnableDebug = true;
input bool EnablePush = true;
input bool EnableScreenshot = true;
input color ArrowColorBuy = clrLime;
input color ArrowColorSell = clrRed;
//--- Allowed symbols (NAS100 variants)
string AllowedSymbols[] = {"NAS100", "US100", "USTEC", "NAS100.cash"};
//--- Time Zones
datetime est_offset = -5 * 3600; // EST = UTC-5
//--- Global
datetime last_bar_time = 0;
//+------------------------------------------------------------------+
//| Expert initialization |
//+------------------------------------------------------------------+
int OnInit()
{
if(Period() != PERIOD_M1)
{
Alert("Attach this EA to a 1-MINUTE chart!");
return(INIT_FAILED);
}
if(!IsNas100Symbol())
{
Alert("This EA only works on NAS100 (US100, USTEC, NAS100.cash)");
return(INIT_FAILED);
}
Print("LiquidityFibConfluenceEA_PRO initialized on ", _Symbol, " M1");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(!IsTradeTime()) return;
if(!IsNewBar(PERIOD_M5)) return;
if(DetectLiquiditySweep() || DetectFVGHits())
{
double fib_062, fib_079;
if(GetFibLevels(fib_062, fib_079))
{
double entry = 0;
bool use_062 = CheckConfluence(fib_062);
bool use_079 = CheckConfluence(fib_079);
if(use_062) entry = fib_062;
else if(use_079) entry = fib_079;
else return;
ENUM_ORDER_TYPE type = (Close[0] > entry) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
double sl = (type == ORDER_TYPE_BUY) ? entry - StopLossPips * _Point : entry + StopLossPips * _Point;
double tp = GetNextStructureLevel(type);
if(tp == 0) return;
OpenPosition(type, entry, sl, tp);
}
}
}
//+------------------------------------------------------------------+
//| Check if symbol is NAS100 |
//+------------------------------------------------------------------+
bool IsNas100Symbol()
{
for(int i = 0; i < ArraySize(AllowedSymbols); i++)
if(StringFind(_Symbol, AllowedSymbols[i], 0) != -1)
return true;
return false;
}
//+------------------------------------------------------------------+
//| Trade Time: 3-4 AM & 10-11 AM EST |
//+------------------------------------------------------------------+
bool IsTradeTime()
{
datetime now = TimeCurrent();
datetime est = now + est_offset;
int hour = TimeHour(est);
return (hour >= 3 && hour < 4) || (hour >= 10 && hour < 11);
}
//+------------------------------------------------------------------+
//| Detect 5M Liquidity Sweep |
//+------------------------------------------------------------------+
bool DetectLiquiditySweep()
{
double high[], low[], close[];
if(CopyHigh(_Symbol, PERIOD_M5, 1, 3, high) <= 0 ||
CopyLow(_Symbol, PERIOD_M5, 1, 3, low) <= 0 ||
CopyClose(_Symbol, PERIOD_M5, 1, 3, close) <= 0)
return false;
if(high[0] > high[1] && close[0] < high[1]) return true; // High sweep
if(low[0] < low[1] && close[0] > low[1]) return true; // Low sweep
return false;
}
//+------------------------------------------------------------------+
//| Detect FVG Hit on 5M |
//+------------------------------------------------------------------+
bool DetectFVGHits()
{
double high[], low[];
if(CopyHigh(_Symbol, PERIOD_M5, 1, 3, high) <= 0 ||
CopyLow(_Symbol, PERIOD_M5, 1, 3, low) <= 0)
return false;
if(low[2] > high[0] || high[2] < low[0]) return true;
return false;
}
//+------------------------------------------------------------------+
//| Get Fib 0.62 & 0.79 from last 5M swing |
//+------------------------------------------------------------------+
bool GetFibLevels(double &fib_062, double &fib_079)
{
double high[], low[];
if(CopyHigh(_Symbol, PERIOD_M5, 1, 25, high) <= 0 ||
CopyLow(_Symbol, PERIOD_M5, 1, 25, low) <= 0)
return false;
int swing_i = -1;
double swing_p = 0;
bool is_high = true;
for(int i = 3; i < 20; i++)
{
if(high[i] > high[i-1] && high[i] > high[i+1] && high[i] > high[i-2] && high[i] > high[i+2])
{
swing_i = i; swing_p = high[i]; is_high = true; break;
}
if(low[i] < low[i-1] && low[i] < low[i+1] && low[i] < low[i-2] && low[i] < low[i+2])
{
swing_i = i; swing_p = low[i]; is_high = false; break;
}
}
if(swing_i == -1) return false;
double base = is_high ? ArrayMinimum(low, swing_i, 12) : ArrayMaximum(high, swing_i, 12);
if(base <= 0) return false;
double range = MathAbs(swing_p - base);
fib_062 = is_high ? swing_p - 0.618 * range : swing_p + 0.618 * range;
fib_079 = is_high ? swing_p - 0.786 * range : swing_p + 0.786 * range;
DrawFibLines(swing_p, base, fib_062, fib_079);
return true;
}
//+------------------------------------------------------------------+
//| Draw Fib Lines on Chart |
//+------------------------------------------------------------------+
void DrawFibLines(double high, double low, double f062, double f079)
{
string name = "Fib_" + IntegerToString(TimeCurrent());
ObjectCreate(0, name, OBJ_TREND, 0, Time[10], high, Time[0], low);
ObjectSetInteger(0, name, OBJPROP_COLOR, clrGray);
ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DOT);
ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
string l062 = name + "_062";
string l079 = name + "_079";
ObjectCreate(0, l062, OBJ_HLINE, 0, 0, f062);
ObjectCreate(0, l079, OBJ_HLINE, 0, 0, f079);
ObjectSetInteger(0, l062, OBJPROP_COLOR, clrYellow);
ObjectSetInteger(0, l079, OBJPROP_COLOR, clrOrange);
ObjectSetString(0, l062, OBJPROP_TEXT, "Fib 0.62");
ObjectSetString(0, l079, OBJPROP_TEXT, "Fib 0.79");
}
//+------------------------------------------------------------------+
//| Check Confluence with PD Arrays |
//+------------------------------------------------------------------+
bool CheckConfluence(double level)
{
double tol = 15 * _Point;
double fvg = GetLastFVG();
double ob = GetLastOrderBlock();
double rb = GetLastRejectionBlock();
if(fvg > 0 && MathAbs(level - fvg) < tol) { DrawLabel("FVG", level, clrAqua); return true; }
if(ob > 0 && MathAbs(level - ob) < tol) { DrawLabel("OB", level, clrGold); return true; }
if(rb > 0 && MathAbs(level - rb) < tol) { DrawLabel("RB", level, clrPink); return true; }
return false;
}
//+------------------------------------------------------------------+
//| Get Last FVG |
//+------------------------------------------------------------------+
double GetLastFVG()
{
double high[], low[];
if(CopyHigh(_Symbol, PERIOD_M5, 1, 5, high) <= 0 || CopyLow(_Symbol, PERIOD_M5, 1, 5, low) <= 0)
return 0;
for(int i = 2; i < 4; i++)
{
if(low[i] > high[i-2]) return (low[i] + high[i-2]) / 2.0;
if(high[i] < low[i-2]) return (high[i] + low[i-2]) / 2.0;
}
return 0;
}
//+------------------------------------------------------------------+
//| Get Last Order Block |
//+------------------------------------------------------------------+
double GetLastOrderBlock()
{
double o[], c[], h[], l[];
if(CopyOpen(_Symbol, PERIOD_M5, 1, 10, o) <= 0 || CopyClose(_Symbol, PERIOD_M5, 1, 10, c) <= 0 ||
CopyHigh(_Symbol, PERIOD_M5, 1, 10, h) <= 0 || CopyLow(_Symbol, PERIOD_M5, 1, 10, l) <= 0)
return 0;
for(int i = 1; i < 8; i++)
{
double body = MathAbs(c[i] - o[i]);
double range = h[i] - l[i];
if(body > 0.7 * range && range > 0)
return (o[i] + c[i]) / 2.0;
}
return 0;
}
//+------------------------------------------------------------------+
//| Get Last Rejection Block |
//+------------------------------------------------------------------+
double GetLastRejectionBlock()
{
double o[], c[], h[], l[];
if(CopyOpen(_Symbol, PERIOD_M5, 1, 10, o) <= 0 || CopyClose(_Symbol, PERIOD_M5, 1, 10, c) <= 0 ||
CopyHigh(_Symbol, PERIOD_M5, 1, 10, h) <= 0 || CopyLow(_Symbol, PERIOD_M5, 1, 10, l) <= 0)
return 0;
for(int i = 1; i < 8; i++)
{
double body = MathAbs(c[i] - o[i]);
double uw = h[i] - MathMax(o[i], c[i]);
double lw = MathMin(o[i], c[i]) - l[i];
if(uw > 2 * body || lw > 2 * body)
return (o[i] + c[i]) / 2.0;
}
return 0;
}
//+------------------------------------------------------------------+
//| Get Next 15M Structure (TP) |
//+------------------------------------------------------------------+
double GetNextStructureLevel(ENUM_ORDER_TYPE type)
{
double high[], low[];
if(CopyHigh(_Symbol, PERIOD_M15, 0, 25, high) <= 0 ||
CopyLow(_Symbol, PERIOD_M15, 0, 25, low) <= 0)
return 0;
double last_high = high[ArrayMaximum(high, 15)];
double last_low = low[ArrayMinimum(low, 15)];
return (type == ORDER_TYPE_BUY) ? last_low : last_high;
}
//+------------------------------------------------------------------+
//| Open Position with Visuals, Push, Screenshot |
//+------------------------------------------------------------------+
void OpenPosition(ENUM_ORDER_TYPE type, double entry, double sl, double tp)
{
if(PositionExists()) return;
MqlTradeRequest req; MqlTradeResult res;
ZeroMemory(req); ZeroMemory(res);
req.action = TRADE_ACTION_DEAL;
req.symbol = _Symbol;
req.volume = LotSize;
req.type = type;
req.price = (type == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK)
: SymbolInfoDouble(_Symbol, SYMBOL_BID);
req.sl = NormalizeDouble(sl, _Digits);
req.tp = NormalizeDouble(tp, _Digits);
req.deviation= Slippage;
req.magic = MagicNumber;
req.comment = "FibConfluencePRO";
if(!OrderSend(req, res))
{
Print("OrderSend failed: ", GetLastError());
return;
}
if(res.retcode == TRADE_RETCODE_DONE)
{
// === Visual Arrow ===
string arrow_name = "Entry_" + IntegerToString(res.order);
ObjectCreate(0, arrow_name, OBJ_ARROW, 0, Time[0], req.price);
ObjectSetInteger(0, arrow_name, OBJPROP_ARROWCODE, type == ORDER_TYPE_BUY ? 233 : 234);
ObjectSetInteger(0, arrow_name, OBJPROP_COLOR, type == ORDER_TYPE_BUY ? ArrowColorBuy : ArrowColorSell);
ObjectSetInteger(0, arrow_name, OBJPROP_WIDTH, 3);
// === Label ===
string label = "Trade_" + IntegerToString(res.order);
ObjectCreate(0, label, OBJ_TEXT, 0, Time[0], req.price);
ObjectSetString(0, label, OBJPROP_TEXT, (type == ORDER_TYPE_BUY ? "BUY" : "SELL") +
" @ " + DoubleToString(req.price, _Digits));
ObjectSetInteger(0, label, OBJPROP_COLOR, clrWhite);
ObjectSetInteger(0, label, OBJPROP_FONTSIZE, 10);
// === Push Notification ===
if(EnablePush)
SendNotification("NAS100 " + (type == ORDER_TYPE_BUY ? "BUY" : "SELL") +
" @ " + DoubleToString(req.price, _Digits) +
" | SL: " + DoubleToString(sl, _Digits) +
" | TP: " + DoubleToString(tp, _Digits));
// === Screenshot ===
if(EnableScreenshot)
{
string filename = "NAS100_" + (type == ORDER_TYPE_BUY ? "BUY" : "SELL") +
"_" + TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES) + ".png";
StringReplace(filename, ":", "");
ChartScreenShot(0, filename, 1920, 1080, ALIGN_CENTER);
}
Print("TRADE OPENED: ", EnumToString(type), " @ ", req.price, " | TP: ", tp);
}
}
//+------------------------------------------------------------------+
//| Draw Label for PD Array |
//+------------------------------------------------------------------+
void DrawLabel(string text, double price, color col)
{
string name = text + "_" + IntegerToString(Time[0]);
ObjectCreate(0, name, OBJ_TEXT, 0, Time[5], price);
ObjectSetString(0, name, OBJPROP_TEXT, text);
ObjectSetInteger(0, name, OBJPROP_COLOR, col);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 9);
}
//+------------------------------------------------------------------+
//| Check if position exists |
//+------------------------------------------------------------------+
bool PositionExists()
{
for(int i = 0; i < PositionsTotal(); i++)
{
if(PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_MAGIC) == MagicNumber)
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| New Bar Detection |
//+------------------------------------------------------------------+
bool IsNewBar(ENUM_TIMEFRAMES tf)
{
datetime curr = iTime(_Symbol, tf, 0);
if(curr != last_bar_time)
{
last_bar_time = curr;
return true;
}
return false;
}