232 lines
7.5 KiB
Plaintext
232 lines
7.5 KiB
Plaintext
//+------------------------------------------------------------------+
|
|
//| SaherElm IT Center MQL5 Expert Advisor |
|
|
//| |
|
|
//| Name: X121 XPV EA |
|
|
//| Description: Multi-Timeframe Peak & Vale Breakout Strategy |
|
|
//| Maintainer: Hadi Khazaee Asl |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
|
#property link "https://saherelm.ir"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
//
|
|
#include "../Helpers/x-saherelm.x121.xpv.helper.mq5"
|
|
|
|
// Input Parameters
|
|
input double RiskPercent = 1.0; // Risk per trade in percentage
|
|
input int StopLossPips = 50; // Stop Loss in pips
|
|
input int TakeProfitPips = 100; // Take Profit in pips
|
|
input bool UseTrailingStop = true; // Enable trailing stop
|
|
input int TrailingStopPips = 30; // Trailing stop distance in pips
|
|
input int MagicNumber = 123456; // Unique identifier for trades
|
|
input bool DebugMode = true; // Enable debug messages
|
|
|
|
//
|
|
// Global Variables ...
|
|
X121XPVInputs mXPVInputs;
|
|
XCX121XPVHelper *mXPVHelper;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert Initialization Function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//
|
|
// Attach the X121 XPV indicator ...
|
|
mXPVInputs.Default();
|
|
mXPVHelper = new XCX121XPVHelper();
|
|
bool isInited = mXPVHelper.Init(
|
|
_Symbol,
|
|
_Period,
|
|
mXPVInputs //
|
|
);
|
|
if (!isInited)
|
|
{
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
//
|
|
Print("X121 XPV EA Initialized.");
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert Deinitialization Function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
//
|
|
mXPVInputs.Clean();
|
|
ZeroMemory(mXPVHelper);
|
|
Print("X121 XPV EA Deinitialized.");
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert Tick Function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
//
|
|
// Check if there are open positions for this symbol
|
|
if (PositionSelect(_Symbol))
|
|
{
|
|
ManageOpenPosition();
|
|
return;
|
|
}
|
|
|
|
//
|
|
X121XPVConditions pvConditions;
|
|
bool isRetrieved = mXPVHelper.GetConditions(
|
|
pvConditions,
|
|
1 //
|
|
);
|
|
if (!isRetrieved)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Get indicator values
|
|
double peak = pvConditions.peaksBuffer[0];
|
|
double vale = pvConditions.valesBuffer[0];
|
|
double peakGoldenZone = pvConditions.peaksGoldenBuffer[0];
|
|
double valeGoldenZone = pvConditions.valesGoldenBuffer[0];
|
|
|
|
//
|
|
// Validate indicator values
|
|
if (peak == EMPTY_VALUE || vale == EMPTY_VALUE || peakGoldenZone == EMPTY_VALUE || valeGoldenZone == EMPTY_VALUE)
|
|
{
|
|
//
|
|
if (DebugMode)
|
|
Print("Invalid indicator values. Skipping...");
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Entry Conditions
|
|
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
|
|
//
|
|
// Long Entry
|
|
if (bid > peak && bid > peakGoldenZone)
|
|
{
|
|
OpenTrade(ORDER_TYPE_BUY, peak, valeGoldenZone);
|
|
}
|
|
|
|
//
|
|
// Short Entry
|
|
if (ask < vale && ask < valeGoldenZone)
|
|
{
|
|
OpenTrade(ORDER_TYPE_SELL, vale, peakGoldenZone);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Open a Trade |
|
|
//+------------------------------------------------------------------+
|
|
void OpenTrade(int orderType, double entryLevel, double targetLevel)
|
|
{
|
|
//
|
|
double lotSize = CalculateLotSize(entryLevel, targetLevel);
|
|
double sl = (orderType == ORDER_TYPE_BUY) ? entryLevel - StopLossPips * Point() : entryLevel + StopLossPips * Point();
|
|
double tp = (orderType == ORDER_TYPE_BUY) ? entryLevel + TakeProfitPips * Point() : entryLevel - TakeProfitPips * Point();
|
|
|
|
//
|
|
// Prepare trade request
|
|
MqlTradeRequest request = {};
|
|
MqlTradeResult result = {};
|
|
|
|
//
|
|
request.action = TRADE_ACTION_DEAL;
|
|
request.symbol = _Symbol;
|
|
request.volume = lotSize;
|
|
request.type = (ENUM_ORDER_TYPE)orderType;
|
|
request.price = (orderType == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
request.sl = sl;
|
|
request.tp = tp;
|
|
request.deviation = 10;
|
|
request.magic = MagicNumber;
|
|
|
|
//
|
|
// Send trade request
|
|
if (!OrderSend(request, result))
|
|
{
|
|
Print("Trade failed: ", result.retcode);
|
|
}
|
|
else
|
|
{
|
|
Print("Trade opened successfully.");
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Manage Open Position |
|
|
//+------------------------------------------------------------------+
|
|
void ManageOpenPosition()
|
|
{
|
|
ulong ticket = PositionGetInteger(POSITION_TICKET);
|
|
double currentPrice = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_BID) : SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
|
|
double sl = PositionGetDouble(POSITION_SL);
|
|
double tp = PositionGetDouble(POSITION_TP);
|
|
|
|
// Trailing Stop Logic
|
|
if (UseTrailingStop)
|
|
{
|
|
double newSL = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
|
|
? currentPrice - TrailingStopPips * Point()
|
|
: currentPrice + TrailingStopPips * Point();
|
|
|
|
if ((PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && newSL > sl) ||
|
|
(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && newSL < sl))
|
|
{
|
|
ModifyPosition(ticket, newSL, tp);
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Modify Position |
|
|
//+------------------------------------------------------------------+
|
|
void ModifyPosition(ulong ticket, double newSL, double newTP)
|
|
{
|
|
MqlTradeRequest request = {};
|
|
MqlTradeResult result = {};
|
|
|
|
request.action = TRADE_ACTION_SLTP;
|
|
request.position = ticket;
|
|
request.sl = newSL;
|
|
request.tp = newTP;
|
|
|
|
if (!OrderSend(request, result))
|
|
{
|
|
Print("Failed to modify position: ", result.retcode);
|
|
}
|
|
else
|
|
{
|
|
Print("Position modified successfully.");
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate Lot Size |
|
|
//+------------------------------------------------------------------+
|
|
double CalculateLotSize(double entryLevel, double targetLevel)
|
|
{
|
|
double riskAmount = AccountInfoDouble(ACCOUNT_BALANCE) * RiskPercent / 100;
|
|
double stopLossDistance = MathAbs(entryLevel - targetLevel) / Point();
|
|
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
|
|
double lotSize = riskAmount / (stopLossDistance * tickValue);
|
|
|
|
// Normalize lot size
|
|
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
|
|
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
|
|
double stepLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
|
|
|
|
lotSize = MathFloor(lotSize / stepLot) * stepLot;
|
|
lotSize = MathMax(minLot, MathMin(maxLot, lotSize));
|
|
|
|
return lotSize;
|
|
} |