- Removed WinUser32.mqh include (path issues) - Removed IndicatorRelease calls (MT5 only function) - MT4 doesn't require explicit indicator cleanup
427 lines
13 KiB
Plaintext
427 lines
13 KiB
Plaintext
//+------------------------------------------------------------------+
|
|
//| OrdersEA_Smart_Grid.mq4 |
|
|
//| Copyright 2024, Garfield Heron |
|
|
//| https://fetcherpay.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2024, Garfield Heron"
|
|
#property link "https://fetcherpay.com"
|
|
#property version "3.0"
|
|
#property strict
|
|
|
|
// WinUser32.mqh removed - not needed for core functionality
|
|
|
|
#define VERSION "Version 3.0 Smart Grid"
|
|
#define MAX_TRADES 600
|
|
#define MAX_LOG_TRADES 1200
|
|
|
|
//--- Input Parameters
|
|
extern string Email= "garfield@fetcherpay.com";
|
|
extern int MagicNum= 333;
|
|
|
|
//--- Smart Grid Settings
|
|
extern string GridSettings = "=== Smart Grid Settings ===";
|
|
extern bool UseAutoPivots = true; // Auto-calculate pivot points
|
|
extern double HIGH= 0; // Manual HIGH (if UseAutoPivots=false)
|
|
extern double LOW= 0; // Manual LOW (if UseAutoPivots=false)
|
|
extern double Entry= 10; // Grid spacing in pips
|
|
extern double TP= 15; // Take profit per level
|
|
extern double Lots=0.01; // Lot size per trade
|
|
extern int MaxLevels = 10; // Max grid levels per side
|
|
|
|
//--- Range Filter Settings
|
|
extern string FilterSettings = "=== Range Filters ===";
|
|
extern bool UseRSIFilter = true; // Enable RSI filter
|
|
extern int RSIPeriod = 14; // RSI period
|
|
extern int RSILower = 35; // RSI lower bound (buy zone)
|
|
extern int RSIUpper = 65; // RSI upper bound (sell zone)
|
|
|
|
extern bool UseADXFilter = true; // Enable ADX filter
|
|
extern int ADXPeriod = 14; // ADX period
|
|
extern double ADXMax = 25; // Max ADX for ranging (below=trending)
|
|
|
|
extern bool UseATRFilter = true; // Enable ATR filter
|
|
extern int ATRPeriod = 14; // ATR period
|
|
extern double ATRMultiplier = 1.5; // ATR multiplier for range width
|
|
|
|
//--- Risk Management
|
|
extern string RiskSettings = "=== Risk Management ===";
|
|
extern int StopLoss=0;
|
|
extern int TRADE_RANGE= 50;
|
|
extern double LongLimit= 0;
|
|
extern double ShortLimit= 0;
|
|
extern string GetOut= "N";
|
|
extern string OpenNewTrades="Y";
|
|
extern bool Opposite= false;
|
|
extern int TakeProfitLevelPercent= 50;
|
|
extern int TakeProfitLevelDollarAmount= 2000;
|
|
extern bool Restart= true;
|
|
extern int EquityFactorPercent= 0;
|
|
extern int LotsFactorPercent= 0;
|
|
extern int BaseEquity= 10000;
|
|
extern bool Master= false;
|
|
extern bool DiagnosticModeOn= false;
|
|
|
|
//--- Indicator Handles
|
|
int RSICurrent = 0;
|
|
int ADXHandle = 0;
|
|
int ATRHandle = 0;
|
|
|
|
//--- Pivot Point Variables
|
|
double PivotP = 0;
|
|
double PivotR1 = 0;
|
|
double PivotR2 = 0;
|
|
double PivotS1 = 0;
|
|
double PivotS2 = 0;
|
|
|
|
//--- Original OrdersEA Variables
|
|
int initialCycleEquity= 0;
|
|
int longs, shorts;
|
|
int longsTicket[MAX_TRADES];
|
|
int shortsTicket[MAX_TRADES];
|
|
int logTickets[MAX_LOG_TRADES];
|
|
int logTicketsTime[MAX_LOG_TRADES];
|
|
int logTicketsCounter;
|
|
int Levels;
|
|
double price[MAX_TRADES];
|
|
int stoplevel;
|
|
bool bFirstTick= false;
|
|
int logId;
|
|
bool bEnableLongs;
|
|
bool bEnableShorts;
|
|
double tickValue;
|
|
int MaximalLoss;
|
|
int lastTicketSentOpen= 0, lastTicketSentClose= 0;
|
|
double longAvgPrice= 0, longAvgLots= 0;
|
|
double shortAvgPrice= 0, shortAvgLots= 0;
|
|
double longProfit= 0;
|
|
double shortProfit= 0;
|
|
bool bConfirmed;
|
|
bool bOpposite;
|
|
bool bInit= false;
|
|
int TakeProfit=0;
|
|
bool AboveHigh;
|
|
bool BelowLow;
|
|
int tradeLogId;
|
|
double closeOnProfit;
|
|
bool bGetOutOK, bOpenNewTradesOK;
|
|
int initEquity;
|
|
int lotDigits;
|
|
bool bWithdrawMailSent= false;
|
|
bool bGetOutHandled;
|
|
int PingTimeMinutes= 240;
|
|
bool bAccess;
|
|
bool bValidSettings;
|
|
string errMsg;
|
|
datetime PivotCalculationTime = 0;
|
|
bool TradeExecutedToday = false;
|
|
bool R1HitToday = false;
|
|
bool S1HitToday = false;
|
|
double P, R1, R2, S1, S2;
|
|
bool PivotsCalculated = false;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate Pivot Points |
|
|
//+------------------------------------------------------------------+
|
|
void CalculatePivotPoints()
|
|
{
|
|
// Get yesterday's data
|
|
datetime yesterday = Time[0] - PeriodSeconds(PERIOD_D1);
|
|
int shift = iBarShift(NULL, PERIOD_D1, yesterday);
|
|
|
|
double prevHigh = iHigh(NULL, PERIOD_D1, shift);
|
|
double prevLow = iLow(NULL, PERIOD_D1, shift);
|
|
double prevClose = iClose(NULL, PERIOD_D1, shift);
|
|
|
|
// Standard Pivot Formula
|
|
PivotP = (prevHigh + prevLow + prevClose) / 3.0;
|
|
PivotR1 = (2.0 * PivotP) - prevLow;
|
|
PivotS1 = (2.0 * PivotP) - prevHigh;
|
|
PivotR2 = PivotP + (prevHigh - prevLow);
|
|
PivotS2 = PivotP - (prevHigh - prevLow);
|
|
|
|
// Set HIGH/LOW if auto-pivots enabled
|
|
if(UseAutoPivots)
|
|
{
|
|
// Use R1/S1 for narrow range, R2/S2 for wider
|
|
double atr = iATR(NULL, 0, ATRPeriod, 0);
|
|
|
|
if(UseATRFilter && atr > 0)
|
|
{
|
|
// ATR-based adaptive range
|
|
HIGH = NormalizeDouble(PivotP + (atr * ATRMultiplier), Digits);
|
|
LOW = NormalizeDouble(PivotP - (atr * ATRMultiplier), Digits);
|
|
}
|
|
else
|
|
{
|
|
// Standard pivot-based range
|
|
HIGH = PivotR1;
|
|
LOW = PivotS1;
|
|
}
|
|
}
|
|
|
|
Print("Pivot Calculated: P=", PivotP, " R1=", PivotR1, " S1=", PivotS1);
|
|
Print("Grid Range: HIGH=", HIGH, " LOW=", LOW);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check if Market is Ranging (Good for Grid) |
|
|
//+------------------------------------------------------------------+
|
|
bool IsRangingMarket()
|
|
{
|
|
bool isRanging = true;
|
|
|
|
//--- RSI Filter
|
|
if(UseRSIFilter)
|
|
{
|
|
double rsi = iRSI(NULL, 0, RSIPeriod, PRICE_CLOSE, 0);
|
|
if(rsi < RSILower || rsi > RSIUpper)
|
|
{
|
|
Print("RSI Filter: Market at extremes (RSI=", rsi, "), skipping grid");
|
|
isRanging = false;
|
|
}
|
|
}
|
|
|
|
//--- ADX Filter
|
|
if(UseADXFilter && isRanging)
|
|
{
|
|
double adx = iADX(NULL, 0, ADXPeriod, PRICE_CLOSE, MODE_MAIN, 0);
|
|
if(adx > ADXMax)
|
|
{
|
|
Print("ADX Filter: Market trending (ADX=", adx, "), skipping grid");
|
|
isRanging = false;
|
|
}
|
|
}
|
|
|
|
//--- Price Position Filter
|
|
double currentPrice = Bid;
|
|
if(currentPrice > HIGH || currentPrice < LOW)
|
|
{
|
|
Print("Price outside grid range, waiting for re-entry");
|
|
isRanging = false;
|
|
}
|
|
|
|
return isRanging;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get Grid Lot Size (Original CalcLots) |
|
|
//+------------------------------------------------------------------+
|
|
double CalcLots()
|
|
{
|
|
double tmp= (AccountEquity()-initEquity);
|
|
double a= EquityFactorPercent;
|
|
double b= LotsFactorPercent;
|
|
double lots;
|
|
|
|
if(0==EquityFactorPercent || 0==LotsFactorPercent)
|
|
lots= Lots;
|
|
else
|
|
{
|
|
a=initEquity*a/100;
|
|
b=b/100;
|
|
if(tmp>0)
|
|
tmp= MathPow(1+b,(tmp/a));
|
|
else if(tmp<0)
|
|
tmp= MathPow(1-b,MathAbs(tmp/a));
|
|
else
|
|
tmp= 1;
|
|
|
|
lots= NormalizeDouble(Lots*tmp,lotDigits);
|
|
if(lots<MarketInfo(Symbol(),MODE_MINLOT))
|
|
lots= MarketInfo(Symbol(),MODE_MINLOT);
|
|
}
|
|
|
|
if(lots<0)
|
|
Log("ERROR tmp="+tmp+",a="+a+",b="+b+",AccountEquity()="+AccountEquity());
|
|
Log("Equity="+AccountEquity()+",lots="+lots);
|
|
return(lots);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Add Trade to Log |
|
|
//+------------------------------------------------------------------+
|
|
void AddTradeToLog(int ticket)
|
|
{
|
|
bool rc= false;
|
|
int i=0;
|
|
for(i=0; i<logTicketsCounter; i++)
|
|
{
|
|
if(logTickets[i]==ticket)
|
|
{
|
|
rc= true;
|
|
break;
|
|
}
|
|
}
|
|
if(!rc && i<MAX_LOG_TRADES)
|
|
{
|
|
logTickets[logTicketsCounter]= ticket;
|
|
logTicketsTime[logTicketsCounter]= TimeCurrent();
|
|
logTicketsCounter++;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Send Notification |
|
|
//+------------------------------------------------------------------+
|
|
void SendNotificationEx(string title, string subject)
|
|
{
|
|
string st= subject;
|
|
if(!IsOptimization())
|
|
{
|
|
st= st + "Price now: " + DoubleToStr(Bid, Digits) + "\n";
|
|
st= st +"Longs: " + longs + " @ " + DoubleToStr(longAvgPrice, Digits) + "\n";
|
|
st= st +"Shorts: " + shorts + " @ " + DoubleToStr(shortAvgPrice, Digits) + "\n";
|
|
st= st +"Account Equity: + "+ AccountEquity() +"\n";
|
|
st= st +"Account Balance: + "+ AccountBalance() +"\n";
|
|
SendMail(title, st);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Log function |
|
|
//+------------------------------------------------------------------+
|
|
void Log(string st)
|
|
{
|
|
if(DiagnosticModeOn)
|
|
if(logId>=0)
|
|
{
|
|
FileWrite(logId, TimeToStr(TimeCurrent(),TIME_DATE|TIME_SECONDS) + ": " + st);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
// Initialize indicators
|
|
if(UseRSIFilter)
|
|
RSICurrent = iRSI(NULL, 0, RSIPeriod, PRICE_CLOSE);
|
|
if(UseADXFilter)
|
|
ADXHandle = iADX(NULL, 0, ADXPeriod);
|
|
if(UseATRFilter)
|
|
ATRHandle = iATR(NULL, 0, ATRPeriod);
|
|
|
|
// Calculate initial pivot points
|
|
CalculatePivotPoints();
|
|
|
|
// Rest of original init
|
|
PivotsCalculated = false;
|
|
stoplevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;
|
|
if(stoplevel <= 0) stoplevel = 0;
|
|
|
|
Print("Smart Grid EA Initialized");
|
|
Print("AutoPivots: ", UseAutoPivots);
|
|
Print("RSI Filter: ", UseRSIFilter, " (", RSILower, "-", RSIUpper, ")");
|
|
Print("ADX Filter: ", UseADXFilter, " (<", ADXMax, ")");
|
|
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert deinitialization |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
// Cleanup indicators
|
|
// MT4 doesn't require explicit indicator release
|
|
|
|
if(logId>=0)
|
|
FileClose(logId);
|
|
Print("Smart Grid EA Deinitialized");
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert tick function - Smart Grid Logic |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
// Recalculate pivots at new day
|
|
datetime TimeNow = TimeCurrent();
|
|
if(TimeHour(TimeNow) == 0 && TimeMinute(TimeNow) < 5)
|
|
{
|
|
CalculatePivotPoints();
|
|
}
|
|
|
|
// Check if we should trade (ranging market?)
|
|
if(!IsRangingMarket())
|
|
{
|
|
// Close existing grid if market starts trending
|
|
if(GetOut == "Y" || GetOut == "y")
|
|
{
|
|
// CloseAllTrades logic here
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Original OrdersEA grid logic would go here
|
|
// (Simplified for this template)
|
|
|
|
static datetime lastBarTime = 0;
|
|
datetime currentBarTime = iTime(NULL, 0, 0);
|
|
|
|
if(currentBarTime != lastBarTime)
|
|
{
|
|
lastBarTime = currentBarTime;
|
|
|
|
// Place grid orders logic
|
|
// This is where you'd integrate the full OrdersEA order placement
|
|
|
|
Print("Smart Grid: RSI=", iRSI(NULL,0,RSIPeriod,PRICE_CLOSE,0),
|
|
" ADX=", iADX(NULL,0,ADXPeriod,PRICE_CLOSE,MODE_MAIN,0),
|
|
" Range: ", LOW, " - ", HIGH);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Place Buy Order at Level |
|
|
//+------------------------------------------------------------------+
|
|
bool PlaceBuyLevel(double priceLevel, int level)
|
|
{
|
|
if(level >= MaxLevels) return false;
|
|
|
|
double lots = CalcLots();
|
|
double sl = (StopLoss > 0) ? priceLevel - (StopLoss * Point) : 0;
|
|
double tp = priceLevel + (TP * Point);
|
|
|
|
int ticket = OrderSend(Symbol(), OP_BUYSTOP, lots, priceLevel, 3, sl, tp,
|
|
"Smart Grid Buy " + IntegerToString(level), MagicNum, 0, clrBlue);
|
|
|
|
if(ticket > 0)
|
|
{
|
|
Print("Buy Level ", level, " placed at ", priceLevel);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
Print("Error placing buy level: ", GetLastError());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Place Sell Order at Level |
|
|
//+------------------------------------------------------------------+
|
|
bool PlaceSellLevel(double priceLevel, int level)
|
|
{
|
|
if(level >= MaxLevels) return false;
|
|
|
|
double lots = CalcLots();
|
|
double sl = (StopLoss > 0) ? priceLevel + (StopLoss * Point) : 0;
|
|
double tp = priceLevel - (TP * Point);
|
|
|
|
int ticket = OrderSend(Symbol(), OP_SELLSTOP, lots, priceLevel, 3, sl, tp,
|
|
"Smart Grid Sell " + IntegerToString(level), MagicNum, 0, clrRed);
|
|
|
|
if(ticket > 0)
|
|
{
|
|
Print("Sell Level ", level, " placed at ", priceLevel);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
Print("Error placing sell level: ", GetLastError());
|
|
return false;
|
|
}
|
|
}
|