Initial commit: MQL Trading Bots

- MultiSignal Confluence EA v1.11 (stop loss bug fixed)
- Harmonic Pattern Finder v2 (optimized)
- Candlestick Pattern EA (fixed)
- Pivot Fade EA v4 (fixed)
- Bot series (10001, 10002, EnhancedEA)

Performance: ~19% return in 2 months on 00k account
This commit is contained in:
2026-03-21 18:39:48 -04:00
commit 74308b38e7
13 changed files with 4262 additions and 0 deletions

View File

@@ -0,0 +1,880 @@
//+------------------------------------------------------------------+
//| CandlestickPatternEA_Fixed.mq5 |
//| Copyright 2025, ART inc. |
//| CRITICAL FIX: Position counting |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, ARTi"
#property link "https://www.abbeyroadtech.com"
#property version "1.01"
#property strict
// Include necessary libraries
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
// Input Parameters for Trading
input double InpLotSize = 0.01; // Lot size
input int InpStopLoss = 100; // Stop Loss in points
input int InpTakeProfit = 200; // Take Profit in points
input bool InpUseHammerSignals = true; // Trade Hammer signals
input bool InpUsePinBarSignals = true; // Trade Pin Bar signals
input bool InpUseWickRejection = true; // Trade Wick Rejection signals
input bool InpUseTweezerTop = true; // Trade Tweezer Top signals
input bool InpUseShootingStar = true; // Trade Shooting Star signals
input int InpMaxPositions = 5; // Maximum open positions
input bool InpCloseOnOppositeSignal = true; // Close position on opposite signal
input ulong InpMagicNumber = 123456; // Magic number for this EA
// Trailing Stop Parameters
input bool InpUseTrailingStop = true; // Use trailing stop
input int InpTrailingStart = 50; // Points of profit before trailing begins
input int InpTrailingStep = 10; // Trailing step in points
input int InpTrailingStop = 30; // Trailing stop distance in points
// Input Parameters for Moving Average Filter
input int InpFastMA = 50; // Fast MA period
input int InpSlowMA = 200; // Slow MA period
input ENUM_MA_METHOD InpMAMethod = MODE_SMA; // MA method
input ENUM_APPLIED_PRICE InpMAPrice = PRICE_CLOSE; // Applied price
// Input Parameters for Indicator
input int InpCandlesToAnalyze = 300; // Number of candles to analyze
input double InpHammerRatio = 0.3; // Hammer body to wick ratio
input double InpPinBarRatio = 0.25; // Pin bar body to wick ratio
input double InpWickRejectionRatio = 0.4; // Wick rejection ratio
input double InpTweezerMaxDiff = 0.1; // Tweezer top max difference %
input double InpShootingStarRatio = 0.3; // Shooting star body to wick ratio
input int InpConfirmationCandles = 1; // Confirmation candles
// ATR Filter Parameters
input bool InpUseATRFilter = true; // Use ATR filter
input int InpATRPeriod = 14; // ATR period
input group "ATR Filter Mode"
input bool InpUseFixedATRValue = true; // Use fixed ATR value (vs percentage of peak)
input double InpMinATRValue = 0.0010; // Fixed: Minimum ATR value to trade (adjust for your pair)
input int InpATRLookbackPeriod = 50; // Period to find peak ATR value
input double InpATRPercentage = 30.0; // Percentage of peak ATR (30% = 0.3 * max ATR)
// Bollinger Band Width Filter Parameters
input bool InpUseBBWFilter = true; // Use Bollinger Band Width filter
input int InpBBPeriod = 20; // Bollinger Bands period
input double InpBBDeviation = 2.0; // Bollinger Bands deviation
input double InpMinBBWidth = 0.0020; // Minimum BB width to trade (as ratio)
// Global Variables
CTrade Trade; // Trading object
CSymbolInfo SymbolInfo; // Symbol info object
int FastMAHandle; // Fast MA indicator handle
int SlowMAHandle; // Slow MA indicator handle
int ATRHandle; // ATR indicator handle
int BBHandle; // Bollinger Bands indicator handle
int PatternIndicatorHandle; // Candlestick pattern indicator handle
bool isTradingAllowed = true; // Flag to control trading
datetime lastBarTime = 0; // Last processed bar time
// CRITICAL FIX: Removed unreliable position counters
// Now using CountOpenPositions() directly every time
//+------------------------------------------------------------------+
//| Input Validation |
//+------------------------------------------------------------------+
bool ValidateInputs()
{
// Validate lot size
if(InpLotSize <= 0)
{
Alert("ERROR: Lot size must be positive");
return false;
}
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
if(InpLotSize < minLot || InpLotSize > maxLot)
{
Alert("ERROR: Lot size must be between ", minLot, " and ", maxLot);
return false;
}
// Validate SL/TP
if(InpStopLoss <= 0)
{
Alert("ERROR: Stop Loss must be positive");
return false;
}
if(InpTakeProfit <= 0)
{
Alert("ERROR: Take Profit must be positive");
return false;
}
if(InpStopLoss >= InpTakeProfit)
{
Alert("WARNING: Stop Loss (", InpStopLoss, ") >= Take Profit (", InpTakeProfit, "). Unfavorable R:R ratio!");
// Don't return false - just warn, trader might want this
}
// Validate MA periods
if(InpFastMA <= 0 || InpSlowMA <= 0)
{
Alert("ERROR: MA periods must be positive");
return false;
}
if(InpFastMA >= InpSlowMA)
{
Alert("ERROR: Fast MA (", InpFastMA, ") should be less than Slow MA (", InpSlowMA, ")");
return false;
}
// Validate max positions
if(InpMaxPositions <= 0 || InpMaxPositions > 100)
{
Alert("ERROR: Max positions must be between 1 and 100");
return false;
}
// Validate trailing stop parameters
if(InpUseTrailingStop)
{
if(InpTrailingStart <= 0 || InpTrailingStop <= 0 || InpTrailingStep <= 0)
{
Alert("ERROR: Trailing stop parameters must be positive");
return false;
}
if(InpTrailingStop >= InpTrailingStart)
{
Alert("WARNING: Trailing stop distance (", InpTrailingStop, ") >= start level (", InpTrailingStart, ")");
}
}
// Validate ATR parameters
if(InpUseATRFilter)
{
if(InpATRPeriod <= 0)
{
Alert("ERROR: ATR period must be positive");
return false;
}
if(InpUseFixedATRValue)
{
if(InpMinATRValue <= 0)
{
Alert("ERROR: Minimum ATR value must be positive");
return false;
}
}
else
{
if(InpATRPercentage <= 0 || InpATRPercentage > 100)
{
Alert("ERROR: ATR percentage must be between 1 and 100");
return false;
}
if(InpATRLookbackPeriod <= 0)
{
Alert("ERROR: ATR lookback period must be positive");
return false;
}
}
}
// Validate BB parameters
if(InpUseBBWFilter)
{
if(InpBBPeriod <= 0 || InpBBDeviation <= 0)
{
Alert("ERROR: BB period and deviation must be positive");
return false;
}
if(InpMinBBWidth <= 0)
{
Alert("ERROR: Minimum BB width must be positive");
return false;
}
}
// Validate pattern ratios
if(InpHammerRatio <= 0 || InpPinBarRatio <= 0 || InpWickRejectionRatio <= 0 ||
InpTweezerMaxDiff < 0 || InpShootingStarRatio <= 0)
{
Alert("ERROR: Pattern ratios must be positive");
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// CRITICAL FIX: Validate all inputs first
if(!ValidateInputs())
return INIT_FAILED;
// Initialize symbol info
if(!SymbolInfo.Name(_Symbol))
{
Print("Failed to initialize symbol info");
return INIT_FAILED;
}
// CRITICAL FIX: Use input magic number instead of hardcoded
Trade.SetExpertMagicNumber(InpMagicNumber);
// Initialize indicator handles
FastMAHandle = iMA(_Symbol, _Period, InpFastMA, 0, InpMAMethod, InpMAPrice);
SlowMAHandle = iMA(_Symbol, _Period, InpSlowMA, 0, InpMAMethod, InpMAPrice);
// Initialize volatility filter indicators
if(InpUseATRFilter)
ATRHandle = iATR(_Symbol, _Period, InpATRPeriod);
if(InpUseBBWFilter)
BBHandle = iBands(_Symbol, _Period, InpBBPeriod, InpBBDeviation, 0, PRICE_CLOSE);
// Initialize the custom candlestick pattern indicator
PatternIndicatorHandle = iCustom(_Symbol, _Period, "CandlePatternConfirmation",
InpCandlesToAnalyze, InpHammerRatio, InpPinBarRatio,
InpWickRejectionRatio, InpTweezerMaxDiff, InpShootingStarRatio, InpConfirmationCandles);
// Check if indicators were created successfully
if(FastMAHandle == INVALID_HANDLE || SlowMAHandle == INVALID_HANDLE || PatternIndicatorHandle == INVALID_HANDLE)
{
Print("Failed to create primary indicators: Error ", GetLastError());
return INIT_FAILED;
}
if((InpUseATRFilter && ATRHandle == INVALID_HANDLE) || (InpUseBBWFilter && BBHandle == INVALID_HANDLE))
{
Print("Failed to create volatility filter indicators: Error ", GetLastError());
return INIT_FAILED;
}
// Set lastBarTime to avoid immediate trading on EA start
lastBarTime = iTime(_Symbol, _Period, 0);
// CRITICAL FIX: Log initialization with actual position count
int buyCount, sellCount;
CountOpenPositions(buyCount, sellCount);
string atrModeDesc = InpUseFixedATRValue ? "Fixed value: " + DoubleToString(InpMinATRValue, 5) :
"Dynamic: " + DoubleToString(InpATRPercentage, 1) + "% of peak over " +
IntegerToString(InpATRLookbackPeriod) + " bars";
Print("=== CandlestickPatternEA Fixed v1.01 Initialized ===");
Print("Magic Number: ", InpMagicNumber);
Print("Current Positions - Buy: ", buyCount, ", Sell: ", sellCount);
Print("ATR Filter: ", (InpUseATRFilter ? "ON (" + atrModeDesc + ")" : "OFF"));
Print("BBW Filter: ", (InpUseBBWFilter ? "ON" : "OFF"));
Print("Max Positions: ", InpMaxPositions);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Release indicator handles
if(FastMAHandle != INVALID_HANDLE) IndicatorRelease(FastMAHandle);
if(SlowMAHandle != INVALID_HANDLE) IndicatorRelease(SlowMAHandle);
if(PatternIndicatorHandle != INVALID_HANDLE) IndicatorRelease(PatternIndicatorHandle);
if(InpUseATRFilter && ATRHandle != INVALID_HANDLE) IndicatorRelease(ATRHandle);
if(InpUseBBWFilter && BBHandle != INVALID_HANDLE) IndicatorRelease(BBHandle);
Print("Expert removed. Reason: ", reason);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Check if there's a new bar
datetime currentBarTime = iTime(_Symbol, _Period, 0);
bool isNewBar = (currentBarTime != lastBarTime);
// Process trailing stops on every tick (not just new bars)
if(InpUseTrailingStop)
{
ManageTrailingStops();
}
// Only process signals on new bar
if(!isNewBar) return;
// Update lastBarTime
lastBarTime = currentBarTime;
// Check if trading is allowed
if(!isTradingAllowed) return;
// CRITICAL FIX: Get actual position counts directly
int totalBuyPositions, totalSellPositions;
CountOpenPositions(totalBuyPositions, totalSellPositions);
int totalPositions = totalBuyPositions + totalSellPositions;
// Check if maximum positions reached
if(totalPositions >= InpMaxPositions)
{
Print("Max positions reached (", totalPositions, "/", InpMaxPositions, "). Skipping trade check.");
return;
}
// Check volatility filters first
if(!CheckVolatilityFilters())
{
Print("Trade skipped due to low volatility or market indecision");
return;
}
// Check for MA filter
bool fastAboveSlow = false;
bool fastBelowSlow = false;
CheckMAFilter(fastAboveSlow, fastBelowSlow);
// Get candlestick pattern signals
bool hammerSignal = false;
bool pinBarSignal = false;
bool wickRejectionBullSignal = false;
bool wickRejectionBearSignal = false;
bool tweezerTopSignal = false;
bool shootingStarSignal = false;
CheckCandlestickPatterns(hammerSignal, pinBarSignal, wickRejectionBullSignal,
wickRejectionBearSignal, tweezerTopSignal, shootingStarSignal);
// Define candlestick pattern signals (without MA filter)
bool buyPatternSignal = (InpUseHammerSignals && hammerSignal) ||
(InpUseWickRejection && wickRejectionBullSignal);
bool sellPatternSignal = (InpUsePinBarSignals && pinBarSignal) ||
(InpUseWickRejection && wickRejectionBearSignal) ||
(InpUseTweezerTop && tweezerTopSignal) ||
(InpUseShootingStar && shootingStarSignal);
// Check for opposite candlestick pattern signals and close positions if needed
// This happens regardless of MA filter - based ONLY on candlestick patterns
if(sellPatternSignal && InpCloseOnOppositeSignal && totalBuyPositions > 0)
{
Print("Sell pattern detected - closing ", totalBuyPositions, " buy position(s)");
CloseBuyPositions();
}
if(buyPatternSignal && InpCloseOnOppositeSignal && totalSellPositions > 0)
{
Print("Buy pattern detected - closing ", totalSellPositions, " sell position(s)");
CloseSellPositions();
}
// CRITICAL FIX: Recount positions after potential closes
CountOpenPositions(totalBuyPositions, totalSellPositions);
totalPositions = totalBuyPositions + totalSellPositions;
// For opening new positions, use both candlestick pattern AND MA filter
bool validBuySignal = buyPatternSignal && fastAboveSlow;
bool validSellSignal = sellPatternSignal && fastBelowSlow;
// Process buy signals
if(validBuySignal && (totalBuyPositions < InpMaxPositions) && (totalPositions < InpMaxPositions))
{
// Check if we can place order (spread, stop level)
if(!CanPlaceOrder(ORDER_TYPE_BUY))
{
Print("Cannot place buy order - spread or stop level issue");
return;
}
// Open buy positions based on specific signals
if(InpUseHammerSignals && hammerSignal)
{
OpenBuyPosition("Hammer");
}
else if(InpUseWickRejection && wickRejectionBullSignal)
{
OpenBuyPosition("Wick Rejection Bullish");
}
}
// Process sell signals
if(validSellSignal && (totalSellPositions < InpMaxPositions) && (totalPositions < InpMaxPositions))
{
// Check if we can place order (spread, stop level)
if(!CanPlaceOrder(ORDER_TYPE_SELL))
{
Print("Cannot place sell order - spread or stop level issue");
return;
}
// Open sell positions based on specific signals
if(InpUsePinBarSignals && pinBarSignal)
{
OpenSellPosition("Pin Bar");
}
else if(InpUseWickRejection && wickRejectionBearSignal)
{
OpenSellPosition("Wick Rejection Bearish");
}
else if(InpUseTweezerTop && tweezerTopSignal)
{
OpenSellPosition("Tweezer Top");
}
else if(InpUseShootingStar && shootingStarSignal)
{
OpenSellPosition("Shooting Star");
}
}
}
//+------------------------------------------------------------------+
//| Check if order can be placed (spread and stop level check) |
//+------------------------------------------------------------------+
bool CanPlaceOrder(ENUM_ORDER_TYPE orderType)
{
SymbolInfo.Refresh();
SymbolInfo.RefreshRates();
double stopLevel = (double)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * _Point;
double spread = SymbolInfo.Ask() - SymbolInfo.Bid();
double minStopDistance = stopLevel + spread;
if(orderType == ORDER_TYPE_BUY)
{
double slDistance = (SymbolInfo.Ask() - (SymbolInfo.Ask() - InpStopLoss * _Point)) / _Point;
if(slDistance < minStopDistance)
{
Print("Buy SL distance (", slDistance, ") < minimum required (", minStopDistance, ")");
return false;
}
}
else if(orderType == ORDER_TYPE_SELL)
{
double slDistance = ((SymbolInfo.Bid() + InpStopLoss * _Point) - SymbolInfo.Bid()) / _Point;
if(slDistance < minStopDistance)
{
Print("Sell SL distance (", slDistance, ") < minimum required (", minStopDistance, ")");
return false;
}
}
return true;
}
//+------------------------------------------------------------------+
//| Check volatility filters to avoid trades during indecision |
//+------------------------------------------------------------------+
bool CheckVolatilityFilters()
{
// Check ATR Filter
if(InpUseATRFilter)
{
double atrValues[];
double minRequiredATR = 0;
// Get current ATR value
if(CopyBuffer(ATRHandle, 0, 0, 1, atrValues) <= 0)
{
Print("Failed to copy current ATR value: Error ", GetLastError());
return false;
}
double currentATR = atrValues[0];
// Determine which ATR threshold to use
if(InpUseFixedATRValue)
{
// Use the fixed value directly
minRequiredATR = InpMinATRValue;
}
else
{
// Get historical ATR values for the lookback period
if(CopyBuffer(ATRHandle, 0, 0, InpATRLookbackPeriod, atrValues) <= 0)
{
Print("Failed to copy historical ATR values: Error ", GetLastError());
return false;
}
// Find the peak ATR value in the lookback period
double peakATR = 0;
for(int i = 0; i < InpATRLookbackPeriod; i++)
{
if(atrValues[i] > peakATR)
peakATR = atrValues[i];
}
// Calculate minimum required ATR as percentage of peak
minRequiredATR = peakATR * (InpATRPercentage / 100.0);
}
// If current ATR is below threshold, market volatility is too low
if(currentATR < minRequiredATR)
{
Print("ATR Filter: Current ATR (", DoubleToString(currentATR, 5),
") is below minimum threshold (", DoubleToString(minRequiredATR, 5), ")");
return false;
}
}
// Check Bollinger Band Width Filter
if(InpUseBBWFilter)
{
double upperBand[1], lowerBand[1], middleBand[1];
if(CopyBuffer(BBHandle, 1, 0, 1, upperBand) <= 0 ||
CopyBuffer(BBHandle, 2, 0, 1, lowerBand) <= 0 ||
CopyBuffer(BBHandle, 0, 0, 1, middleBand) <= 0)
{
Print("Failed to copy Bollinger Bands values: Error ", GetLastError());
return false;
}
// Calculate width as a ratio rather than raw points
double bbWidth = (upperBand[0] - lowerBand[0]) / middleBand[0];
// If BB width is below minimum threshold, market is in consolidation
if(bbWidth < InpMinBBWidth)
{
Print("BB Width Filter: Current BB width (", DoubleToString(bbWidth, 5),
") is below minimum threshold (", DoubleToString(InpMinBBWidth, 5), ")");
return false;
}
}
// All filters passed or are disabled
return true;
}
//+------------------------------------------------------------------+
//| Check Moving Average Filter |
//+------------------------------------------------------------------+
void CheckMAFilter(bool &fastAboveSlow, bool &fastBelowSlow)
{
// Get MA values
double fastMAValue[1] = {0};
double slowMAValue[1] = {0};
// Copy MA values
if(CopyBuffer(FastMAHandle, 0, 0, 1, fastMAValue) <= 0 ||
CopyBuffer(SlowMAHandle, 0, 0, 1, slowMAValue) <= 0)
{
Print("Failed to copy MA values: Error ", GetLastError());
return;
}
// Set filter flags
fastAboveSlow = (fastMAValue[0] > slowMAValue[0]);
fastBelowSlow = (fastMAValue[0] < slowMAValue[0]);
}
//+------------------------------------------------------------------+
//| Check Candlestick Patterns |
//+------------------------------------------------------------------+
void CheckCandlestickPatterns(bool &hammerSignal, bool &pinBarSignal,
bool &wickRejectionBullSignal, bool &wickRejectionBearSignal,
bool &tweezerTopSignal, bool &shootingStarSignal)
{
// Arrays to store indicator values for each pattern
double hammerValues[1] = {0};
double pinBarValues[1] = {0};
double wickRejectionValues[1] = {0};
double tweezerTopValues[1] = {0};
double shootingStarValues[1] = {0};
// Get values from the pattern indicator
if(CopyBuffer(PatternIndicatorHandle, 0, 1, 1, hammerValues) <= 0 ||
CopyBuffer(PatternIndicatorHandle, 1, 1, 1, pinBarValues) <= 0 ||
CopyBuffer(PatternIndicatorHandle, 2, 1, 1, wickRejectionValues) <= 0 ||
CopyBuffer(PatternIndicatorHandle, 3, 1, 1, tweezerTopValues) <= 0 ||
CopyBuffer(PatternIndicatorHandle, 4, 1, 1, shootingStarValues) <= 0)
{
Print("Failed to copy pattern values: Error ", GetLastError());
return;
}
// Set signal flags
hammerSignal = (hammerValues[0] != EMPTY_VALUE);
pinBarSignal = (pinBarValues[0] != EMPTY_VALUE);
// For wick rejection, we need to determine if it's bullish or bearish
if(wickRejectionValues[0] != EMPTY_VALUE)
{
// Determine if bullish or bearish based on the position relative to the candle
double candleHigh = iHigh(_Symbol, _Period, 1);
wickRejectionBullSignal = (wickRejectionValues[0] < candleHigh);
wickRejectionBearSignal = (wickRejectionValues[0] > candleHigh);
}
else
{
wickRejectionBullSignal = false;
wickRejectionBearSignal = false;
}
tweezerTopSignal = (tweezerTopValues[0] != EMPTY_VALUE);
shootingStarSignal = (shootingStarValues[0] != EMPTY_VALUE);
}
//+------------------------------------------------------------------+
//| Open a Buy position |
//+------------------------------------------------------------------+
void OpenBuyPosition(string signalType)
{
// Update symbol info
SymbolInfo.Refresh();
SymbolInfo.RefreshRates();
// Calculate position size
double lotSize = InpLotSize;
// Calculate stop loss and take profit levels
double stopLoss = SymbolInfo.Ask() - InpStopLoss * SymbolInfo.Point();
double takeProfit = SymbolInfo.Ask() + InpTakeProfit * SymbolInfo.Point();
// Execute buy order
if(!Trade.Buy(lotSize, _Symbol, SymbolInfo.Ask(), stopLoss, takeProfit, signalType))
{
Print("Buy order failed: Error ", Trade.ResultRetcode(), ", ", Trade.ResultRetcodeDescription());
}
else
{
Print("Buy order placed successfully: Signal = ", signalType, ", Lots = ", lotSize);
}
}
//+------------------------------------------------------------------+
//| Open a Sell position |
//+------------------------------------------------------------------+
void OpenSellPosition(string signalType)
{
// Update symbol info
SymbolInfo.Refresh();
SymbolInfo.RefreshRates();
// Calculate position size
double lotSize = InpLotSize;
// Calculate stop loss and take profit levels
double stopLoss = SymbolInfo.Bid() + InpStopLoss * SymbolInfo.Point();
double takeProfit = SymbolInfo.Bid() - InpTakeProfit * SymbolInfo.Point();
// Execute sell order
if(!Trade.Sell(lotSize, _Symbol, SymbolInfo.Bid(), stopLoss, takeProfit, signalType))
{
Print("Sell order failed: Error ", Trade.ResultRetcode(), ", ", Trade.ResultRetcodeDescription());
}
else
{
Print("Sell order placed successfully: Signal = ", signalType, ", Lots = ", lotSize);
}
}
//+------------------------------------------------------------------+
//| Close all Buy positions |
//+------------------------------------------------------------------+
void CloseBuyPositions()
{
int closedCount = 0;
int failedCount = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
if(PositionSelectByTicket(ticket))
{
// Check if it's our EA's position
if(PositionGetInteger(POSITION_MAGIC) == InpMagicNumber)
{
// Check if it's a buy position
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
// Close the position
if(!Trade.PositionClose(ticket))
{
Print("Failed to close buy position #", ticket, ": Error ", Trade.ResultRetcode());
failedCount++;
}
else
{
Print("Buy position #", ticket, " closed on opposite signal");
closedCount++;
}
}
}
}
}
Print("CloseBuyPositions: ", closedCount, " closed, ", failedCount, " failed");
}
//+------------------------------------------------------------------+
//| Close all Sell positions |
//+------------------------------------------------------------------+
void CloseSellPositions()
{
int closedCount = 0;
int failedCount = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
if(PositionSelectByTicket(ticket))
{
// Check if it's our EA's position
if(PositionGetInteger(POSITION_MAGIC) == InpMagicNumber)
{
// Check if it's a sell position
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
{
// Close the position
if(!Trade.PositionClose(ticket))
{
Print("Failed to close sell position #", ticket, ": Error ", Trade.ResultRetcode());
failedCount++;
}
else
{
Print("Sell position #", ticket, " closed on opposite signal");
closedCount++;
}
}
}
}
}
Print("CloseSellPositions: ", closedCount, " closed, ", failedCount, " failed");
}
//+------------------------------------------------------------------+
//| CRITICAL FIX: Count open positions properly |
//+------------------------------------------------------------------+
void CountOpenPositions(int &buyCount, int &sellCount)
{
buyCount = 0;
sellCount = 0;
for(int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
if(PositionSelectByTicket(ticket))
{
// Check if it's our EA's position
if(PositionGetInteger(POSITION_MAGIC) == InpMagicNumber)
{
// Count by position type
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
if(posType == POSITION_TYPE_BUY)
buyCount++;
else if(posType == POSITION_TYPE_SELL)
sellCount++;
}
}
}
}
//+------------------------------------------------------------------+
//| Manage trailing stops for all open positions |
//+------------------------------------------------------------------+
void ManageTrailingStops()
{
// Update symbol info
SymbolInfo.Refresh();
SymbolInfo.RefreshRates();
double ask = SymbolInfo.Ask();
double bid = SymbolInfo.Bid();
double point = SymbolInfo.Point();
// Process all open positions
for(int i = 0; i < PositionsTotal(); i++)
{
// Select position by ticket
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
if(!PositionSelectByTicket(ticket))
continue;
// Check if it's our EA's position
if(PositionGetInteger(POSITION_MAGIC) != InpMagicNumber)
continue;
// Get position details
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double currentSL = PositionGetDouble(POSITION_SL);
double currentTP = PositionGetDouble(POSITION_TP);
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
// Trailing logic for BUY positions
if(posType == POSITION_TYPE_BUY)
{
// Calculate profit in points
double profitPoints = (bid - openPrice) / point;
// Only trail if minimum profit is reached
if(profitPoints >= InpTrailingStart)
{
// Calculate new stop loss level
double newSL = NormalizeDouble(bid - InpTrailingStop * point, _Digits);
// Only modify if new SL is higher (better) than current one
// and at least one trailing step away from current SL
if(newSL > currentSL + InpTrailingStep * point)
{
if(Trade.PositionModify(ticket, newSL, currentTP))
{
Print("Trailing stop adjusted for BUY position #", ticket,
" New SL: ", newSL, " Previous SL: ", currentSL);
}
else
{
Print("Failed to adjust trailing stop for #", ticket, ": Error ", Trade.ResultRetcode());
}
}
}
}
// Trailing logic for SELL positions
else if(posType == POSITION_TYPE_SELL)
{
// Calculate profit in points
double profitPoints = (openPrice - ask) / point;
// Only trail if minimum profit is reached
if(profitPoints >= InpTrailingStart)
{
// Calculate new stop loss level
double newSL = NormalizeDouble(ask + InpTrailingStop * point, _Digits);
// Only modify if new SL is lower (better) than current one
// and at least one trailing step away from current SL
if(currentSL == 0 || newSL < currentSL - InpTrailingStep * point)
{
if(Trade.PositionModify(ticket, newSL, currentTP))
{
Print("Trailing stop adjusted for SELL position #", ticket,
" New SL: ", newSL, " Previous SL: ", currentSL);
}
else
{
Print("Failed to adjust trailing stop for #", ticket, ": Error ", Trade.ResultRetcode());
}
}
}
}
}
}
//+------------------------------------------------------------------+