mql5/Experts/Previous/FX_trading_strategy.mq5
2025-07-20 16:41:20 +01:00

586 lines
No EOL
24 KiB
MQL5

//+------------------------------------------------------------------+
//| Multi_Instrument_Trading_EA.mq5 |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include <Trade\Trade.mqh>
// Input parameters
input double LotSize = 0.1; // Lot size for trading
input int MagicNumber = 123456; // Magic number for orders
input int MACD_Fast = 12; // MACD Fast EMA period
input int MACD_Slow = 26; // MACD Slow EMA period
input int MACD_Signal = 9; // MACD Signal period
input double MaxSpread = 3.0; // Maximum allowed spread in points
input double RiskPercent = 2.0; // Risk per trade as % of account
input double MaxDailyLoss = 5.0; // Maximum daily loss %
input bool EnableGBPUSD = true; // Enable GBP/USD trading
input bool EnableUSDJPY = true; // Enable USD/JPY trading
input bool EnableBuyScenario1 = true; // Enable Buy Scenario 1
input bool EnableBuyScenario2 = true; // Enable Buy Scenario 2
input bool EnableSellScenario1 = true; // Enable Sell Scenario 1
input bool EnableSellScenario2 = true; // Enable Sell Scenario 2
// Structure for instrument data
struct InstrumentData
{
string symbol;
double entryBuyLevel;
double targetLevel;
double supportLevel;
double sellTarget;
double expectedBuyPullback;
double expectedSellRebound;
int testCount_Support;
int testCount_Entry;
datetime lastTestTime_Support;
datetime lastTestTime_Entry;
bool inLongPosition;
bool inShortPosition;
int macdHandle;
};
// Global variables
CTrade trade;
InstrumentData instruments[2];
double dailyStartBalance;
datetime dailyStartTime;
// Dynamic arrays for MACD data
double macdMain_GBPUSD[], macdSignal_GBPUSD[];
double macdMain_USDJPY[], macdSignal_USDJPY[];
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Initialize instruments
int index = 0;
if(EnableGBPUSD)
{
instruments[index].symbol = "GBPUSD";
instruments[index].entryBuyLevel = 1.3600;
instruments[index].targetLevel = 1.3641;
instruments[index].supportLevel = 1.3566;
instruments[index].sellTarget = 1.3521;
instruments[index].expectedBuyPullback = 35; // pips
instruments[index].expectedSellRebound = 25; // pips
// Initialize MACD for GBP/USD
instruments[index].macdHandle = iMACD("GBPUSD", PERIOD_CURRENT, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE);
if(instruments[index].macdHandle == INVALID_HANDLE)
{
Print("Error creating MACD indicator for GBPUSD");
return INIT_FAILED;
}
ArraySetAsSeries(macdMain_GBPUSD, true);
ArraySetAsSeries(macdSignal_GBPUSD, true);
index++;
}
if(EnableUSDJPY)
{
instruments[index].symbol = "USDJPY";
instruments[index].entryBuyLevel = 143.77;
instruments[index].targetLevel = 144.26;
instruments[index].supportLevel = 143.36;
instruments[index].sellTarget = 142.78;
instruments[index].expectedBuyPullback = 35; // pips
instruments[index].expectedSellRebound = 25; // pips
// Initialize MACD for USD/JPY
instruments[index].macdHandle = iMACD("USDJPY", PERIOD_CURRENT, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE);
if(instruments[index].macdHandle == INVALID_HANDLE)
{
Print("Error creating MACD indicator for USDJPY");
return INIT_FAILED;
}
ArraySetAsSeries(macdMain_USDJPY, true);
ArraySetAsSeries(macdSignal_USDJPY, true);
}
// Set trade parameters
trade.SetExpertMagicNumber(MagicNumber);
trade.SetDeviationInPoints(10);
// Initialize daily tracking
dailyStartBalance = AccountInfoDouble(ACCOUNT_BALANCE);
dailyStartTime = TimeCurrent();
Print("Multi-Instrument Trading EA initialized successfully");
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
for(int i = 0; i < ArraySize(instruments); i++)
{
if(instruments[i].macdHandle != INVALID_HANDLE)
IndicatorRelease(instruments[i].macdHandle);
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Check daily risk management
if(!CheckDailyRiskManagement())
return;
// Process each enabled instrument
for(int i = 0; i < ArraySize(instruments); i++)
{
if(instruments[i].symbol == "" || instruments[i].macdHandle == INVALID_HANDLE)
continue;
// Check spread for this instrument
if(!CheckSpread(instruments[i].symbol))
continue;
// Update MACD values for this instrument
if(!UpdateMACDValues(i))
continue;
// Update position status for this instrument
UpdatePositionStatus(i);
// Check trading scenarios for this instrument
if(EnableBuyScenario1)
CheckBuyScenario1(i);
if(EnableBuyScenario2)
CheckBuyScenario2(i);
if(EnableSellScenario1)
CheckSellScenario1(i);
if(EnableSellScenario2)
CheckSellScenario2(i);
// Check exit conditions for this instrument
CheckExitConditions(i);
}
}
//+------------------------------------------------------------------+
//| Check daily risk management |
//+------------------------------------------------------------------+
bool CheckDailyRiskManagement()
{
// Reset daily tracking at new day
MqlDateTime timeStruct;
TimeToStruct(TimeCurrent(), timeStruct);
MqlDateTime startStruct;
TimeToStruct(dailyStartTime, startStruct);
if(timeStruct.day != startStruct.day)
{
dailyStartBalance = AccountInfoDouble(ACCOUNT_BALANCE);
dailyStartTime = TimeCurrent();
Print("New trading day started. Daily balance reset.");
}
// Check if daily loss limit exceeded
double currentBalance = AccountInfoDouble(ACCOUNT_BALANCE);
double dailyLoss = (dailyStartBalance - currentBalance) / dailyStartBalance * 100;
if(dailyLoss >= MaxDailyLoss)
{
Print("Daily loss limit exceeded: ", dailyLoss, "%. Trading stopped for today.");
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Check spread for specific instrument |
//+------------------------------------------------------------------+
bool CheckSpread(string symbol)
{
double ask = SymbolInfoDouble(symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(symbol, SYMBOL_BID);
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
double spread = (ask - bid) / point;
return spread <= MaxSpread;
}
//+------------------------------------------------------------------+
//| Calculate lot size based on risk management |
//+------------------------------------------------------------------+
double CalculateLotSize(string symbol, double entryPrice, double stopLoss)
{
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
double riskAmount = balance * RiskPercent / 100;
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
double stopLossPoints = MathAbs(entryPrice - stopLoss) / point;
double lotSize = riskAmount / (stopLossPoints * tickValue);
// Round to nearest lot step
lotSize = MathFloor(lotSize / lotStep) * lotStep;
// Apply limits
if(lotSize < minLot) lotSize = minLot;
if(lotSize > maxLot) lotSize = maxLot;
return lotSize;
}
//+------------------------------------------------------------------+
//| Update MACD indicator values for specific instrument |
//+------------------------------------------------------------------+
bool UpdateMACDValues(int instrumentIndex)
{
if(instrumentIndex == 0 && instruments[0].symbol == "GBPUSD") // GBP/USD
{
if(CopyBuffer(instruments[instrumentIndex].macdHandle, 0, 0, 3, macdMain_GBPUSD) < 0 ||
CopyBuffer(instruments[instrumentIndex].macdHandle, 1, 0, 3, macdSignal_GBPUSD) < 0)
{
Print("Error copying MACD buffers for GBPUSD");
return false;
}
}
else if(instrumentIndex == 1 && instruments[1].symbol == "USDJPY") // USD/JPY
{
if(CopyBuffer(instruments[instrumentIndex].macdHandle, 0, 0, 3, macdMain_USDJPY) < 0 ||
CopyBuffer(instruments[instrumentIndex].macdHandle, 1, 0, 3, macdSignal_USDJPY) < 0)
{
Print("Error copying MACD buffers for USDJPY");
return false;
}
}
else if(instruments[instrumentIndex].symbol == "GBPUSD")
{
if(CopyBuffer(instruments[instrumentIndex].macdHandle, 0, 0, 3, macdMain_GBPUSD) < 0 ||
CopyBuffer(instruments[instrumentIndex].macdHandle, 1, 0, 3, macdSignal_GBPUSD) < 0)
{
Print("Error copying MACD buffers for GBPUSD");
return false;
}
}
else if(instruments[instrumentIndex].symbol == "USDJPY")
{
if(CopyBuffer(instruments[instrumentIndex].macdHandle, 0, 0, 3, macdMain_USDJPY) < 0 ||
CopyBuffer(instruments[instrumentIndex].macdHandle, 1, 0, 3, macdSignal_USDJPY) < 0)
{
Print("Error copying MACD buffers for USDJPY");
return false;
}
}
return true;
}
//+------------------------------------------------------------------+
//| Get MACD values for specific instrument |
//+------------------------------------------------------------------+
double GetMACDMain(int instrumentIndex, int shift)
{
if(instruments[instrumentIndex].symbol == "GBPUSD")
return macdMain_GBPUSD[shift];
else if(instruments[instrumentIndex].symbol == "USDJPY")
return macdMain_USDJPY[shift];
return 0;
}
double GetMACDSignal(int instrumentIndex, int shift)
{
if(instruments[instrumentIndex].symbol == "GBPUSD")
return macdSignal_GBPUSD[shift];
else if(instruments[instrumentIndex].symbol == "USDJPY")
return macdSignal_USDJPY[shift];
return 0;
}
void UpdatePositionStatus(int instrumentIndex)
{
instruments[instrumentIndex].inLongPosition = false;
instruments[instrumentIndex].inShortPosition = false;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(PositionGetSymbol(i) == instruments[instrumentIndex].symbol &&
PositionGetInteger(POSITION_MAGIC) == MagicNumber)
{
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
instruments[instrumentIndex].inLongPosition = true;
else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
instruments[instrumentIndex].inShortPosition = true;
}
}
}
//+------------------------------------------------------------------+
//| Check Buy Scenario 1 for specific instrument |
//+------------------------------------------------------------------+
void CheckBuyScenario1(int instrumentIndex)
{
if(instruments[instrumentIndex].inLongPosition)
return;
string symbol = instruments[instrumentIndex].symbol;
double ask = SymbolInfoDouble(symbol, SYMBOL_ASK);
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
// Check if price is near entry level (within 5 pips)
if(MathAbs(ask - instruments[instrumentIndex].entryBuyLevel) <= 5 * point)
{
// Check MACD conditions: above zero and rising
if(GetMACDMain(instrumentIndex, 0) > 0 &&
GetMACDMain(instrumentIndex, 0) > GetMACDMain(instrumentIndex, 1))
{
// Calculate lot size with risk management
double stopLoss = instruments[instrumentIndex].supportLevel;
double lotSize = CalculateLotSize(symbol, ask, stopLoss);
// Execute buy order
if(trade.Buy(lotSize, symbol, ask, stopLoss, instruments[instrumentIndex].targetLevel,
"Buy Scenario 1 - " + symbol))
{
Print("Buy Scenario 1 executed for ", symbol, " at ", ask, " Lot size: ", lotSize);
}
}
}
}
//+------------------------------------------------------------------+
//| Check Buy Scenario 2 for specific instrument |
//+------------------------------------------------------------------+
void CheckBuyScenario2(int instrumentIndex)
{
if(instruments[instrumentIndex].inLongPosition)
return;
string symbol = instruments[instrumentIndex].symbol;
double bid = SymbolInfoDouble(symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(symbol, SYMBOL_ASK);
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
// Check if price is testing support level (within 3 pips)
if(MathAbs(bid - instruments[instrumentIndex].supportLevel) <= 3 * point)
{
// Check if this is a new test (not within last 4 hours)
if(TimeCurrent() - instruments[instrumentIndex].lastTestTime_Support > 4 * 3600)
{
instruments[instrumentIndex].testCount_Support++;
instruments[instrumentIndex].lastTestTime_Support = TimeCurrent();
Print("Test #", instruments[instrumentIndex].testCount_Support,
" of support level detected for ", symbol);
// Determine oversold threshold based on instrument
double oversoldThreshold = (symbol == "GBPUSD") ? -0.0005 : -0.0010;
// If second test and MACD is oversold
if(instruments[instrumentIndex].testCount_Support >= 2 &&
GetMACDMain(instrumentIndex, 0) < oversoldThreshold)
{
// Calculate lot size with risk management
double stopLoss = instruments[instrumentIndex].supportLevel - 10 * point;
double lotSize = CalculateLotSize(symbol, ask, stopLoss);
// Execute buy order
if(trade.Buy(lotSize, symbol, ask, stopLoss, instruments[instrumentIndex].targetLevel,
"Buy Scenario 2 - " + symbol))
{
Print("Buy Scenario 2 executed for ", symbol, " at ", ask, " Lot size: ", lotSize);
instruments[instrumentIndex].testCount_Support = 0; // Reset counter
}
}
}
}
// Reset counter if price moves significantly away from level
if(MathAbs(bid - instruments[instrumentIndex].supportLevel) > 20 * point)
{
instruments[instrumentIndex].testCount_Support = 0;
}
}
//+------------------------------------------------------------------+
//| Check Sell Scenario 1 for specific instrument |
//+------------------------------------------------------------------+
void CheckSellScenario1(int instrumentIndex)
{
if(instruments[instrumentIndex].inShortPosition)
return;
string symbol = instruments[instrumentIndex].symbol;
double bid = SymbolInfoDouble(symbol, SYMBOL_BID);
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
// Check if price breaks below support level
if(bid < instruments[instrumentIndex].supportLevel - 2 * point)
{
// Check MACD conditions: below zero and declining
if(GetMACDMain(instrumentIndex, 0) < 0 &&
GetMACDMain(instrumentIndex, 0) < GetMACDMain(instrumentIndex, 1))
{
// Calculate lot size with risk management
double stopLoss = instruments[instrumentIndex].entryBuyLevel;
double lotSize = CalculateLotSize(symbol, bid, stopLoss);
// Execute sell order
if(trade.Sell(lotSize, symbol, bid, stopLoss, instruments[instrumentIndex].sellTarget,
"Sell Scenario 1 - " + symbol))
{
Print("Sell Scenario 1 executed for ", symbol, " at ", bid, " Lot size: ", lotSize);
}
}
}
}
//+------------------------------------------------------------------+
//| Check Sell Scenario 2 for specific instrument |
//+------------------------------------------------------------------+
void CheckSellScenario2(int instrumentIndex)
{
if(instruments[instrumentIndex].inShortPosition)
return;
string symbol = instruments[instrumentIndex].symbol;
double ask = SymbolInfoDouble(symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(symbol, SYMBOL_BID);
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
// Check if price is testing entry level (within 3 pips)
if(MathAbs(ask - instruments[instrumentIndex].entryBuyLevel) <= 3 * point)
{
// Check if this is a new test (not within last 4 hours)
if(TimeCurrent() - instruments[instrumentIndex].lastTestTime_Entry > 4 * 3600)
{
instruments[instrumentIndex].testCount_Entry++;
instruments[instrumentIndex].lastTestTime_Entry = TimeCurrent();
Print("Test #", instruments[instrumentIndex].testCount_Entry,
" of entry level detected for ", symbol);
// Determine overbought threshold based on instrument
double overboughtThreshold = (symbol == "GBPUSD") ? 0.0005 : 0.0010;
// If second test and MACD is overbought
if(instruments[instrumentIndex].testCount_Entry >= 2 &&
GetMACDMain(instrumentIndex, 0) > overboughtThreshold)
{
// Calculate lot size with risk management
double stopLoss = instruments[instrumentIndex].entryBuyLevel + 10 * point;
double lotSize = CalculateLotSize(symbol, bid, stopLoss);
// Execute sell order
if(trade.Sell(lotSize, symbol, bid, stopLoss, instruments[instrumentIndex].sellTarget,
"Sell Scenario 2 - " + symbol))
{
Print("Sell Scenario 2 executed for ", symbol, " at ", bid, " Lot size: ", lotSize);
instruments[instrumentIndex].testCount_Entry = 0; // Reset counter
}
}
}
}
// Reset counter if price moves significantly away from level
if(MathAbs(ask - instruments[instrumentIndex].entryBuyLevel) > 20 * point)
{
instruments[instrumentIndex].testCount_Entry = 0;
}
}
//+------------------------------------------------------------------+
//| Check exit conditions and automatic reversals |
//+------------------------------------------------------------------+
void CheckExitConditions(int instrumentIndex)
{
string symbol = instruments[instrumentIndex].symbol;
double bid = SymbolInfoDouble(symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(symbol, SYMBOL_ASK);
double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(PositionGetSymbol(i) == symbol && PositionGetInteger(POSITION_MAGIC) == MagicNumber)
{
ulong ticket = PositionGetInteger(POSITION_TICKET);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double currentPrice = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ? bid : ask;
// Check long position exit at target
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
if(currentPrice >= instruments[instrumentIndex].targetLevel)
{
if(trade.PositionClose(ticket))
{
Print("Long position closed at target for ", symbol, ": ", currentPrice);
// Open automatic reversal short position for pullback
double reversalTarget = instruments[instrumentIndex].targetLevel -
instruments[instrumentIndex].expectedBuyPullback * point;
double stopLoss = instruments[instrumentIndex].targetLevel + 15 * point;
double lotSize = CalculateLotSize(symbol, bid, stopLoss);
if(trade.Sell(lotSize, symbol, bid, stopLoss, reversalTarget,
"Auto Reversal Short - " + symbol))
{
Print("Automatic reversal short opened for ", symbol,
" expecting ", instruments[instrumentIndex].expectedBuyPullback, " pip pullback");
}
}
}
}
// Check short position exit at target
else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
{
if(currentPrice <= instruments[instrumentIndex].sellTarget)
{
if(trade.PositionClose(ticket))
{
Print("Short position closed at target for ", symbol, ": ", currentPrice);
// Open automatic reversal long position for rebound
double reversalTarget = instruments[instrumentIndex].sellTarget +
instruments[instrumentIndex].expectedSellRebound * point;
double stopLoss = instruments[instrumentIndex].sellTarget - 15 * point;
double lotSize = CalculateLotSize(symbol, ask, stopLoss);
if(trade.Buy(lotSize, symbol, ask, stopLoss, reversalTarget,
"Auto Reversal Long - " + symbol))
{
Print("Automatic reversal long opened for ", symbol,
" expecting ", instruments[instrumentIndex].expectedSellRebound, " pip rebound");
}
}
}
}
}
}
}
//+------------------------------------------------------------------+
//| Trade transaction function |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{
// Handle trade events
if(trans.type == TRADE_TRANSACTION_DEAL_ADD)
{
Print("Trade executed: ", trans.symbol, " Volume: ", trans.volume,
" Price: ", trans.price, " Type: ",
(trans.deal_type == DEAL_TYPE_BUY ? "BUY" : "SELL"));
}
}