//+------------------------------------------------------------------+ //| TrendBarTrader.mq4 | //| Copyright 2024 | //+------------------------------------------------------------------+ #property copyright "Copyright 2024" #property link "" #property version "1.00" #property strict // Input parameters extern double LotSize = 0.1; // Trading lot size extern double WickLimit = 1.5; // Maximum wick size in points extern double BodyRatio = 70.0; // Minimum body to range ratio (%) // Global variables int ticket = 0; // Trade ticket number bool hasOpenPosition = false; // Flag for open positions //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Validate inputs if(LotSize <= 0 || WickLimit <= 0 || BodyRatio <= 0 || BodyRatio > 100) { Print("Invalid input parameters"); return INIT_PARAMETERS_INCORRECT; } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Check for new bar if(!IsNewBar()) return; // Check for data validity if(!IsValidData()) return; // Update existing position if we have one if(hasOpenPosition) { UpdateStopLoss(); return; } // Check for entry conditions CheckEntryConditions(); } //+------------------------------------------------------------------+ //| Check if we have a new bar | //+------------------------------------------------------------------+ bool IsNewBar() { static datetime lastBar = 0; datetime currentBar = iTime(Symbol(), Period(), 0); if(currentBar != lastBar) { lastBar = currentBar; return true; } return false; } //+------------------------------------------------------------------+ //| Validate data integrity | //+------------------------------------------------------------------+ bool IsValidData() { // Check for minimum bars needed if(Bars < 3) return false; // Check for valid prices for(int i = 0; i < 3; i++) { if(Open[i] == 0 || High[i] == 0 || Low[i] == 0 || Close[i] == 0) { Print("Invalid price data detected at bar ", i); return false; } // Check for price inconsistencies if(High[i] < Low[i] || High[i] < Open[i] || High[i] < Close[i] || Low[i] > Open[i] || Low[i] > Close[i]) { Print("Price mismatch detected at bar ", i); return false; } } return true; } //+------------------------------------------------------------------+ //| Check entry conditions | //+------------------------------------------------------------------+ void CheckEntryConditions() { double bodySize = MathAbs(Close[1] - Open[1]); double totalRange = High[1] - Low[1]; // Avoid division by zero if(totalRange == 0) return; double bodyRatioPercent = (bodySize / totalRange) * 100; // Check for bullish trend bar if(Close[1] > Open[1] && bodyRatioPercent >= BodyRatio && High[1] - Close[1] <= WickLimit * Point && High[1] > High[2]) { OpenTrade(OP_BUY); } // Check for bearish trend bar else if(Close[1] < Open[1] && bodyRatioPercent >= BodyRatio && Close[1] - Low[1] <= WickLimit * Point && Low[1] < Low[2]) { OpenTrade(OP_SELL); } } //+------------------------------------------------------------------+ //| Open new trade | //+------------------------------------------------------------------+ void OpenTrade(int type) { double stopLoss; if(type == OP_BUY) stopLoss = Low[1] - Point; else stopLoss = High[1] + Point; ticket = OrderSend( Symbol(), type, LotSize, Ask, 3, stopLoss, 0, "TrendBarTrader", 0, 0, type == OP_BUY ? clrGreen : clrRed ); if(ticket > 0) { hasOpenPosition = true; Print("Trade opened: ", type == OP_BUY ? "BUY" : "SELL"); } else { Print("Error opening trade: ", GetLastError()); } } //+------------------------------------------------------------------+ //| Update stop loss for existing position | //+------------------------------------------------------------------+ void UpdateStopLoss() { if(!OrderSelect(ticket, SELECT_BY_TICKET)) return; if(OrderType() == OP_BUY && Close[1] > Open[1]) { double newStop = Low[1] - Point; if(newStop > OrderStopLoss()) { if(!OrderModify(ticket, OrderOpenPrice(), newStop, 0, 0, clrGreen)) { Print("Error modifying stop loss: ", GetLastError()); } } } else if(OrderType() == OP_SELL && Close[1] < Open[1]) { double newStop = High[1] + Point; if(newStop < OrderStopLoss()) { if(!OrderModify(ticket, OrderOpenPrice(), newStop, 0, 0, clrRed)) { Print("Error modifying stop loss: ", GetLastError()); } } } // Check if position is still open if(OrderSelect(ticket, SELECT_BY_TICKET)) { if(OrderCloseTime() > 0) { hasOpenPosition = false; ticket = 0; } } }