mql5/Experts/Previous/ATR_Dynamic_Trading_System.mq5

505 lines
17 KiB
MQL5
Raw Permalink Normal View History

2025-07-20 16:41:20 +01:00
//+------------------------------------------------------------------+
//| ATR Dynamic Trading System.mq5 |
//| Complete ATR-Based Trading System for Testing |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025"
#property link ""
#property version "1.00"
#property strict
#property description "ATR-based trading system with dynamic risk management for strategy tester"
#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\OrderInfo.mqh>
// EA input parameters
input group "ATR Risk Parameters"
input int ATR_Period = 14; // ATR Period
input double SL_ATR_Multiplier = 3.0; // Stop Loss ATR Multiplier
input double TP_ATR_Multiplier = 3.5; // Take Profit ATR Multiplier
input double Trail_Start_Multiplier = 2.5; // Trailing Start ATR Multiplier
input double Trail_Step_Multiplier = 0.5; // Trailing Step ATR Multiplier
input int ATR_Shift = 1; // ATR shift (1 for previous bar)
input double Extra_Buffer_Pips = 5; // Extra buffer in pips
input group "Trading Parameters"
input bool Manage_SL = true; // Manage Stop Loss
input bool Manage_TP = true; // Manage Take Profit
input bool Use_Trailing_Stop = true; // Use Trailing Stop
input bool Close_At_Profit_Target = false; // Close position at profit target instead of setting TP
input group "Entry Strategy Parameters"
input int Fast_MA_Period = 8; // Fast Moving Average Period
input int Slow_MA_Period = 21; // Slow Moving Average Period
input ENUM_MA_METHOD MA_Method = MODE_SMA; // Moving Average Method
input ENUM_APPLIED_PRICE Applied_Price = PRICE_CLOSE; // Applied Price
input double Lot_Size = 0.1; // Fixed Lot Size
input bool Allow_Long_Positions = true; // Allow Long Positions
input bool Allow_Short_Positions = true; // Allow Short Positions
input group "Timing Parameters"
input int Check_Interval_Seconds = 5; // Interval between checks (seconds)
input bool Process_On_Bar_Close = true; // Process only on bar close
// Global variables
CTrade trade;
CPositionInfo posInfo;
COrderInfo orderInfo;
double atrValue;
double point;
int digits;
datetime lastCheckTime = 0;
datetime lastBarTime = 0;
int atrHandle;
int fastMAHandle;
int slowMAHandle;
int positionCount = 0;
ulong positionTickets[];
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Initialize trade operations
trade.SetExpertMagicNumber(123456); // Use a fixed magic number for testing
// Initialize market information
digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
// Create indicator handles
atrHandle = iATR(_Symbol, PERIOD_CURRENT, ATR_Period);
fastMAHandle = iMA(_Symbol, PERIOD_CURRENT, Fast_MA_Period, 0, MA_Method, Applied_Price);
slowMAHandle = iMA(_Symbol, PERIOD_CURRENT, Slow_MA_Period, 0, MA_Method, Applied_Price);
if(atrHandle == INVALID_HANDLE || fastMAHandle == INVALID_HANDLE || slowMAHandle == INVALID_HANDLE)
{
Print("Error creating indicator handles");
return(INIT_FAILED);
}
// Set timer for real-time operation (not needed in strategy tester)
if(!EventSetTimer(Check_Interval_Seconds))
{
Print("Error setting timer");
return(INIT_FAILED);
}
// Initial identification of positions
RefreshPositions();
Print("ATR Dynamic Trading System initialized successfully");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Release indicator handles
IndicatorRelease(atrHandle);
IndicatorRelease(fastMAHandle);
IndicatorRelease(slowMAHandle);
// Remove timer
EventKillTimer();
// Clean up
Comment("");
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
// Check if it's time to update (for real-time trading)
if(!IsTimeToCheck())
return;
// Update indicators and manage positions
UpdateIndicators();
ManagePositions();
CheckForEntrySignals();
// Record the check time
lastCheckTime = TimeCurrent();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Check if we process only on bar close
if(Process_On_Bar_Close)
{
datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
if(currentBarTime != lastBarTime)
{
lastBarTime = currentBarTime;
UpdateIndicators();
ManagePositions();
CheckForEntrySignals();
}
return;
}
// Otherwise, check if it's time to update based on timer
if(IsTimeToCheck())
{
UpdateIndicators();
ManagePositions();
CheckForEntrySignals();
lastCheckTime = TimeCurrent();
}
}
//+------------------------------------------------------------------+
//| Check if it's time to process |
//+------------------------------------------------------------------+
bool IsTimeToCheck()
{
if(TimeCurrent() - lastCheckTime >= Check_Interval_Seconds)
return true;
return false;
}
//+------------------------------------------------------------------+
//| Update indicators |
//+------------------------------------------------------------------+
void UpdateIndicators()
{
double atrBuffer[];
// Get current ATR value
if(CopyBuffer(atrHandle, 0, ATR_Shift, 1, atrBuffer) > 0)
{
atrValue = NormalizeDouble(atrBuffer[0], digits);
if(atrValue <= 0)
{
Print("Warning: ATR calculation returned zero or negative value. Using fallback value.");
atrValue = 0.0001; // Fallback to prevent errors
}
}
else
{
Print("Error getting ATR value: ", GetLastError());
}
}
//+------------------------------------------------------------------+
//| Check for entry signals |
//+------------------------------------------------------------------+
void CheckForEntrySignals()
{
// Check if we already have positions
if(PositionsTotal() > 0)
{
// For simplicity in testing, we'll only allow one position at a time
for(int i = 0; i < PositionsTotal(); i++)
{
if(posInfo.SelectByIndex(i))
{
if(posInfo.Symbol() == _Symbol && posInfo.Magic() == 123456)
return; // Exit if we already have a position
}
}
}
// Get MA values
double fastMA[], slowMA[];
if(CopyBuffer(fastMAHandle, 0, 0, 2, fastMA) <= 0 ||
CopyBuffer(slowMAHandle, 0, 0, 2, slowMA) <= 0)
{
Print("Error getting MA values");
return;
}
// Entry logic - MA crossover
bool buySignal = fastMA[1] <= slowMA[1] && fastMA[0] > slowMA[0];
bool sellSignal = fastMA[1] >= slowMA[1] && fastMA[0] < slowMA[0];
double currentPrice;
double stopLoss, takeProfit;
double bufferInPoints = Extra_Buffer_Pips * 10 * point;
// Check for Buy Signal
if(buySignal && Allow_Long_Positions)
{
currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
// Calculate SL and TP
stopLoss = Manage_SL ? NormalizeDouble(currentPrice - (atrValue * SL_ATR_Multiplier) - bufferInPoints, digits) : 0;
takeProfit = Manage_TP && !Close_At_Profit_Target ? NormalizeDouble(currentPrice + (atrValue * TP_ATR_Multiplier), digits) : 0;
// Execute the buy order
if(!trade.Buy(Lot_Size, _Symbol, 0, stopLoss, takeProfit, "ATR Strategy Buy"))
{
Print("Buy order failed with error: ", GetLastError());
}
else
{
Print("Buy order executed at ", currentPrice, " SL: ", stopLoss, " TP: ", takeProfit);
}
}
// Check for Sell Signal
if(sellSignal && Allow_Short_Positions)
{
currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
// Calculate SL and TP
stopLoss = Manage_SL ? NormalizeDouble(currentPrice + (atrValue * SL_ATR_Multiplier) + bufferInPoints, digits) : 0;
takeProfit = Manage_TP && !Close_At_Profit_Target ? NormalizeDouble(currentPrice - (atrValue * TP_ATR_Multiplier), digits) : 0;
// Execute the sell order
if(!trade.Sell(Lot_Size, _Symbol, 0, stopLoss, takeProfit, "ATR Strategy Sell"))
{
Print("Sell order failed with error: ", GetLastError());
}
else
{
Print("Sell order executed at ", currentPrice, " SL: ", stopLoss, " TP: ", takeProfit);
}
}
}
//+------------------------------------------------------------------+
//| Refresh list of position tickets |
//+------------------------------------------------------------------+
void RefreshPositions()
{
int total = PositionsTotal();
int count = 0;
// First, count valid positions
for(int i = 0; i < total; i++)
{
if(posInfo.SelectByIndex(i))
{
if(posInfo.Symbol() == _Symbol && posInfo.Magic() == 123456)
count++;
}
}
// Resize array and fill with position tickets
ArrayResize(positionTickets, count);
positionCount = 0;
for(int i = 0; i < total; i++)
{
if(posInfo.SelectByIndex(i))
{
if(posInfo.Symbol() == _Symbol && posInfo.Magic() == 123456)
{
positionTickets[positionCount] = posInfo.Ticket();
positionCount++;
}
}
}
}
//+------------------------------------------------------------------+
//| Manage all positions |
//+------------------------------------------------------------------+
void ManagePositions()
{
// Get current open positions
RefreshPositions();
// Convert buffer from pips to points
double bufferInPoints = Extra_Buffer_Pips * 10 * point;
// Display current ATR info
string info = "Current ATR: " + DoubleToString(atrValue, digits) + "\n";
info += "SL distance: " + DoubleToString(atrValue * SL_ATR_Multiplier + bufferInPoints, digits) + "\n";
info += "TP distance: " + DoubleToString(atrValue * TP_ATR_Multiplier, digits) + "\n";
info += "Positions managed: " + IntegerToString(positionCount);
Comment(info);
// Process existing positions
for(int i = 0; i < positionCount; i++)
{
if(posInfo.SelectByTicket(positionTickets[i]))
{
// Process the position
ProcessPosition(posInfo.PositionType(), posInfo.PriceOpen(),
posInfo.StopLoss(), posInfo.TakeProfit(),
posInfo.Ticket(), bufferInPoints);
}
}
}
//+------------------------------------------------------------------+
//| Process a single position |
//+------------------------------------------------------------------+
void ProcessPosition(ENUM_POSITION_TYPE posType, double openPrice,
double currentSL, double currentTP, ulong ticket,
double bufferInPoints)
{
double newSL = 0, newTP = 0;
double trailingStartLevel = 0;
double currentPrice = 0;
bool modifyPosition = false;
// Get current bid/ask
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
// Set SL and TP based on position type
if(posType == POSITION_TYPE_BUY)
{
currentPrice = bid;
// Calculate new stop loss if needed
if(Manage_SL)
{
// Initial SL calculation
newSL = NormalizeDouble(openPrice - (atrValue * SL_ATR_Multiplier) - bufferInPoints, digits);
}
else
{
newSL = currentSL; // Keep current SL
}
// Calculate new take profit if needed
if(Manage_TP && !Close_At_Profit_Target)
{
newTP = NormalizeDouble(openPrice + (atrValue * TP_ATR_Multiplier), digits);
}
else
{
newTP = currentTP; // Keep current TP
}
// Check for profit target if closing instead of TP
if(Close_At_Profit_Target)
{
double profitTarget = openPrice + (atrValue * TP_ATR_Multiplier);
if(currentPrice >= profitTarget)
{
// Close the position at profit target
if(trade.PositionClose(ticket))
{
Print("Position #", ticket, " closed at profit target!");
}
return; // Exit the function
}
}
// Check for trailing stop if enabled
if(Use_Trailing_Stop && Manage_SL)
{
// Calculate trailing start level
trailingStartLevel = NormalizeDouble(openPrice + (atrValue * Trail_Start_Multiplier), digits);
// Check if price has moved enough to activate trailing
if(currentPrice >= trailingStartLevel)
{
// Calculate new trailing stop level
double trailingSL = NormalizeDouble(currentPrice - (atrValue * Trail_Step_Multiplier) - bufferInPoints, digits);
// Only move stop up, never down
if(trailingSL > currentSL || currentSL == 0)
{
newSL = trailingSL;
modifyPosition = true;
}
}
}
}
else if(posType == POSITION_TYPE_SELL)
{
currentPrice = ask;
// Calculate new stop loss if needed
if(Manage_SL)
{
// Initial SL calculation
newSL = NormalizeDouble(openPrice + (atrValue * SL_ATR_Multiplier) + bufferInPoints, digits);
}
else
{
newSL = currentSL; // Keep current SL
}
// Calculate new take profit if needed
if(Manage_TP && !Close_At_Profit_Target)
{
newTP = NormalizeDouble(openPrice - (atrValue * TP_ATR_Multiplier), digits);
}
else
{
newTP = currentTP; // Keep current TP
}
// Check for profit target if closing instead of TP
if(Close_At_Profit_Target)
{
double profitTarget = openPrice - (atrValue * TP_ATR_Multiplier);
if(currentPrice <= profitTarget)
{
// Close the position at profit target
if(trade.PositionClose(ticket))
{
Print("Position #", ticket, " closed at profit target!");
}
return; // Exit the function
}
}
// Check for trailing stop if enabled
if(Use_Trailing_Stop && Manage_SL)
{
// Calculate trailing start level
trailingStartLevel = NormalizeDouble(openPrice - (atrValue * Trail_Start_Multiplier), digits);
// Check if price has moved enough to activate trailing
if(currentPrice <= trailingStartLevel)
{
// Calculate new trailing stop level
double trailingSL = NormalizeDouble(currentPrice + (atrValue * Trail_Step_Multiplier) + bufferInPoints, digits);
// Only move stop down (for shorts), never up
if(trailingSL < currentSL || currentSL == 0)
{
newSL = trailingSL;
modifyPosition = true;
}
}
}
}
// Ensure we're not moving SL in wrong direction for position type
if(posType == POSITION_TYPE_BUY && currentSL > 0 && newSL < currentSL)
{
// Keep current SL
newSL = currentSL;
}
else if(posType == POSITION_TYPE_SELL && currentSL > 0 && newSL > currentSL)
{
// Keep current SL
newSL = currentSL;
}
// Check if SL or TP needs to be changed
if((MathAbs(currentSL - newSL) > Point() && Manage_SL) ||
(MathAbs(currentTP - newTP) > Point() && Manage_TP) ||
modifyPosition)
{
// Apply the new SL and TP
if(trade.PositionModify(ticket, newSL, newTP))
{
string action = modifyPosition ? "Trailing Stop" : "Initial SL/TP";
Print(action, " applied to position #", ticket, " New SL: ", newSL, " New TP: ", newTP);
}
else
{
Print("Failed to modify position #", ticket, " Error: ", GetLastError());
}
}
}