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:
880
CandlestickPatternEA_Fixed.mq5
Normal file
880
CandlestickPatternEA_Fixed.mq5
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Reference in New Issue
Block a user