//+------------------------------------------------------------------+ //| ATR Dynamic Risk Manager.mq5 | //| Optimized Forex ATR Risk Management System | // The MQL5 language is used for programming trading strategies and indicators for the MetaTrader 5platform. The script you mentioned, //"ATR Dynamic Risk Manager.mq5," seems to be a custom Expert Advisor (EA) or script designed to manage trading risk dynamically using the Average True Range (ATR) indicator. //Below is a general outline of how you might implement such a script: // //+------------------------------------------------------------------+ //| ATR Dynamic Risk Manager.mq5 | //| Your Name or Company Name Here | //| Your Website or Contact Info | //+------------------------------------------------------------------+ #property strict // Input parameters input double RiskPercentage = 1.0; // Risk percentage per trade input int ATRPeriod = 14; // ATR calculation period input double ATRMultiplier = 1.5; // Multiplier for ATR to set stop loss // Global variables double atrValue; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Initialization of the ATR indicator atrValue = iATR(_Symbol, _Period, ATRPeriod); if(atrValue <= 0) { Print("Error initializing ATR indicator"); return INIT_FAILED; } Print("ATR Dynamic Risk Manager initialized successfully"); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // Cleanup code if necessary } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Update ATR value on each tick atrValue = iATR(_Symbol, _Period, ATRPeriod); // Calculate the lot size based on risk percentage and ATR double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE); double riskAmount = accountBalance * (RiskPercentage / 100.0); double stopLoss = atrValue * ATRMultiplier; // Assuming a 1:1 risk-reward ratio for simplicity double lotSize = CalculateLotSize(riskAmount, stopLoss); // Example: Place a buy order with calculated lot size if(/* Your buy condition here */) { // Check for existing positions or orders if necessary // PlaceOrder function is a placeholder for your order logic PlaceOrder(ORDER_TYPE_BUY, lotSize, stopLoss); } } //+------------------------------------------------------------------+ //| Function to calculate lot size based on risk and stop loss | //+------------------------------------------------------------------+ double CalculateLotSize(double riskAmount, double stopLoss) { double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE); if(tickValue <= 0 || tickSize <= 0) { Print("Error retrieving symbol information"); return 0; } double lotSize = riskAmount / (stopLoss / tickSize * tickValue); return NormalizeDouble(lotSize, 2); // Adjust precision as needed } //+------------------------------------------------------------------+ //| Function to place an order | //+------------------------------------------------------------------+ void PlaceOrder(int orderType, double lotSize, double stopLoss) { // Implement order placement logic here // Example: OrderSend function with necessary parameters // Ensure to handle errors and order confirmation } //+------------------------------------------------------------------+ // // ### Key Components: // 1. **ATR Calculation**: The script uses the ATR indicator to determine market volatility. The ATR value is updated on each tick. // // 2. **Risk Management**: The script calculates the lot size based on a specified risk percentage of the account balance and the ATR value, which is used to set the stop loss. // // 3. **Order Placement**: The script includes a placeholder for order placement logic. You need to implement the actual conditions for opening trades and manage existing positions. // // 4. **Error Handling**: Ensure to handle any errors, especially during order placement and ATR calculation. // // ### Notes: // - This script is a template and requires further development to be functional. You need to define the specific trading conditions and complete the order placement logic. // - Always test your scripts on a demo account before deploying them on a live account to ensure they work as expected. // - Consider adding more features such as take profit levels, trailing stops, and additional risk management rules. // //+------------------------------------------------------------------+ #property copyright "Copyright 2025" #property link "" #property version "1.00" #property strict #property description "Dynamic ATR-based risk management EA for forex" #include #include #include // 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 Manage_New_Positions = true; // Apply to new positions input bool Manage_Existing_Positions = true; // Apply to existing positions input int Magic_Number = 123456; // EA Magic Number (0 for all positions) input bool Close_At_Profit_Target = false; // Close position at profit target instead of setting TP input group "Timing Parameters" input int Check_Interval_Seconds = 5; // Interval between checks (seconds) input bool Process_On_Bar_Close = false; // 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 positionCount = 0; ulong positionTickets[]; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Initialize trade operations trade.SetExpertMagicNumber(Magic_Number); // Initialize market information digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); // Create ATR indicator handle atrHandle = iATR(_Symbol, PERIOD_CURRENT, ATR_Period); if(atrHandle == INVALID_HANDLE) { Print("Error creating ATR indicator handle"); return(INIT_FAILED); } // Set timer if(!EventSetTimer(Check_Interval_Seconds)) { Print("Error setting timer"); return(INIT_FAILED); } // Initial identification of positions RefreshPositions(); Print("ATR Dynamic Risk Manager EA initialized successfully"); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // Release indicator handles IndicatorRelease(atrHandle); // Remove timer EventKillTimer(); // Clean up Comment(""); } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { // Check if it's time to update if(!IsTimeToCheck()) return; // Update ATR value and manage positions UpdateATRValue(); ManagePositions(); // 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; UpdateATRValue(); ManagePositions(); } return; } // Otherwise, check if it's time to update based on timer if(IsTimeToCheck()) { UpdateATRValue(); ManagePositions(); lastCheckTime = TimeCurrent(); } } //+------------------------------------------------------------------+ //| Check if it's time to process | //+------------------------------------------------------------------+ bool IsTimeToCheck() { if(TimeCurrent() - lastCheckTime >= Check_Interval_Seconds) return true; return false; } //+------------------------------------------------------------------+ //| Update ATR value | //+------------------------------------------------------------------+ void UpdateATRValue() { 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()); } } //+------------------------------------------------------------------+ //| 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(Magic_Number == 0 || posInfo.Magic() == Magic_Number) { if(posInfo.Symbol() == _Symbol) 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(Magic_Number == 0 || posInfo.Magic() == Magic_Number) { if(posInfo.Symbol() == _Symbol) { 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 if(Manage_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 pending orders if needed if(Manage_New_Positions) ProcessPendingOrders(bufferInPoints); } //+------------------------------------------------------------------+ //| Process pending orders | //+------------------------------------------------------------------+ void ProcessPendingOrders(double bufferInPoints) { for(int i = OrdersTotal() - 1; i >= 0; i--) { if(orderInfo.SelectByIndex(i)) { // Check if it's our order and symbol if((Magic_Number == 0 || orderInfo.Magic() == Magic_Number) && orderInfo.Symbol() == _Symbol) { // Get order type ENUM_ORDER_TYPE orderType = orderInfo.OrderType(); // Process only if it's a pending order if(orderType == ORDER_TYPE_BUY_LIMIT || orderType == ORDER_TYPE_BUY_STOP || orderType == ORDER_TYPE_SELL_LIMIT || orderType == ORDER_TYPE_SELL_STOP) { double newSL = 0.0, newTP = 0.0; double entryPrice = orderInfo.PriceOpen(); // Calculate SL and TP based on order type if(orderType == ORDER_TYPE_BUY_LIMIT || orderType == ORDER_TYPE_BUY_STOP) { if(Manage_SL) newSL = NormalizeDouble(entryPrice - (atrValue * SL_ATR_Multiplier) - bufferInPoints, digits); if(Manage_TP) newTP = NormalizeDouble(entryPrice + (atrValue * TP_ATR_Multiplier), digits); } else // Sell orders { if(Manage_SL) newSL = NormalizeDouble(entryPrice + (atrValue * SL_ATR_Multiplier) + bufferInPoints, digits); if(Manage_TP) newTP = NormalizeDouble(entryPrice - (atrValue * TP_ATR_Multiplier), digits); } // Get current SL and TP double currentSL = orderInfo.StopLoss(); double currentTP = orderInfo.TakeProfit(); // Check if we need to modify the order if((currentSL != newSL && Manage_SL) || (currentTP != newTP && Manage_TP)) { if(!Manage_SL) newSL = currentSL; // Keep current SL if not managing it if(!Manage_TP) newTP = currentTP; // Keep current TP if not managing it // Modify the order if(!trade.OrderModify(orderInfo.Ticket(), entryPrice, newSL, newTP, orderInfo.TypeTime(), orderInfo.TimeExpiration())) { Print("Failed to modify order #", orderInfo.Ticket(), " Error: ", GetLastError()); } } } } } } } //+------------------------------------------------------------------+ //| 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()); } } }