817 lines
31 KiB
Plaintext
817 lines
31 KiB
Plaintext
//+------------------------------------------------------------------+
|
|
//| X121_Strategy_EA.mq5 |
|
|
//| Copyright 2023, SaherElm IT |
|
|
//| https://saherelm.ir/ |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
|
#property link "https://saherelm.ir"
|
|
#property version "1.00"
|
|
#property description "EA based on X121 XCA and X3MA indicators"
|
|
#property strict
|
|
|
|
// Include Common Library
|
|
#include "../Libraries/x-saherelm.common.lib.mq5"
|
|
#include <Trade/Trade.mqh>
|
|
|
|
// Indicator handles
|
|
int xcaHandle = INVALID_HANDLE;
|
|
int x3maHandle = INVALID_HANDLE;
|
|
|
|
// Indicator buffers for XCA
|
|
double xcaTrendBuffer[];
|
|
double xcaTrendColorBuffer[];
|
|
double xcaKIBuffer[];
|
|
double xcaKIColorBuffer[];
|
|
double xcaVidyaBuffer[];
|
|
double xcaVidyaColorBuffer[];
|
|
double xcaSwingLowBuffer[];
|
|
double xcaSwingHighBuffer[];
|
|
double xcaSupportBuffer[];
|
|
double xcaResistanceBuffer[];
|
|
double xcaSLBuffer[]; // Short Cycle Low
|
|
double xcaSHBuffer[]; // Short Cycle High
|
|
double xcaMLBuffer[]; // Medium Cycle Low
|
|
double xcaMHBuffer[]; // Medium Cycle High
|
|
double xcaFiboLevel2Buffer[]; // 50% Fibo level
|
|
|
|
// Indicator buffers for X3MA
|
|
double x3maFastBuffer[];
|
|
double x3maFastColorBuffer[];
|
|
double x3maMediumBuffer[];
|
|
double x3maMediumColorBuffer[];
|
|
double x3maSlowBuffer[];
|
|
double x3maSlowColorBuffer[];
|
|
|
|
// Trade parameters
|
|
input group "Trade Settings" input double LotSize = 0.1; // Fixed Lot Size
|
|
input bool UseAutoLotSize = false; // Use Auto Lot Size
|
|
input double RiskPercent = 1.0; // Risk Percent (for Auto Lot)
|
|
input int StopLoss = 100; // Stop Loss in points
|
|
input int TakeProfit = 200; // Take Profit in points
|
|
input bool UseTrailingStop = true; // Use Trailing Stop
|
|
input int TrailingStop = 50; // Trailing Stop in points
|
|
input int TrailingStep = 10; // Trailing Step in points
|
|
|
|
input group "Strategy Parameters" input bool UseSwingPoints = true; // Use Swing Points for Entry
|
|
input bool UseFiboLevels = true; // Use Fibonacci Levels
|
|
input bool UseMAAlignment = true; // Require All MAs Alignment
|
|
input bool UseKIConfirmation = true; // Require KI Confirmation
|
|
input bool UseVidyaConfirmation = true; // Require VIDYA Confirmation
|
|
input bool UseTrendConfirmation = true; // Require Trend Confirmation
|
|
|
|
input group "Money Management" input bool UseMultipleTargets = true; // Use Multiple Profit Targets
|
|
input double Target1Percent = 33.0; // First Target Percentage
|
|
input double Target2Percent = 33.0; // Second Target Percentage
|
|
input double Target3Percent = 34.0; // Third Target Percentage
|
|
|
|
input group "Time Filter" input bool UseTimeFilter = false; // Use Time Filter
|
|
input string StartTradeTime = "08:00"; // Start Trading Time (Server Time)
|
|
input string EndTradeTime = "16:00"; // End Trading Time (Server Time)
|
|
|
|
// Global variables
|
|
int magicNumber = 12121;
|
|
bool isTradingAllowed = true;
|
|
datetime lastBarTime = 0;
|
|
int barsTotalPrev = 0;
|
|
|
|
// Trade objects
|
|
CTrade trade;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
// Initialize trade object
|
|
trade.SetExpertMagicNumber(magicNumber);
|
|
|
|
// Initialize XCA indicator
|
|
xcaHandle = iCustom(_Symbol, _Period, "x-saherelm.x121.xca");
|
|
if (xcaHandle == INVALID_HANDLE)
|
|
{
|
|
Print("Failed to create handle of the XCA indicator");
|
|
return (INIT_FAILED);
|
|
}
|
|
|
|
// Initialize X3MA indicator
|
|
x3maHandle = iCustom(_Symbol, _Period, "x-saherelm.x121.x3ma");
|
|
if (x3maHandle == INVALID_HANDLE)
|
|
{
|
|
Print("Failed to create handle of the X3MA indicator");
|
|
return (INIT_FAILED);
|
|
}
|
|
|
|
// Set up arrays as series
|
|
ArraySetAsSeries(xcaTrendBuffer, true);
|
|
ArraySetAsSeries(xcaTrendColorBuffer, true);
|
|
ArraySetAsSeries(xcaKIBuffer, true);
|
|
ArraySetAsSeries(xcaKIColorBuffer, true);
|
|
ArraySetAsSeries(xcaVidyaBuffer, true);
|
|
ArraySetAsSeries(xcaVidyaColorBuffer, true);
|
|
ArraySetAsSeries(xcaSwingLowBuffer, true);
|
|
ArraySetAsSeries(xcaSwingHighBuffer, true);
|
|
ArraySetAsSeries(xcaSupportBuffer, true);
|
|
ArraySetAsSeries(xcaResistanceBuffer, true);
|
|
ArraySetAsSeries(xcaSLBuffer, true);
|
|
ArraySetAsSeries(xcaSHBuffer, true);
|
|
ArraySetAsSeries(xcaMLBuffer, true);
|
|
ArraySetAsSeries(xcaMHBuffer, true);
|
|
ArraySetAsSeries(xcaFiboLevel2Buffer, true);
|
|
|
|
ArraySetAsSeries(x3maFastBuffer, true);
|
|
ArraySetAsSeries(x3maFastColorBuffer, true);
|
|
ArraySetAsSeries(x3maMediumBuffer, true);
|
|
ArraySetAsSeries(x3maMediumColorBuffer, true);
|
|
ArraySetAsSeries(x3maSlowBuffer, true);
|
|
ArraySetAsSeries(x3maSlowColorBuffer, true);
|
|
|
|
return (INIT_SUCCEEDED);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert deinitialization function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
// Release indicator handles
|
|
if (xcaHandle != INVALID_HANDLE)
|
|
IndicatorRelease(xcaHandle);
|
|
|
|
if (x3maHandle != INVALID_HANDLE)
|
|
IndicatorRelease(x3maHandle);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert tick function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
// Check if we're allowed to trade based on time filter
|
|
if (UseTimeFilter && !IsTradeTimeAllowed())
|
|
return;
|
|
|
|
// Get current bar time
|
|
datetime currentBarTime = iTime(_Symbol, _Period, 0);
|
|
|
|
// Only process on new bar
|
|
if (currentBarTime == lastBarTime)
|
|
return;
|
|
|
|
lastBarTime = currentBarTime;
|
|
|
|
// Update indicator buffers
|
|
if (!UpdateIndicatorBuffers())
|
|
return;
|
|
|
|
// Check for open positions and manage them
|
|
ManageOpenPositions();
|
|
|
|
// Check for new trade signals
|
|
CheckForTradeSignals();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Update all indicator buffers |
|
|
//+------------------------------------------------------------------+
|
|
bool UpdateIndicatorBuffers()
|
|
{
|
|
// Copy XCA indicator buffers
|
|
if (CopyBuffer(xcaHandle, 18, 0, 3, xcaTrendBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(xcaHandle, 19, 0, 3, xcaTrendColorBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(xcaHandle, 20, 0, 3, xcaKIBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(xcaHandle, 21, 0, 3, xcaKIColorBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(xcaHandle, 26, 0, 3, xcaVidyaBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(xcaHandle, 27, 0, 3, xcaVidyaColorBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(xcaHandle, 22, 0, 3, xcaSwingLowBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(xcaHandle, 23, 0, 3, xcaSwingHighBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(xcaHandle, 8, 0, 3, xcaSupportBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(xcaHandle, 9, 0, 3, xcaResistanceBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(xcaHandle, 0, 0, 3, xcaSHBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(xcaHandle, 1, 0, 3, xcaSLBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(xcaHandle, 2, 0, 3, xcaMHBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(xcaHandle, 3, 0, 3, xcaMLBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(xcaHandle, 15, 0, 3, xcaFiboLevel2Buffer) < 3)
|
|
return false;
|
|
|
|
// Copy X3MA indicator buffers
|
|
if (CopyBuffer(x3maHandle, 0, 0, 3, x3maFastBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(x3maHandle, 1, 0, 3, x3maFastColorBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(x3maHandle, 2, 0, 3, x3maMediumBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(x3maHandle, 3, 0, 3, x3maMediumColorBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(x3maHandle, 4, 0, 3, x3maSlowBuffer) < 3)
|
|
return false;
|
|
if (CopyBuffer(x3maHandle, 5, 0, 3, x3maSlowColorBuffer) < 3)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check if current time is within allowed trading hours |
|
|
//+------------------------------------------------------------------+
|
|
bool IsTradeTimeAllowed()
|
|
{
|
|
// If time filter is not enabled, always allow trading
|
|
if (!UseTimeFilter)
|
|
return true;
|
|
|
|
// Get current server time
|
|
datetime serverTime = TimeCurrent();
|
|
MqlDateTime currentTime;
|
|
TimeToStruct(serverTime, currentTime);
|
|
|
|
// Convert start and end time strings to hours and minutes
|
|
int startHour = 0, startMinute = 0;
|
|
int endHour = 0, endMinute = 0;
|
|
|
|
// Parse start time
|
|
string startTimeParts[];
|
|
if (StringSplit(StartTradeTime, ':', startTimeParts) == 2)
|
|
{
|
|
startHour = (int)StringToInteger(startTimeParts[0]);
|
|
startMinute = (int)StringToInteger(startTimeParts[1]);
|
|
}
|
|
|
|
// Parse end time
|
|
string endTimeParts[];
|
|
if (StringSplit(EndTradeTime, ':', endTimeParts) == 2)
|
|
{
|
|
endHour = (int)StringToInteger(endTimeParts[0]);
|
|
endMinute = (int)StringToInteger(endTimeParts[1]);
|
|
}
|
|
|
|
// Convert current time, start time and end time to minutes for easy comparison
|
|
int currentTimeInMinutes = currentTime.hour * 60 + currentTime.min;
|
|
int startTimeInMinutes = startHour * 60 + startMinute;
|
|
int endTimeInMinutes = endHour * 60 + endMinute;
|
|
|
|
// Check if current time is within trading hours
|
|
bool isAllowed = false;
|
|
|
|
// If end time is greater than start time (same day trading session)
|
|
if (endTimeInMinutes > startTimeInMinutes)
|
|
{
|
|
isAllowed = (currentTimeInMinutes >= startTimeInMinutes &&
|
|
currentTimeInMinutes <= endTimeInMinutes);
|
|
}
|
|
// If end time is less than start time (overnight trading session)
|
|
else if (endTimeInMinutes < startTimeInMinutes)
|
|
{
|
|
isAllowed = (currentTimeInMinutes >= startTimeInMinutes ||
|
|
currentTimeInMinutes <= endTimeInMinutes);
|
|
}
|
|
// If start time equals end time (24-hour trading)
|
|
else
|
|
{
|
|
isAllowed = true;
|
|
}
|
|
|
|
return isAllowed;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check for new trade signals |
|
|
//+------------------------------------------------------------------+
|
|
void CheckForTradeSignals()
|
|
{
|
|
// Don't open new trades if we already have open positions
|
|
if (CountOpenPositions() > 0)
|
|
return;
|
|
|
|
// Check for buy signal
|
|
if (IsBuySignal())
|
|
{
|
|
OpenBuyPosition();
|
|
}
|
|
// Check for sell signal
|
|
else if (IsSellSignal())
|
|
{
|
|
OpenSellPosition();
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check if we have a valid buy signal |
|
|
//+------------------------------------------------------------------+
|
|
bool IsBuySignal()
|
|
{
|
|
// 1. Trend Confirmation
|
|
bool trendConfirmation = true;
|
|
if (UseTrendConfirmation)
|
|
{
|
|
// X3MA: Fast MA crosses above Medium MA
|
|
bool fastCrossingAboveMedium = x3maFastBuffer[1] <= x3maMediumBuffer[1] &&
|
|
x3maFastBuffer[0] > x3maMediumBuffer[0];
|
|
|
|
// X3MA: All three MAs are in bullish alignment
|
|
bool maAlignment = true;
|
|
if (UseMAAlignment)
|
|
{
|
|
maAlignment = x3maFastBuffer[0] > x3maMediumBuffer[0] &&
|
|
x3maMediumBuffer[0] > x3maSlowBuffer[0];
|
|
}
|
|
|
|
// XCA: VIDYA line shows bullish color
|
|
bool vidyaBullish = true;
|
|
if (UseVidyaConfirmation)
|
|
{
|
|
vidyaBullish = xcaVidyaColorBuffer[0] == 1; // 1 is bullish color index
|
|
}
|
|
|
|
// XCA: Trend line shows bullish color
|
|
bool trendBullish = xcaTrendColorBuffer[0] == 1; // 1 is bullish color index
|
|
|
|
trendConfirmation = (fastCrossingAboveMedium || maAlignment) &&
|
|
(vidyaBullish || !UseVidyaConfirmation) &&
|
|
trendBullish;
|
|
}
|
|
|
|
// 2. Cycle Analysis
|
|
bool cycleAnalysis = true;
|
|
{
|
|
// XCA: Price is above the Short Cycle low
|
|
double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
bool priceAboveSL = currentPrice > xcaSLBuffer[0];
|
|
|
|
// XCA: Medium Cycle is in uptrend phase
|
|
bool mediumCycleUptrend = xcaMLBuffer[0] > xcaMLBuffer[1];
|
|
|
|
// XCA: Support level is established and holding
|
|
bool supportHolding = currentPrice > xcaSupportBuffer[0];
|
|
|
|
cycleAnalysis = priceAboveSL && mediumCycleUptrend && supportHolding;
|
|
}
|
|
|
|
// 3. Entry Timing
|
|
bool entryTiming = true;
|
|
{
|
|
// XCA: A swing low is identified
|
|
bool swingLowFound = UseSwingPoints ? xcaSwingLowBuffer[0] != 0 : true;
|
|
|
|
// XCA: Price is near but above the Fibonacci level 2 (50% retracement)
|
|
bool nearFiboLevel = true;
|
|
if (UseFiboLevels)
|
|
{
|
|
double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
double fiboLevel = xcaFiboLevel2Buffer[0];
|
|
double priceDiff = MathAbs(currentPrice - fiboLevel);
|
|
double priceRange = xcaResistanceBuffer[0] - xcaSupportBuffer[0];
|
|
nearFiboLevel = priceDiff < priceRange * 0.1 && currentPrice > fiboLevel;
|
|
}
|
|
|
|
// XCA: KI line shows bullish color
|
|
bool kiBullish = true;
|
|
if (UseKIConfirmation)
|
|
{
|
|
kiBullish = xcaKIColorBuffer[0] == 1; // 1 is bullish color index
|
|
}
|
|
|
|
entryTiming = swingLowFound && (nearFiboLevel || !UseFiboLevels) &&
|
|
(kiBullish || !UseKIConfirmation);
|
|
}
|
|
|
|
return trendConfirmation && cycleAnalysis && entryTiming;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check if we have a valid sell signal |
|
|
//+------------------------------------------------------------------+
|
|
bool IsSellSignal()
|
|
{
|
|
// 1. Trend Confirmation
|
|
bool trendConfirmation = true;
|
|
if (UseTrendConfirmation)
|
|
{
|
|
// X3MA: Fast MA crosses below Medium MA
|
|
bool fastCrossingBelowMedium = x3maFastBuffer[1] >= x3maMediumBuffer[1] &&
|
|
x3maFastBuffer[0] < x3maMediumBuffer[0];
|
|
|
|
// X3MA: All three MAs are in bearish alignment
|
|
bool maAlignment = true;
|
|
if (UseMAAlignment)
|
|
{
|
|
maAlignment = x3maFastBuffer[0] < x3maMediumBuffer[0] &&
|
|
x3maMediumBuffer[0] < x3maSlowBuffer[0];
|
|
}
|
|
|
|
// XCA: VIDYA line shows bearish color
|
|
bool vidyaBearish = true;
|
|
if (UseVidyaConfirmation)
|
|
{
|
|
vidyaBearish = xcaVidyaColorBuffer[0] == 2; // 2 is bearish color index
|
|
}
|
|
|
|
// XCA: Trend line shows bearish color
|
|
bool trendBearish = xcaTrendColorBuffer[0] == 2; // 2 is bearish color index
|
|
|
|
trendConfirmation = (fastCrossingBelowMedium || maAlignment) &&
|
|
(vidyaBearish || !UseVidyaConfirmation) &&
|
|
trendBearish;
|
|
}
|
|
|
|
// 2. Cycle Analysis
|
|
bool cycleAnalysis = true;
|
|
{
|
|
// XCA: Price is below the Short Cycle high
|
|
double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
bool priceBelowSH = currentPrice < xcaSHBuffer[0];
|
|
|
|
// XCA: Medium Cycle is in downtrend phase
|
|
bool mediumCycleDowntrend = xcaMHBuffer[0] < xcaMHBuffer[1];
|
|
|
|
// XCA: Resistance level is established and holding
|
|
bool resistanceHolding = currentPrice < xcaResistanceBuffer[0];
|
|
|
|
cycleAnalysis = priceBelowSH && mediumCycleDowntrend && resistanceHolding;
|
|
}
|
|
|
|
// 3. Entry Timing
|
|
bool entryTiming = true;
|
|
{
|
|
// XCA: A swing high is identified
|
|
bool swingHighFound = UseSwingPoints ? xcaSwingHighBuffer[0] != 0 : true;
|
|
|
|
// XCA: Price is near but below the Fibonacci level 2 (50% retracement)
|
|
bool nearFiboLevel = true;
|
|
if (UseFiboLevels)
|
|
{
|
|
double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
double fiboLevel = xcaFiboLevel2Buffer[0];
|
|
double priceDiff = MathAbs(currentPrice - fiboLevel);
|
|
double priceRange = xcaResistanceBuffer[0] - xcaSupportBuffer[0];
|
|
nearFiboLevel = priceDiff < priceRange * 0.1 && currentPrice < fiboLevel;
|
|
}
|
|
|
|
// XCA: KI line shows bearish color
|
|
bool kiBearish = true;
|
|
if (UseKIConfirmation)
|
|
{
|
|
kiBearish = xcaKIColorBuffer[0] == 2; // 2 is bearish color index
|
|
}
|
|
|
|
entryTiming = swingHighFound && (nearFiboLevel || !UseFiboLevels) &&
|
|
(kiBearish || !UseKIConfirmation);
|
|
}
|
|
|
|
return trendConfirmation && cycleAnalysis && entryTiming;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Count open positions with our magic number |
|
|
//+------------------------------------------------------------------+
|
|
int CountOpenPositions()
|
|
{
|
|
int count = 0;
|
|
int total = PositionsTotal();
|
|
|
|
for (int i = 0; i < total; i++)
|
|
{
|
|
ulong ticket = PositionGetTicket(i);
|
|
if (ticket <= 0)
|
|
continue;
|
|
|
|
// Check if position belongs to current symbol and our EA
|
|
if (PositionGetString(POSITION_SYMBOL) == _Symbol &&
|
|
PositionGetInteger(POSITION_MAGIC) == magicNumber)
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Manage open positions (trailing stops, partial closes) |
|
|
//+------------------------------------------------------------------+
|
|
void ManageOpenPositions()
|
|
{
|
|
int total = PositionsTotal();
|
|
|
|
// Loop through all open positions
|
|
for (int i = total - 1; i >= 0; i--)
|
|
{
|
|
ulong ticket = PositionGetTicket(i);
|
|
if (ticket <= 0)
|
|
continue;
|
|
|
|
// Check if position belongs to current symbol and our EA
|
|
if (PositionGetString(POSITION_SYMBOL) != _Symbol ||
|
|
PositionGetInteger(POSITION_MAGIC) != magicNumber)
|
|
continue;
|
|
|
|
// Get position details
|
|
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
|
|
double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT);
|
|
double stopLoss = PositionGetDouble(POSITION_SL);
|
|
double takeProfit = PositionGetDouble(POSITION_TP);
|
|
double positionVolume = PositionGetDouble(POSITION_VOLUME);
|
|
ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
|
|
|
// Check for exit signals
|
|
bool exitSignal = false;
|
|
|
|
// For BUY positions
|
|
if (positionType == POSITION_TYPE_BUY)
|
|
{
|
|
// Exit if Fast MA crosses below Medium MA
|
|
if (x3maFastBuffer[1] > x3maMediumBuffer[1] && x3maFastBuffer[0] <= x3maMediumBuffer[0])
|
|
exitSignal = true;
|
|
|
|
// Apply trailing stop if enabled
|
|
if (UseTrailingStop && !exitSignal)
|
|
{
|
|
// Calculate new stop loss level
|
|
double newStopLoss = 0;
|
|
|
|
// Use the most recent swing low as trailing stop if available
|
|
if (xcaSwingLowBuffer[0] > 0 && xcaSwingLowBuffer[0] < currentPrice)
|
|
{
|
|
newStopLoss = xcaSwingLowBuffer[0] - 5 * _Point;
|
|
}
|
|
else
|
|
{
|
|
// Traditional trailing stop
|
|
double trailingLevel = currentPrice - TrailingStop * _Point;
|
|
if (trailingLevel > stopLoss + TrailingStep * _Point)
|
|
newStopLoss = trailingLevel;
|
|
}
|
|
|
|
// Update stop loss if we have a better level
|
|
if (newStopLoss > stopLoss && newStopLoss > 0)
|
|
{
|
|
trade.PositionModify(ticket, newStopLoss, takeProfit);
|
|
Print("Updated BUY trailing stop to: ", newStopLoss);
|
|
}
|
|
}
|
|
|
|
// Handle multiple targets
|
|
if (UseMultipleTargets && positionVolume > LotSize * 0.5)
|
|
{
|
|
// First target: When price reaches resistance or initial TP
|
|
if (currentPrice >= xcaResistanceBuffer[0] && xcaResistanceBuffer[0] > openPrice)
|
|
{
|
|
double closeVolume = NormalizeDouble(positionVolume * Target1Percent / 100, 2);
|
|
if (closeVolume > 0)
|
|
{
|
|
trade.PositionClosePartial(ticket, closeVolume);
|
|
Print("First target reached for BUY position. Partially closed: ", closeVolume);
|
|
}
|
|
}
|
|
|
|
// Second target: When price reaches Fibonacci level 3 (76.4%)
|
|
double fiboLevel3Buffer[];
|
|
ArraySetAsSeries(fiboLevel3Buffer, true);
|
|
if (CopyBuffer(xcaHandle, 16, 0, 1, fiboLevel3Buffer) > 0)
|
|
{
|
|
double fiboLevel3 = fiboLevel3Buffer[0];
|
|
if (fiboLevel3 > 0 && currentPrice >= fiboLevel3 && fiboLevel3 > openPrice)
|
|
{
|
|
double closeVolume = NormalizeDouble(positionVolume * Target2Percent / 100, 2);
|
|
if (closeVolume > 0)
|
|
{
|
|
trade.PositionClosePartial(ticket, closeVolume);
|
|
Print("Second target reached for BUY position. Partially closed: ", closeVolume);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// For SELL positions
|
|
else if (positionType == POSITION_TYPE_SELL)
|
|
{
|
|
// Exit if Fast MA crosses above Medium MA
|
|
if (x3maFastBuffer[1] < x3maMediumBuffer[1] && x3maFastBuffer[0] >= x3maMediumBuffer[0])
|
|
exitSignal = true;
|
|
|
|
// Apply trailing stop if enabled
|
|
if (UseTrailingStop && !exitSignal)
|
|
{
|
|
// Calculate new stop loss level
|
|
double newStopLoss = 0;
|
|
|
|
// Use the most recent swing high as trailing stop if available
|
|
if (xcaSwingHighBuffer[0] > 0 && xcaSwingHighBuffer[0] > currentPrice)
|
|
{
|
|
newStopLoss = xcaSwingHighBuffer[0] + 5 * _Point;
|
|
}
|
|
else
|
|
{
|
|
// Traditional trailing stop
|
|
double trailingLevel = currentPrice + TrailingStop * _Point;
|
|
if (trailingLevel < stopLoss - TrailingStep * _Point || stopLoss == 0)
|
|
newStopLoss = trailingLevel;
|
|
}
|
|
|
|
// Update stop loss if we have a better level
|
|
if ((newStopLoss < stopLoss || stopLoss == 0) && newStopLoss > 0)
|
|
{
|
|
trade.PositionModify(ticket, newStopLoss, takeProfit);
|
|
Print("Updated SELL trailing stop to: ", newStopLoss);
|
|
}
|
|
}
|
|
|
|
// Handle multiple targets
|
|
if (UseMultipleTargets && positionVolume > LotSize * 0.5)
|
|
{
|
|
// First target: When price reaches support or initial TP
|
|
if (currentPrice <= xcaSupportBuffer[0] && xcaSupportBuffer[0] < openPrice)
|
|
{
|
|
double closeVolume = NormalizeDouble(positionVolume * Target1Percent / 100, 2);
|
|
if (closeVolume > 0)
|
|
{
|
|
trade.PositionClosePartial(ticket, closeVolume);
|
|
Print("First target reached for SELL position. Partially closed: ", closeVolume);
|
|
}
|
|
}
|
|
|
|
// Second target: When price reaches Fibonacci level 3 (76.4%)
|
|
double fiboLevel3Buffer[];
|
|
ArraySetAsSeries(fiboLevel3Buffer, true);
|
|
if (CopyBuffer(xcaHandle, 16, 0, 1, fiboLevel3Buffer) > 0)
|
|
{
|
|
double fiboLevel3 = fiboLevel3Buffer[0];
|
|
if (fiboLevel3 > 0 && currentPrice <= fiboLevel3 && fiboLevel3 < openPrice)
|
|
{
|
|
double closeVolume = NormalizeDouble(positionVolume * Target2Percent / 100, 2);
|
|
if (closeVolume > 0)
|
|
{
|
|
trade.PositionClosePartial(ticket, closeVolume);
|
|
Print("Second target reached for SELL position. Partially closed: ", closeVolume);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Close position if exit signal is triggered
|
|
if (exitSignal)
|
|
{
|
|
trade.PositionClose(ticket);
|
|
Print("Exit signal triggered. Position closed.");
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Open a buy position with proper risk management |
|
|
//+------------------------------------------------------------------+
|
|
void OpenBuyPosition()
|
|
{
|
|
double entryPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
double stopLossPrice = 0;
|
|
double takeProfitPrice = 0;
|
|
|
|
// Calculate stop loss price
|
|
if (StopLoss > 0)
|
|
{
|
|
// Use either the specified stop loss or the swing low, whichever is closer
|
|
double swingLowPrice = xcaSwingLowBuffer[0];
|
|
double slByPoints = entryPrice - StopLoss * _Point;
|
|
|
|
// If we have a valid swing low and it's not too far
|
|
if (swingLowPrice > 0 && entryPrice - swingLowPrice < StopLoss * 2 * _Point)
|
|
stopLossPrice = swingLowPrice - 5 * _Point; // Place SL slightly below swing low
|
|
else
|
|
stopLossPrice = slByPoints;
|
|
}
|
|
|
|
// Calculate take profit price
|
|
if (TakeProfit > 0)
|
|
{
|
|
// If using multiple targets, we'll set the first one here and manage the rest in position management
|
|
if (UseMultipleTargets)
|
|
{
|
|
// Use resistance level as first target if available
|
|
if (xcaResistanceBuffer[0] > entryPrice)
|
|
takeProfitPrice = xcaResistanceBuffer[0];
|
|
else
|
|
takeProfitPrice = entryPrice + TakeProfit * _Point;
|
|
}
|
|
else
|
|
{
|
|
takeProfitPrice = entryPrice + TakeProfit * _Point;
|
|
}
|
|
}
|
|
|
|
// Calculate position size
|
|
double volume = LotSize;
|
|
if (UseAutoLotSize && stopLossPrice > 0)
|
|
{
|
|
double riskAmount = AccountInfoDouble(ACCOUNT_BALANCE) * RiskPercent / 100;
|
|
double pipValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE) *
|
|
(SymbolInfoDouble(_Symbol, SYMBOL_POINT) / SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE));
|
|
double pipDistance = MathAbs(entryPrice - stopLossPrice) / SymbolInfoDouble(_Symbol, SYMBOL_POINT);
|
|
|
|
if (pipDistance > 0 && pipValue > 0)
|
|
volume = NormalizeDouble(riskAmount / (pipDistance * pipValue), 2);
|
|
|
|
// Ensure volume is within allowed limits
|
|
double minVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
|
|
double maxVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
|
|
double volumeStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
|
|
|
|
volume = MathMax(minVolume, MathMin(maxVolume, volume));
|
|
volume = NormalizeDouble(volume / volumeStep, 0) * volumeStep;
|
|
}
|
|
|
|
// Execute the trade
|
|
trade.Buy(volume, _Symbol, 0, stopLossPrice, takeProfitPrice, "X121 Strategy Buy");
|
|
|
|
// Log the trade
|
|
Print("BUY Signal: Opening position at ", entryPrice,
|
|
", SL: ", stopLossPrice,
|
|
", TP: ", takeProfitPrice,
|
|
", Volume: ", volume);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Open a sell position with proper risk management |
|
|
//+------------------------------------------------------------------+
|
|
void OpenSellPosition()
|
|
{
|
|
double entryPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
double stopLossPrice = 0;
|
|
double takeProfitPrice = 0;
|
|
|
|
// Calculate stop loss price
|
|
if (StopLoss > 0)
|
|
{
|
|
// Use either the specified stop loss or the swing high, whichever is closer
|
|
double swingHighPrice = xcaSwingHighBuffer[0];
|
|
double slByPoints = entryPrice + StopLoss * _Point;
|
|
|
|
// If we have a valid swing high and it's not too far
|
|
if (swingHighPrice > 0 && swingHighPrice - entryPrice < StopLoss * 2 * _Point)
|
|
stopLossPrice = swingHighPrice + 5 * _Point; // Place SL slightly above swing high
|
|
else
|
|
stopLossPrice = slByPoints;
|
|
}
|
|
|
|
// Calculate take profit price
|
|
if (TakeProfit > 0)
|
|
{
|
|
// If using multiple targets, we'll set the first one here and manage the rest in position management
|
|
if (UseMultipleTargets)
|
|
{
|
|
// Use support level as first target if available
|
|
if (xcaSupportBuffer[0] > 0 && xcaSupportBuffer[0] < entryPrice)
|
|
takeProfitPrice = xcaSupportBuffer[0];
|
|
else
|
|
takeProfitPrice = entryPrice - TakeProfit * _Point;
|
|
}
|
|
else
|
|
{
|
|
takeProfitPrice = entryPrice - TakeProfit * _Point;
|
|
}
|
|
}
|
|
|
|
// Calculate position size
|
|
double volume = LotSize;
|
|
if (UseAutoLotSize && stopLossPrice > 0)
|
|
{
|
|
double riskAmount = AccountInfoDouble(ACCOUNT_BALANCE) * RiskPercent / 100;
|
|
double pipValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE) *
|
|
(SymbolInfoDouble(_Symbol, SYMBOL_POINT) / SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE));
|
|
double pipDistance = MathAbs(entryPrice - stopLossPrice) / SymbolInfoDouble(_Symbol, SYMBOL_POINT);
|
|
|
|
if (pipDistance > 0 && pipValue > 0)
|
|
volume = NormalizeDouble(riskAmount / (pipDistance * pipValue), 2);
|
|
|
|
// Ensure volume is within allowed limits
|
|
double minVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
|
|
double maxVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
|
|
double volumeStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
|
|
|
|
volume = MathMax(minVolume, MathMin(maxVolume, volume));
|
|
volume = NormalizeDouble(volume / volumeStep, 0) * volumeStep;
|
|
}
|
|
|
|
// Execute the trade
|
|
trade.Sell(volume, _Symbol, 0, stopLossPrice, takeProfitPrice, "X121 Strategy Sell");
|
|
|
|
// Log the trade
|
|
Print("SELL Signal: Opening position at ", entryPrice,
|
|
", SL: ", stopLossPrice,
|
|
", TP: ", takeProfitPrice,
|
|
", Volume: ", volume);
|
|
}
|