//+------------------------------------------------------------------+ //| DarvasBox.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property strict #include #include #include #include "../_united/MagicNumberHelpers.mqh" // Input parameters input int BoxPeriod = 165; // Period for Darvas Box calculation input double BoxDeviation = 25140; // Box deviation in points input int VolumeThreshold = 938; // Minimum volume for confirmation input double StopLoss = 1665; // Stop loss in points (increased for BTCUSD) input double TakeProfit = 3685; // Take profit in points (increased for BTCUSD) input bool EnableLogging = false; // Enable detailed logging input color BoxColor = clrBlue; // Color for Darvas Box input int BoxWidth = 1; // Width of box lines // Trend confirmation parameters input ENUM_TIMEFRAMES TrendTimeframe = PERIOD_H2; // Timeframe for trend analysis input int MA_Period = 125; // Moving Average period for trend input ENUM_MA_METHOD MA_Method = MODE_EMA; // Moving Average method input ENUM_APPLIED_PRICE MA_Price = PRICE_WEIGHTED; // Price type for MA input double TrendThreshold = 4.94; // Trend strength threshold // Volume analysis parameters input int VolumeMA_Period = 110; // Period for Volume MA input double VolumeThresholdMultiplier = 1.5; // Volume spike threshold // Magic Number input int MagicNumber = 135790; // Magic Number for Trades // Global variables double boxHigh = 0; double boxLow = 0; bool boxFormed = false; datetime lastBoxTime = 0; string boxName = "DarvasBox_"; double minStopLevel = 0; double point = 0; CTrade trade; // Indicator handles int maHandle; int volumeHandle; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Initialize indicators and variables boxHigh = 0; boxLow = 0; boxFormed = false; lastBoxTime = 0; // Get symbol properties point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); minStopLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * point; // Initialize indicators maHandle = iMA(_Symbol, TrendTimeframe, MA_Period, 0, MA_Method, MA_Price); volumeHandle = iVolumes(_Symbol, PERIOD_CURRENT, VOLUME_TICK); if(maHandle == INVALID_HANDLE || volumeHandle == INVALID_HANDLE) { Print("Error creating indicators"); return(INIT_FAILED); } // Configure trade object trade.SetDeviationInPoints(10); trade.SetTypeFilling(ORDER_FILLING_IOC); trade.SetAsyncMode(false); trade.SetExpertMagicNumber(MagicNumber); if(EnableLogging) { Print("Darvas Box Expert Advisor initialized"); Print("Symbol: ", _Symbol); Print("Point: ", point); Print("Minimum Stop Level: ", minStopLevel); } // Delete any existing box objects ObjectsDeleteAll(0, boxName); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Draw Darvas Box on chart | //+------------------------------------------------------------------+ void DrawDarvasBox() { if(!boxFormed) return; datetime time1 = iTime(_Symbol, PERIOD_H1, BoxPeriod); datetime time2 = iTime(_Symbol, PERIOD_H1, 0); // Delete old box ObjectsDeleteAll(0, boxName); // Draw box ObjectCreate(0, boxName + "Top", OBJ_TREND, 0, time1, boxHigh, time2, boxHigh); ObjectCreate(0, boxName + "Bottom", OBJ_TREND, 0, time1, boxLow, time2, boxLow); // Set box properties ObjectSetInteger(0, boxName + "Top", OBJPROP_COLOR, BoxColor); ObjectSetInteger(0, boxName + "Bottom", OBJPROP_COLOR, BoxColor); ObjectSetInteger(0, boxName + "Top", OBJPROP_WIDTH, BoxWidth); ObjectSetInteger(0, boxName + "Bottom", OBJPROP_WIDTH, BoxWidth); ObjectSetInteger(0, boxName + "Top", OBJPROP_RAY_RIGHT, true); ObjectSetInteger(0, boxName + "Bottom", OBJPROP_RAY_RIGHT, true); } //+------------------------------------------------------------------+ //| Calculate Darvas Box levels | //+------------------------------------------------------------------+ void CalculateDarvasBox() { double high = 0; double low = DBL_MAX; // Find highest high and lowest low in the period for(int i = 0; i < BoxPeriod; i++) { high = MathMax(high, iHigh(_Symbol, PERIOD_H1, i)); low = MathMin(low, iLow(_Symbol, PERIOD_H1, i)); } double range = high - low; double allowedRange = BoxDeviation * _Point; if(EnableLogging) { Print("Box Calculation - High: ", high, " Low: ", low, " Range: ", range, " Allowed Range: ", allowedRange); } // Check if box is formed if(range <= allowedRange) { boxHigh = high; boxLow = low; boxFormed = true; lastBoxTime = iTime(_Symbol, PERIOD_CURRENT, 0); // Draw the box DrawDarvasBox(); if(EnableLogging) Print("Box Formed - High: ", boxHigh, " Low: ", boxLow, " Time: ", lastBoxTime); } else { boxFormed = false; // Delete box if it exists ObjectsDeleteAll(0, boxName); } } //+------------------------------------------------------------------+ //| Validate and adjust stop levels | //+------------------------------------------------------------------+ bool ValidateStopLevels(double price, double &sl, double &tp, ENUM_ORDER_TYPE orderType) { double minSlDistance = MathMax(minStopLevel, StopLoss * point); double minTpDistance = MathMax(minStopLevel, TakeProfit * point); if(EnableLogging) { Print("Minimum SL Distance: ", minSlDistance); Print("Minimum TP Distance: ", minTpDistance); } // Adjust stop loss if(orderType == ORDER_TYPE_BUY) { sl = price - minSlDistance; tp = price + minTpDistance; if(EnableLogging) { Print("Buy Order Levels:"); Print("Entry: ", price); Print("Stop Loss: ", sl); Print("Take Profit: ", tp); } } else // ORDER_TYPE_SELL { sl = price + minSlDistance; tp = price - minTpDistance; if(EnableLogging) { Print("Sell Order Levels:"); Print("Entry: ", price); Print("Stop Loss: ", sl); Print("Take Profit: ", tp); } } return true; } //+------------------------------------------------------------------+ //| Check trend direction and strength | //+------------------------------------------------------------------+ bool IsTrendFavorable(ENUM_ORDER_TYPE orderType) { double ma[]; ArraySetAsSeries(ma, true); if(CopyBuffer(maHandle, 0, 0, 2, ma) <= 0) return false; double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double trendStrength = MathAbs(currentPrice - ma[0]) / point; if(EnableLogging) Print("Trend Strength: ", trendStrength); if(orderType == ORDER_TYPE_BUY) return (currentPrice > ma[0] && trendStrength > TrendThreshold); else return (currentPrice < ma[0] && trendStrength > TrendThreshold); } //+------------------------------------------------------------------+ //| Check volume conditions | //+------------------------------------------------------------------+ bool CheckVolumeConditions() { double volumes[]; ArraySetAsSeries(volumes, true); if(CopyBuffer(volumeHandle, 0, 0, VolumeMA_Period + 1, volumes) <= 0) return false; double volumeMA = 0; for(int i = 1; i <= VolumeMA_Period; i++) volumeMA += volumes[i]; volumeMA /= VolumeMA_Period; double currentVolume = volumes[0]; double volumeRatio = currentVolume / volumeMA; if(EnableLogging) Print("Volume Ratio: ", volumeRatio); return (volumeRatio > VolumeThresholdMultiplier); } //+------------------------------------------------------------------+ //| Place trade order | //+------------------------------------------------------------------+ bool PlaceOrder(ENUM_ORDER_TYPE orderType, double price, double sl, double tp) { // Validate and adjust stop levels if(!ValidateStopLevels(price, sl, tp, orderType)) { if(EnableLogging) Print("Invalid stop levels after adjustment"); return false; } // Check trend and volume conditions if(!IsTrendFavorable(orderType)) { if(EnableLogging) Print("Trend not favorable for trade"); return false; } if(!CheckVolumeConditions()) { if(EnableLogging) Print("Volume conditions not met"); return false; } if(EnableLogging) { Print("Order Details:"); Print("Type: ", EnumToString(orderType)); Print("Price: ", price); Print("Stop Loss: ", sl); Print("Take Profit: ", tp); } bool result = false; if(orderType == ORDER_TYPE_BUY) { result = trade.Buy(0.01, _Symbol, price, sl, tp, "Darvas Box Breakout"); } else { result = trade.Sell(0.01, _Symbol, price, sl, tp, "Darvas Box Breakdown"); } if(EnableLogging) { if(result) Print((orderType == ORDER_TYPE_BUY ? "Buy" : "Sell"), " Order Placed Successfully"); else Print((orderType == ORDER_TYPE_BUY ? "Buy" : "Sell"), " Order Failed - Error: ", trade.ResultRetcode(), " Description: ", trade.ResultRetcodeDescription()); } return result; } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Calculate new box levels CalculateDarvasBox(); // Check for trading signals if(boxFormed) { double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double currentVolume = iVolume(_Symbol, PERIOD_CURRENT, 0); if(EnableLogging) { Print("Current Price: ", currentPrice, " Box High: ", boxHigh, " Box Low: ", boxLow); Print("Current Volume: ", currentVolume, " Volume Threshold: ", VolumeThreshold); } // Check for breakout above box if(currentPrice > boxHigh && currentVolume > VolumeThreshold) { if(EnableLogging) Print("Breakout Signal Detected - Price above box high"); // Buy signal if(!PositionExistsByMagic(_Symbol, MagicNumber)) // No existing positions with our magic number { double sl = currentPrice - StopLoss * _Point; double tp = currentPrice + TakeProfit * _Point; if(EnableLogging) Print("Preparing Buy Order - Price: ", currentPrice, " SL: ", sl, " TP: ", tp); PlaceOrder(ORDER_TYPE_BUY, currentPrice, sl, tp); } else if(EnableLogging) Print("Skipping Buy Signal - Position already exists"); } // Check for breakdown below box if(currentPrice < boxLow && currentVolume > VolumeThreshold) { if(EnableLogging) Print("Breakdown Signal Detected - Price below box low"); // Sell signal if(!PositionExistsByMagic(_Symbol, MagicNumber)) // No existing positions with our magic number { double sl = currentPrice + StopLoss * _Point; double tp = currentPrice - TakeProfit * _Point; if(EnableLogging) Print("Preparing Sell Order - Price: ", currentPrice, " SL: ", sl, " TP: ", tp); PlaceOrder(ORDER_TYPE_SELL, currentPrice, sl, tp); } else if(EnableLogging) Print("Skipping Sell Signal - Position already exists"); } } else if(EnableLogging) Print("No Box Formed - Waiting for consolidation"); } //+------------------------------------------------------------------+ //| Get last error description | //+------------------------------------------------------------------+ string GetLastErrorDescription() { string errorDescription; switch(GetLastError()) { case 0: errorDescription = "No error"; break; case 1: errorDescription = "No error, but result unknown"; break; case 2: errorDescription = "Common error"; break; case 3: errorDescription = "Invalid trade parameters"; break; case 4: errorDescription = "Trade server is busy"; break; case 5: errorDescription = "Old version of the client terminal"; break; case 6: errorDescription = "No connection with trade server"; break; case 7: errorDescription = "Not enough rights"; break; case 8: errorDescription = "Too frequent requests"; break; case 9: errorDescription = "Malfunctional trade operation"; break; case 64: errorDescription = "Account disabled"; break; case 65: errorDescription = "Invalid account"; break; case 128: errorDescription = "Trade timeout"; break; case 129: errorDescription = "Invalid price"; break; case 130: errorDescription = "Invalid stops"; break; case 131: errorDescription = "Invalid trade volume"; break; case 132: errorDescription = "Market is closed"; break; case 133: errorDescription = "Trade is disabled"; break; case 134: errorDescription = "Not enough money"; break; case 135: errorDescription = "Price changed"; break; case 136: errorDescription = "Off quotes"; break; case 137: errorDescription = "Broker is busy"; break; case 138: errorDescription = "Requote"; break; case 139: errorDescription = "Order is locked"; break; case 140: errorDescription = "Long positions only allowed"; break; case 141: errorDescription = "Too many requests"; break; case 145: errorDescription = "Modification denied because order is too close to market"; break; case 146: errorDescription = "Trade context is busy"; break; case 147: errorDescription = "Expirations are denied by broker"; break; case 148: errorDescription = "Amount of open and pending orders has reached the limit"; break; case 149: errorDescription = "Hedging is prohibited"; break; case 150: errorDescription = "Prohibited by FIFO rules"; break; default: errorDescription = "Unknown error"; break; } return errorDescription; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // Delete all box objects ObjectsDeleteAll(0, boxName); if(EnableLogging) Print("Expert Advisor deinitialized - Reason: ", reason); }