586 lines
24 KiB
MQL5
586 lines
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"));
|
||
|
}
|
||
|
}
|