Files
MQL5Data/Experts/x-saherelm.x121.xki.backtester.ea.mq5
T
saherelm 31232dffef some cleanups, refactor unnecessary requirements, implement rejected checkers and also counters ...
ass support for PV and KISuperSlow and MASuper Slow in KI Indicator and also Helper and implement them in BackTester ...
2026-01-07 04:27:38 +03:30

882 lines
22 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Expert Advisor
// -------------------------------------------------
// Name: X121XKIEABackTester
// Description: Base Expert Advisor as Template ...
//
// Maintainer:
// ------------
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
//
//////////////////////////////////////////////////////
//
// Global Properties ...
#property copyright "Copyright 2023, SaherElm IT Center"
#property link "https://saherelm.ir"
#property version "1.00"
#property icon "../Images/SaherElm_Logo_Color.ico"
#property description "SaherElm XFIMA Expert Advisor"
#property strict
//
#define ShortName "X121XKIEABackTester"
//
// Importts ...
#include "../Classes/x-saherelm.x-backtester.expert.class.mq5"
#include "../X121XKIEA/Classes/x-saherelm.x121.xki.signaller.class.mq5"
// #region Inputs ...
// #region Commons ...
input group "Common";
input long eaMagicNumber = 78692110; // Magic Number
input int eaSlippage = 10; // Slippgae
input string eaLogSuffix = ""; // Log Suffix
// #endregion
// #region Volume ...
input group "Volume";
input ENUM_X_VOLUME_SELECT_TYPE eaVolumeSelect = X_VOLUME_CONSTANT; // Volume Applying Type
input double eaStaticVoluem = 0.0; // Static Volume
input double eaDynamicVolumeStepBalance = 0.0; // Step of Balance for Increase Volume
input double eaDynamicVolumeStepVolume = X_MIN_VOLUME; // Step of Volume Increasing
input double eaConstantRiskBalance = 0.0; // Constant Risk Balance per Trade
input double eaConstantPercent = 1; // Constant Percent of Balance Per Trade
input double eaConstantBalance = 1000.0; // Constant Balance for Calculations
// #endregion
// #region Alert ...
input group "Alert";
input bool eaEnableAlerts = true; // Enable Alerts
input bool eaLogAlerts = true; // Log Alerts
input bool eaMailAlerts = false; // Mail Alerts
input bool eaPushAlerts = false; // Push Alerts
input bool eaTerminalAlerts = false; // Terminal Alerts
// #endregion
// #region Configurations ...
input group "Configuration";
input bool eaProcessAllTicks = false; // Process All Ticks
input double eaSignallerR2R = 2.0; // Risk To Reward Ratio
input double eaSignallerVolume = 0.01; // Default Volume
input double eaSignallerRiskInPoint = 50; // Default Risk In Point
// #endregion
// #region Bar Time ...
input group "Bar Timer";
input int barTimeFontSize = 10; // Font Size
input string barTimeFont = "Arial"; // Font
input color barTimeColor = clrYellow; // Text Color
input ENUM_BASE_CORNER barTimeCorner = CORNER_RIGHT_LOWER; // Text Position
input bool showBars = true; // Show Bars
input bool showBarTime = true; // Show Bar Time
// #endregion
// #region Indicator Inputs ...
//
input group "Calculation";
input int kiFastLength = 26; // KI Fast Length
input int kiSlowLength = 104; // KI Slow Length
input int kiSuperSlowLength = 208; // KI Super Slow Length
input int maFastLength = 26; // MA Fast Length
input int maSlowLength = 104; // MA Slow Length
input int maSuperSlowLength = 208; // MA Super Slow Length
input ENUM_MA_METHOD maMethod = MODE_EMA; // MA Mode
input ENUM_APPLIED_PRICE maAppliedTo = PRICE_CLOSE; // MA Applied To
input int rsiLength = 14; // RSI Length
input ENUM_APPLIED_PRICE rsiAppliedTo = PRICE_CLOSE; // RSI Applied To
input int kiWaveSmoothingLength = 14; // RSI KI Wave Smoothing Length
input ENUM_X_MA_METHOD kiWaveSmoothingMode = X_MA_MODE_EMA; // RSI KI Wave Smoothing Method
input double rsiMultiplier = 0.5; // RSI Multiplier
input int atrLength = 14; // ATR Length
input double atrMultiplier = 2; // ATR Multiplier
input int atrSmoothingLength = 14; // ATR Smoothing Length
input ENUM_X_MA_METHOD atrSmoothingMode = X_MA_MODE_EMA; // ATR Smoothing Method
input ENUM_X_PRICE atrUpperPriceType = X_PRICE_HIGH; // ATR Upper Price Type
input ENUM_X_PRICE atrLowerPriceType = X_PRICE_LOW; // ATR Lower Price Type
//
// Presentation ...
input group "Presentation";
input bool showPV = true; // Show PV
input bool showKIFast = true; // Show KI Fast
input bool showKISlow = true; // Show KI Slow
input bool showKISuperSlow = true; // Show KI Super Slow
input bool showMaFast = true; // Show Ma Fast
input bool showMaSlow = true; // Show MA Slow
input bool showMaSuperSlow = true; // Show MA Super Slow
input bool showKIWave = true; // Show KI Wave
input bool showKIUpper = true; // Show KI Upper
input bool showKILower = true; // Show KI Lower
//
input int startCalculationForLastBars = 1500; // Calculate Last n Bars
// #endregion
// #endregion
// #region Local Variables ...
//
// Requirements ...
string eaLogTag; // EA Log Prefix ...
XCBackTesterEA *eaExpert; // EA Expert ...
//
// Registered Signallers ...
XCX121XKIStrategy1Signaller *signaller1; // XFIMA1 Signaller ...
//
XBarTracker eaBarTracker; // EA Bar Traker ...
//
// Registered Handlers ...
int eaCTHandler = INVALID_HANDLE; // Candle Timer Handler ...
int eaCCHandler = INVALID_HANDLE; // Candle Cleaner Handler ...
//
bool eaIsNewBar; // Check New Bar ...
//
ENUM_CHART_MODE eaBarMode = CHART_CANDLES;
//
color eaBarUpColor = clrLime;
color eaBarDownColor = clrRed;
color eaBarLineColor = clrLime;
color eaBarBearishColor = clrRed;
color eaBarBullishColor = clrLime;
color eaBarVolumesColor = clrGreen;
// #endregion
// #region Event Handlers ...
//
// Initialization ...
int OnInit()
{
//
// Preparing Tags ...
string eaTag =
(IsValid(eaLogSuffix)
? eaLogSuffix + "_"
: "") +
ShortName;
//
// Validate Inputs and Required Parameters
// for EA to Works fine ...
if (!ValidateInputs())
{
return INIT_PARAMETERS_INCORRECT;
}
//
// Initialize Timer ...
if (!InitTimer())
{
return INIT_FAILED;
}
//
// Configure EA Expert Class ...
eaExpert = new XCBackTesterEA();
//
// Symbol / Period ...
eaExpert.symbol = _Symbol;
eaExpert.period = _Period;
//
// Common ...
eaExpert.eaMagicNumber = eaMagicNumber;
eaExpert.eaSlippage = eaSlippage;
eaExpert.eaLogSuffix = eaTag;
//
// Volume ...
eaExpert.eaVolumeSelect = eaVolumeSelect;
eaExpert.eaStaticVoluem = eaStaticVoluem;
eaExpert.eaDynamicVolumeStepBalance = eaDynamicVolumeStepBalance;
eaExpert.eaDynamicVolumeStepVolume = eaDynamicVolumeStepVolume;
eaExpert.eaConstantRiskBalance = eaConstantRiskBalance;
eaExpert.eaConstantPercent = eaConstantPercent;
eaExpert.eaConstantBalance = eaConstantBalance;
//
// Alert ...
eaExpert.eaEnableAlerts = eaEnableAlerts;
eaExpert.eaLogAlerts = eaLogAlerts;
eaExpert.eaMailAlerts = eaMailAlerts;
eaExpert.eaPushAlerts = eaPushAlerts;
eaExpert.eaTerminalAlerts = eaTerminalAlerts;
//
// Attach Event Handlers ...
eaExpert.AddOnDealsChangedEventHandler(OnDealsChanged);
eaExpert.AddOnStopLossEventHandler(OnStopLossTriggered);
eaExpert.AddOnOrdersChangedEventHandler(OnOrdersChanged);
eaExpert.AddOnSignalExecutedEventHandler(OnSignalExecuted);
eaExpert.AddOnTakeProfitEventHandler(OnTakeProfitTriggered);
eaExpert.AddOnModifyPositionEventHandler(OnPositionModified);
eaExpert.AddOnPositionsChangedEventHandler(OnPositionsChanged);
eaExpert.AddOnTradeStateChangedEventHandler(OnTradeStateChanged);
eaExpert.AddOnForceClosePositionEventHandler(OnPositionForceClosed);
eaExpert.AddOnPartialClosePositionEventHandler(OnPositionPartialClosed);
//
// Configure Other Requirements ...
eaExpert.allowedTPSLStep = 10;
eaExpert.minAllowedRiskInPoint = 20;
eaExpert.volume = eaSignallerVolume;
eaExpert.riskToRewardRatio = eaSignallerR2R;
eaExpert.riskInPoint = eaSignallerRiskInPoint;
//
// Try to Initialize eaExpert ...
bool isInited = eaExpert.HandleOnInit();
if (!isInited)
{
//
Print(ShortName, ": Initialization Failed ...");
return INIT_FAILED;
}
//
// Here Instantiate Signaller Class ...
//
// Preparing Indicator Inputs ...
X121XKIInputs kiInputs;
//
// This is Default Configuration ...
kiInputs.Default();
kiInputs.Hide();
//
// Here we Attach Inputs to Indicator ...
kiInputs.kiFastLength = kiFastLength;
kiInputs.kiSlowLength = kiSlowLength;
kiInputs.kiSuperSlowLength = kiSuperSlowLength;
kiInputs.maFastLength = maFastLength;
kiInputs.maSlowLength = maSlowLength;
kiInputs.maSuperSlowLength = maSuperSlowLength;
kiInputs.maMethod = maMethod;
kiInputs.maAppliedTo = maAppliedTo;
kiInputs.rsiLength = rsiLength;
kiInputs.rsiAppliedTo = rsiAppliedTo;
kiInputs.kiWaveSmoothingLength = kiWaveSmoothingLength;
kiInputs.kiWaveSmoothingMode = kiWaveSmoothingMode;
kiInputs.rsiMultiplier = rsiMultiplier;
kiInputs.atrLength = atrLength;
kiInputs.atrMultiplier = atrMultiplier;
kiInputs.atrSmoothingLength = atrSmoothingLength;
kiInputs.atrSmoothingMode = atrSmoothingMode;
kiInputs.atrUpperPriceType = atrUpperPriceType;
kiInputs.atrLowerPriceType = atrLowerPriceType;
kiInputs.showPV = showPV;
kiInputs.showKIFast = showKIFast;
kiInputs.showKISlow = showKISlow;
kiInputs.showKISuperSlow = showKISuperSlow;
kiInputs.showMaFast = showMaFast;
kiInputs.showMaSlow = showMaSlow;
kiInputs.showMaSuperSlow = showMaSuperSlow;
kiInputs.showKIWave = showKIWave;
kiInputs.showKIUpper = showKIUpper;
kiInputs.showKILower = showKILower;
kiInputs.startCalculationForLastBars = startCalculationForLastBars;
//
// Instantiate Signaller ...
//
// X121XKI1 Signaller ...
signaller1 = new XCX121XKIStrategy1Signaller(
_Symbol,
_Period,
kiInputs,
eaProcessAllTicks, // Process All Ticks ...
eaSignallerR2R, // Signaller Risk to Reward Ratio ...
eaSignallerRiskInPoint, // Default Risk In Points ...
eaSignallerVolume // Defaul Volume ...
);
//
// Configure Signaller ...
signaller1.ignoreTargets = false;
signaller1.slAdditionDistance = 30;
signaller1.maxAllowedRiskDistance = 350;
signaller1.AddOnSignalEventHandler(OnSignalTriggered);
//
isInited =
signaller1.IsValid();
if (!isInited)
{
//
Print(ShortName, ": Initialization Failed ...");
return INIT_FAILED;
}
//
// Initialize Candle Timer Handler ...
eaCTHandler = iCustom(
_Symbol,
_Period,
"x-saherelm.x121.xct",
//
// Inputs ...
barTimeFontSize, // Font Size ...
barTimeFont, // Font ...
barTimeColor, // Text Color ...
barTimeCorner, // Text Position ...
//
// Presentation ...
"",
showBarTime // Show Candle Time
//
);
isInited = eaCTHandler != INVALID_HANDLE;
if (!isInited)
{
//
Print(ShortName, ": Initialization Failed ...");
return INIT_FAILED;
}
//
// Initialize Candle Cleaner Handler ...
eaCCHandler = iCustom(
_Symbol,
_Period,
"x-saherelm.x121.xcc",
//
// Inputs ...
//
// Chart Style ...
"",
eaBarMode, // Mode
eaBarUpColor, // Up Color
eaBarDownColor, // Down Color
eaBarLineColor, // Line mode and Doji candlestick Color
eaBarBullishColor, // Bearish Color
eaBarBearishColor, // Bullish Color
eaBarVolumesColor, // Volumes Color
//
// Presentation ...
"",
showBars // Show Candles
//
);
isInited = eaCCHandler != INVALID_HANDLE;
if (!isInited)
{
//
Print(ShortName, ": Initialization Failed ...");
return INIT_FAILED;
}
//
// Initialize Bar Tracker ...
isInited = eaBarTracker.Init(
_Symbol,
_Period //
);
if (!isInited)
{
//
Print(ShortName, ": Initialization Failed ...");
return INIT_FAILED;
}
//
// Configure XFIMA POI Detector / Drawer ...
// detectorConfig.Default();
// detectorConfig.FullDetect();
// marketStructureDrawerConfig.FullDraw();
//
// Ignoring Position Drawer ...
delete eaExpert.eaPositionDrawer;
ZeroMemory(eaExpert.eaPositionDrawer);
eaExpert.eaPositionDrawer = NULL;
//
Print(ShortName, ": Initialized Successfully ...");
return INIT_SUCCEEDED;
}
//
// DeInitialization ...
void OnDeinit(const int reason)
{
//
// REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function
// REASON_REMOVE 1 Program removed from a chart
// REASON_RECOMPILE 2 Program recompiled
// REASON_CHARTCHANGE 3 A symbol or a chart period is changed
// REASON_CHARTCLOSE 4 Chart closed
// REASON_PARAMETERS 5 Inputs changed by a user
// REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings
// REASON_TEMPLATE 7 Another chart template applied
// REASON_INITFAILED 8 The OnInit() handler returned a non-zero value
// REASON_CLOSE 9 Terminal closed
//
// Destroy Timer ...
eaExpert.HandleOnDeInit();
//
// De Init Indicator ...
IndicatorRelease(eaCTHandler);
//
eaBarTracker.Clean();
//
delete signaller1;
ZeroMemory(signaller1);
//
delete eaExpert;
ZeroMemory(eaExpert);
}
//
// On Tick Handler ...
void OnTick()
{
//
eaIsNewBar = eaBarTracker.IsNewBar();
bool canProcess = eaProcessAllTicks
? true
: eaIsNewBar;
//
eaExpert.HandleOnTick();
//
if (!canProcess)
{
return;
}
//
// Bar Index ...
int barIndex = 0;
//
// Signallers Calling OnTick ...
signaller1.OnTick(barIndex);
//
// Checking For Guard only When has Position ...
XPosition positions[];
int positionsCount = eaExpert.eaTrader.GetPositions(
positions,
signaller1.symbol,
signaller1.name,
signaller1.period,
NULL, // All Types ...
true, // Filter By Magic ...
true // Force Clean ...
);
if (IsValidSize(positionsCount))
{
//
XGuard guards[];
int guardsCount = signaller1.CheckForGuard(
guards,
positions,
barIndex //
);
if (IsValidSize(guardsCount))
{
//
// Handling Guards ...
eaExpert.eaGuard.DoGuards(guards);
}
}
}
//
// Handle On Trade Event ...
void OnTrade()
{
eaExpert.HandleOnTrade();
}
//
// On Timer ...
void OnTimer()
{
eaExpert.HandleOnTimer();
}
//
// Chart Event Handler ...
void OnChartEvent(
const int id,
const long &lparam,
const double &dparam,
const string &sparam //
)
{
eaExpert.HandleOnChartEvent(id, lparam, dparam, sparam);
}
// #endregion
// #region Custom Event Handlers ...
/**
* Validate all Inputs of Expert Adviser ...
*
* @return ( bool )
*/
bool ValidateInputs()
{
//
bool result = false;
//
string errMessage = "";
//
bool isCommonValid = (
//
eaSlippage > 0 &&
eaMagicNumber > 0 &&
//
// Indicator Inputs ...
//
// KI ...
kiFastLength >= 5 &&
kiSlowLength > kiFastLength &&
//
// ATR ...
atrLength >= 5 &&
//
// RSI ...
rsiLength >= 5
//
//
);
if (!isCommonValid)
{
//
errMessage += "common configurations error;" + "\n";
}
//
result =
//
// Common ...
isCommonValid &&
//
// Otere ...
true
//
;
//
if (!result)
{
//
// Since here Logger not Initiallized, we Use Raw Print Command ...
Print(ShortName + " Errors: \n", errMessage);
}
//
return result;
}
/**
* Initialize Timer ...
*
* @return ( bool )
*/
bool InitTimer()
{
//
bool result = false;
//
// TODO: Initialize Timer if necessary ...
// result = EventSetTimer(1);
// result = EventSetMillisecondTimer(100);
result = true;
//
return result;
}
/**
* Destroy Timer ...
*/
void DestroyTimer()
{
//
// TODO: Use This ...
// EventKillTimer();
}
/**
* Trigger OnSignal Event ...
*
* @param signal: XSignal
*/
void OnSignalTriggered(XSignal &signal)
{
// //
// // Draw Signal on Chart ...
// XCSignalObject *iSignalObj;
// bool has = signaller1.poiDrawer.DrawSignal(
// signal,
// iSignalObj,
// 7 //
// );
//
eaExpert.HandleOnSignalTriggered(signal);
}
/**
* Trigger OnSignal Executed Event ...
*
* @param signal: XSignal
*/
void OnSignalExecuted(XSignal &signal)
{
eaExpert.HandleOnSignalExecuted(signal);
}
/**
* Check For Guard ...
*
* @param guards: XGuard, reference Collection to holds result ...
* @param positions: XPosition, refrence collection to Provides Positions ...
* @param barIndex: int, Specified Bar index ...
*
* @return ( int )
*/
int CheckForGuard(
XGuard &guards[],
XPosition &positions[],
int barIndex = 0 //
)
{
//
int result = signaller1.CheckForGuard(
guards,
positions,
barIndex //
);
//
return result;
}
//
// Trade Event Handlers ...
/**
* Handle StopLoss Triggered Positions ...
*
* @param deal: XDeal instance ...
*/
void OnStopLossTriggered(const XDeal &deal)
{
//
eaExpert.HandleOnStopLossTriggered(deal);
//
HandleBalanceReport();
HandleWinTrade(deal.positionId, deal.profit);
HandleLoseTrade(deal.positionId, deal.profit);
}
/**
* Handle Take Profit Triggered Positions ...
*
* @param deal: XDeal instance ...
*/
void OnTakeProfitTriggered(const XDeal &deal)
{
//
eaExpert.HandleOnTakeProfitTriggered(deal);
//
HandleBalanceReport();
HandleWinTrade(deal.positionId, deal.profit);
}
/**
* Handle Force Close a Position ...
*
* @param ticket: ULONG ...
* @param position: XPosition instance ...
* @param comment: String ...
*/
void OnPositionForceClosed(
const ulong ticket,
const XPosition &position,
const string comment //
)
{
//
eaExpert.HandleOnPositionForceClosed(
ticket,
position,
comment //
);
//
HandleBalanceReport();
HandleWinTrade(ticket, position.profit);
HandleLoseTrade(ticket, position.profit);
}
/**
* Handle Deals Changes ...
*
* @param count: Integer, Number of Changes ...
*/
void OnDealsChanged(int count)
{
eaExpert.HandleOnDealsChanged(count);
}
/**
* Handle Orders Changes ...
*
* @param count: Integer, Number of Changes ...
*/
void OnOrdersChanged(int count)
{
eaExpert.HandleOnOrdersChanged(count);
}
/**
* Handle Positions Changes ...
*
* @param count: Integer, Number of Changes ...
*/
void OnPositionsChanged(int count)
{
eaExpert.HandleOnPositionsChanged(count);
}
/**
* Handle Position Modified ...
*
* @param ticket: ulong, Position Ticket ...
* @param profit: double, Position Profit ...
* @param comment: string, Comment ...
*/
void OnPositionModified(
const ulong ticket,
const double profit,
const string comment //
)
{
//
eaExpert.HandleOnPositionModified(
ticket,
profit,
comment //
);
}
/**
* Handle Position Partial Closed ...
*
* @param ticket: ulong, Position Ticket ...
* @param profit: double, Position Profit ...
* @param comment: string, Comment ...
*/
void OnPositionPartialClosed(
const ulong ticket,
const double profit,
const string comment //
)
{
//
eaExpert.HandleOnPositionPartialClosed(
ticket,
profit,
comment //
);
}
/**
* Handle Trade State Changed ...
*
* @param state: XOnTradeHandlerState instance ...
*/
void OnTradeStateChanged(const XOnTradeHandlerState &state)
{
eaExpert.HandleOnTradeStateChanged(state);
}
/**
* Test Resting Signals ...
*
* @param ticket: ulong, Position Ticket ...
* @param profit: double, Position Profit ...
*/
void HandleLoseTrade(
ulong ticket = 0,
double profit = 0 //
)
{
//
// Check Position Loose ...
bool has = ticket > 0 &&
profit < 0;
if (!has)
{
return;
}
//
// NOTE: Here we Can Add Restrictions on Signaller based on our Requirements ...
// restingSignals: Specified Number of Signals which must to Ignore ...
// restUntil: Specified DateTime to Ignore all Signals before it Expiration ...
// restingDelay: Specified Bars Delay to Ignore all Signals before it passed ...
//
// Increase Resting Signals of Signallers ...
signaller1.LoseTrade();
}
/**
* Handle Win Trade ...
*
* @param ticket: ulong, Position Ticket ...
* @param profit: double, Position Profit ...
*/
void HandleWinTrade(
ulong ticket = 0,
double profit = 0 //
)
{
//
bool has = ticket > 0 &&
profit > 0;
if (!has)
{
return;
}
//
signaller1.WinTrade();
}
/**
* Handle Balance Report ...
*/
void HandleBalanceReport()
{
//
string message = eaExpert.eaTrader.mAccount.GetBalanceReportMessage();
eaExpert.eaAlert.SendAlert(message);
}
// #endregion