From 011a82bf1eb22b3d66e0e4a1d1c2fea0df9430af Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Tue, 16 Sep 2025 00:44:27 +0330 Subject: [PATCH] last works on XBackTester and Complete it ... --- .../x-saherelm.x-backtester.expert.class.mq5 | 736 +++++++++++++++++- Experts/x-saherelm.backtester.ea.mq5 | 8 + Experts/x-saherelm.xfima.backtester.ea.mq5 | 138 +++- .../x-saherelm.common.extensions.lib.mq5 | 24 +- Libraries/x-saherelm.x-trade.lib.mq5 | 13 + 5 files changed, 882 insertions(+), 37 deletions(-) diff --git a/Classes/x-saherelm.x-backtester.expert.class.mq5 b/Classes/x-saherelm.x-backtester.expert.class.mq5 index 8f8e6dfc..506b6fed 100644 --- a/Classes/x-saherelm.x-backtester.expert.class.mq5 +++ b/Classes/x-saherelm.x-backtester.expert.class.mq5 @@ -71,11 +71,27 @@ class XCBackTesterEA : public XCBase bool eaPushAlerts; // Push Alerts bool eaTerminalAlerts; // Terminal Alerts + // + // SL/TP Manipulation Props ... + double allowedTPSLStep; // Value for Change TP/SL in Each Step ... + double minAllowedRiskInPoint; // Min Allowed Risk in Point ... + double riskInPoint; // Risk in Point per Trades ... + double riskToRewardRatio; // Risk To Reward per Trades ... + double volume; // Default volume Per Trade ... + // // Constructor ... XCBackTesterEA() { + // selectedPositionID = 0; + + // + volume = 0.01; + riskInPoint = 50; + allowedTPSLStep = 5; + riskToRewardRatio = 2; + minAllowedRiskInPoint = 10; } // @@ -260,6 +276,10 @@ class XCBackTesterEA : public XCBase return result; } + // + // Normalize Requirements ... + NormalizeProps(); + // return result; } @@ -668,21 +688,23 @@ class XCBackTesterEA : public XCBase CButton btnCloseAll; CEdit lblPositionId; + // + CButton lblTP; + CButton lblSL; + CButton btnSLPlus; + CButton btnTPPlus; + CButton btnSLMinus; + CButton btnTPMinus; + CButton btnSLPlusPlus; + CButton btnTPPlusPlus; + CButton btnSLMinusMinus; + CButton btnTPMinusMinus; + // CArrayObj posArray; CButton *btnSelectedPosInfo; CArrayObj selectedPosInfoArr; - // - int btnCloseSizeX; - int btnCloseSizeY; - int btnCloseStartX; - int btnCloseStartY; - int lblPositionIdSizeX; - int lblPositionIdSizeY; - int lblPositionIdStartX; - int lblPositionIdStartY; - // ulong selectedPositionID; bool showSelectedPositionInfo; @@ -774,10 +796,10 @@ class XCBackTesterEA : public XCBase // // LABEL Position ID ... - lblPositionIdStartX = btnBuyStartX; - lblPositionIdSizeX = lblPositionIdStartX + defaultWidth; - lblPositionIdStartY = btnSellSizeY + defaultGap; - lblPositionIdSizeY = lblPositionIdStartY + defaultHeight; + int lblPositionIdStartX = btnBuyStartX; + int lblPositionIdSizeX = lblPositionIdStartX + defaultWidth; + int lblPositionIdStartY = btnSellSizeY + defaultGap; + int lblPositionIdSizeY = lblPositionIdStartY + defaultHeight; string lblPositionIdName = objSuffix + "LBL_POS_ID"; result = lblPositionId.Create( chartId, @@ -800,10 +822,10 @@ class XCBackTesterEA : public XCBase // // Close ... - btnCloseStartX = startX; - btnCloseSizeX = btnCloseStartX + defaultWidth; - btnCloseStartY = lblPositionIdSizeY + defaultGap; - btnCloseSizeY = lblPositionIdSizeY + defaultHeight; + int btnCloseStartX = startX; + int btnCloseSizeX = btnCloseStartX + defaultWidth; + int btnCloseStartY = lblPositionIdSizeY + defaultGap; + int btnCloseSizeY = lblPositionIdSizeY + defaultHeight; string btnCloseName = objSuffix + "BTN_CLOSE"; result = btnClose.Create( chartId, @@ -852,6 +874,261 @@ class XCBackTesterEA : public XCBase btnCloseAll.ColorBackground(clrDarkRed); } + // + int minusPlusWidth = 20; + + // + // TP Label ... + int lblTPX1 = btnCloseStartX; + int lblTPX2 = lblTPX1 + defaultWidth; + int lblTPY1 = btnCloseSizeY + defaultGap; + int lblTPY2 = lblTPY1 + defaultHeight; + string lblTPName = objSuffix + "LBL_TP"; + result = lblTP.Create( + chartId, + lblTPName, + subWindow, + lblTPX1, + lblTPY1, + lblTPX2, + lblTPY2 // + ); + if (result) + { + // + // Apply Style ... + lblTP.Disable(); + lblTP.Text("TP"); + lblTP.Color(clrWhite); + lblTP.ColorBackground(clrGreen); + } + + // + // TP Plus ... + int btnTPPlusX1 = lblTPX1; + int btnTPPlusX2 = btnTPPlusX1 + minusPlusWidth; + int btnTPPlusY1 = lblTPY2 + defaultGap; + int btnTPPlusY2 = btnTPPlusY1 + defaultHeight; + string btnTPPlusName = objSuffix + "BTN_TP_PLUS"; + result = btnTPPlus.Create( + chartId, + btnTPPlusName, + subWindow, + btnTPPlusX1, + btnTPPlusY1, + btnTPPlusX2, + btnTPPlusY2 // + ); + if (result) + { + // + // Apply Style ... + btnTPPlus.Text("+"); + btnTPPlus.Color(clrYellow); + btnTPPlus.ColorBackground(clrGreen); + } + + // + // TP Plus Plus ... + int btnTPPlusPlusX1 = btnTPPlusX2 + defaultGap; + int btnTPPlusPlusX2 = btnTPPlusPlusX1 + minusPlusWidth; + int btnTPPlusPlusY1 = lblTPY2 + defaultGap; + int btnTPPlusPlusY2 = btnTPPlusPlusY1 + defaultHeight; + string btnTPPlusPlusName = objSuffix + "BTN_TP_PLUSPLUS"; + result = btnTPPlusPlus.Create( + chartId, + btnTPPlusPlusName, + subWindow, + btnTPPlusPlusX1, + btnTPPlusPlusY1, + btnTPPlusPlusX2, + btnTPPlusPlusY2 // + ); + if (result) + { + // + // Apply Style ... + btnTPPlusPlus.Text("++"); + btnTPPlusPlus.Color(clrYellow); + btnTPPlusPlus.ColorBackground(clrGreen); + } + + // + // TP Minus ... + int btnTPMinusX1 = lblTPX2 - minusPlusWidth; + int btnTPMinusX2 = btnTPMinusX1 + minusPlusWidth; + int btnTPMinusY1 = lblTPY2 + defaultGap; + int btnTPMinusY2 = btnTPMinusY1 + defaultHeight; + string btnTPMinusName = objSuffix + "BTN_TP_MINUS"; + result = btnTPMinus.Create( + chartId, + btnTPMinusName, + subWindow, + btnTPMinusX1, + btnTPMinusY1, + btnTPMinusX2, + btnTPMinusY2 // + ); + if (result) + { + // + // Apply Style ... + btnTPMinus.Text("-"); + btnTPMinus.Color(clrYellow); + btnTPMinus.ColorBackground(clrDarkRed); + } + + // + // TP Minus Minus ... + int btnTPMinusMinusX1 = btnTPMinusX1 - minusPlusWidth - defaultGap; + int btnTPMinusMinusX2 = btnTPMinusMinusX1 + minusPlusWidth; + int btnTPMinusMinusY1 = lblTPY2 + defaultGap; + int btnTPMinusMinusY2 = btnTPMinusY1 + defaultHeight; + string btnTPMinusMinusName = objSuffix + "BTN_TP_MINUSMINUS"; + result = btnTPMinusMinus.Create( + chartId, + btnTPMinusMinusName, + subWindow, + btnTPMinusMinusX1, + btnTPMinusMinusY1, + btnTPMinusMinusX2, + btnTPMinusMinusY2 // + ); + if (result) + { + // + // Apply Style ... + btnTPMinusMinus.Text("--"); + btnTPMinusMinus.Color(clrYellow); + btnTPMinusMinus.ColorBackground(clrDarkRed); + } + + // + // SL Label ... + int lblSLX1 = btnCloseAllStartX; + int lblSLX2 = lblSLX1 + defaultWidth; + int lblSLY1 = btnCloseAllSizeY + defaultGap; + int lblSLY2 = lblTPY1 + defaultHeight; + string lblSLName = objSuffix + "LBL_SL"; + result = lblSL.Create( + chartId, + lblSLName, + subWindow, + lblSLX1, + lblSLY1, + lblSLX2, + lblSLY2 // + ); + if (result) + { + // + // Apply Style ... + lblSL.Disable(); + lblSL.Text("SL"); + lblSL.Color(clrWhite); + lblSL.ColorBackground(clrDarkRed); + } + + // + // SL Plus ... + int btnSLPlusX1 = lblSLX1; + int btnSLPlusX2 = btnSLPlusX1 + minusPlusWidth; + int btnSLPlusY1 = lblSLY2 + defaultGap; + int btnSLPlusY2 = btnSLPlusY1 + defaultHeight; + string btnSLPlusName = objSuffix + "BTN_SL_PLUS"; + result = btnSLPlus.Create( + chartId, + btnSLPlusName, + subWindow, + btnSLPlusX1, + btnSLPlusY1, + btnSLPlusX2, + btnSLPlusY2 // + ); + if (result) + { + // + // Apply Style ... + btnSLPlus.Text("+"); + btnSLPlus.Color(clrYellow); + btnSLPlus.ColorBackground(clrGreen); + } + + // + // SL Plus Plus ... + int btnSLPlusPlusX1 = btnSLPlusX2 + defaultGap; + int btnSLPlusPlusX2 = btnSLPlusPlusX1 + minusPlusWidth; + int btnSLPlusPlusY1 = lblSLY2 + defaultGap; + int btnSLPlusPlusY2 = btnSLPlusPlusY1 + defaultHeight; + string btnSLPlusPlusName = objSuffix + "BTN_SL_PLUSPLUS"; + result = btnSLPlusPlus.Create( + chartId, + btnSLPlusPlusName, + subWindow, + btnSLPlusPlusX1, + btnSLPlusPlusY1, + btnSLPlusPlusX2, + btnSLPlusPlusY2 // + ); + if (result) + { + // + // Apply Style ... + btnSLPlusPlus.Text("++"); + btnSLPlusPlus.Color(clrYellow); + btnSLPlusPlus.ColorBackground(clrGreen); + } + + // + // SL Minus ... + int btnSLMinusX1 = lblSLX2 - minusPlusWidth; + int btnSLMinusX2 = btnSLMinusX1 + minusPlusWidth; + int btnSLMinusY1 = lblSLY2 + defaultGap; + int btnSLMinusY2 = btnSLMinusY1 + defaultHeight; + string btnSLMinusName = objSuffix + "BTN_SL_MINUS"; + result = btnSLMinus.Create( + chartId, + btnSLMinusName, + subWindow, + btnSLMinusX1, + btnSLMinusY1, + btnSLMinusX2, + btnSLMinusY2 // + ); + if (result) + { + // + // Apply Style ... + btnSLMinus.Text("-"); + btnSLMinus.Color(clrYellow); + btnSLMinus.ColorBackground(clrDarkRed); + } + + // + // SL Minus Minus ... + int btnSLMinusMinusX1 = btnSLMinusX1 - minusPlusWidth - defaultGap; + int btnSLMinusMinusX2 = btnSLMinusMinusX1 + minusPlusWidth; + int btnSLMinusMinusY1 = lblSLY2 + defaultGap; + int btnSLMinusMinusY2 = btnSLMinusY1 + defaultHeight; + string btnSLMinusMinusName = objSuffix + "BTN_SL_MINUSMINUS"; + result = btnSLMinusMinus.Create( + chartId, + btnSLMinusMinusName, + subWindow, + btnSLMinusMinusX1, + btnSLMinusMinusY1, + btnSLMinusMinusX2, + btnSLMinusMinusY2 // + ); + if (result) + { + // + // Apply Style ... + btnSLMinusMinus.Text("--"); + btnSLMinusMinus.Color(clrYellow); + btnSLMinusMinus.ColorBackground(clrDarkRed); + } + // UpdateGUIState(); @@ -971,6 +1248,124 @@ class XCBackTesterEA : public XCBase } } + // + // TP Managing ... + + // + // TP Plus ... + if (btnTPPlus.Pressed()) + { + // + if (btnTPPlus.IsEnabled()) + { + HandleTPChange(X_DIRECTION_BULLISH); + } + + // + btnTPPlus.Pressed(false); + } + + // + // TP Plus Plus ... + if (btnTPPlusPlus.Pressed()) + { + // + if (btnTPPlusPlus.IsEnabled()) + { + HandleTPChange(X_DIRECTION_BULLISH, 2); + } + + // + btnTPPlusPlus.Pressed(false); + } + + // + // TP Minus ... + if (btnTPMinus.Pressed()) + { + // + if (btnTPMinus.IsEnabled()) + { + HandleTPChange(X_DIRECTION_BEARISH); + } + + // + btnTPMinus.Pressed(false); + } + + // + // TP Minus Minus ... + if (btnTPMinusMinus.Pressed()) + { + // + if (btnTPMinusMinus.IsEnabled()) + { + HandleTPChange(X_DIRECTION_BEARISH, 2); + } + + // + btnTPMinusMinus.Pressed(false); + } + + // + // SL Managing ... + + // + // SL Plus ... + if (btnSLPlus.Pressed()) + { + // + if (btnSLPlus.IsEnabled()) + { + HandleSLChange(X_DIRECTION_BULLISH); + } + + // + btnSLPlus.Pressed(false); + } + + // + // SL Plus Plus ... + if (btnSLPlusPlus.Pressed()) + { + // + if (btnSLPlusPlus.IsEnabled()) + { + HandleSLChange(X_DIRECTION_BULLISH, 2); + } + + // + btnSLPlusPlus.Pressed(false); + } + + // + // SL Minus ... + if (btnSLMinus.Pressed()) + { + // + if (btnSLMinus.IsEnabled()) + { + HandleSLChange(X_DIRECTION_BEARISH); + } + + // + btnSLMinus.Pressed(false); + } + + // + // SL Minus Minus ... + if (btnSLMinusMinus.Pressed()) + { + // + if (btnSLMinusMinus.IsEnabled()) + { + HandleSLChange(X_DIRECTION_BEARISH, 2); + } + + // + btnSLMinusMinus.Pressed(false); + } + // // Check Positions Buttons ... int posCount = posArray.Total(); @@ -1224,22 +1619,25 @@ class XCBackTesterEA : public XCBase string name = objSuffix + "BTN_TOOGLE_SPOS_INFO"; // - int btnStartX = btnCloseStartX; - int btnSizeX = btnStartX + 200 + 5; + CRect iRect = btnTPPlus.Rect(); // - int btnStartY = btnCloseSizeY + 5; - int btnSizeY = btnStartY + 25; + int x1 = iRect.left; + int x2 = x1 + 200 + 5; + + // + int y1 = iRect.bottom + 5; + int y2 = y1 + iRect.Height(); // bool isCreated = btnSelectedPosInfo.Create( chartId, name, subWindow, - btnStartX, - btnStartY, - btnSizeX, - btnSizeY // + x1, + y1, + x2, + y2 // ); if (!isCreated) { @@ -1416,12 +1814,92 @@ class XCBackTesterEA : public XCBase // btnClose.Disable(); btnClose.ColorBackground(clrDarkGray); + + // + lblTP.Disable(); + lblTP.ColorBackground(clrDarkGray); + + // + btnTPPlus.Disable(); + btnTPPlus.ColorBackground(clrDarkGray); + + // + btnTPPlusPlus.Disable(); + btnTPPlusPlus.ColorBackground(clrDarkGray); + + // + btnTPMinus.Disable(); + btnTPMinus.ColorBackground(clrDarkGray); + + // + btnTPMinusMinus.Disable(); + btnTPMinusMinus.ColorBackground(clrDarkGray); + + // + lblSL.Disable(); + lblSL.ColorBackground(clrDarkGray); + + // + btnSLPlus.Disable(); + btnSLPlus.ColorBackground(clrDarkGray); + + // + btnSLPlusPlus.Disable(); + btnSLPlusPlus.ColorBackground(clrDarkGray); + + // + btnSLMinus.Disable(); + btnSLMinus.ColorBackground(clrDarkGray); + + // + btnSLMinusMinus.Disable(); + btnSLMinusMinus.ColorBackground(clrDarkGray); } else { // btnClose.Enable(); btnClose.ColorBackground(clrDarkOrange); + + // + lblTP.Enable(); + lblTP.ColorBackground(clrGreen); + + // + btnTPPlus.Enable(); + btnTPPlus.ColorBackground(clrGreen); + + // + btnTPPlusPlus.Enable(); + btnTPPlusPlus.ColorBackground(clrGreen); + + // + btnTPMinus.Enable(); + btnTPMinus.ColorBackground(clrDarkRed); + + // + btnTPMinusMinus.Enable(); + btnTPMinusMinus.ColorBackground(clrDarkRed); + + // + lblSL.Enable(); + lblSL.ColorBackground(clrDarkRed); + + // + btnSLPlus.Enable(); + btnSLPlus.ColorBackground(clrGreen); + + // + btnSLPlusPlus.Enable(); + btnSLPlusPlus.ColorBackground(clrGreen); + + // + btnSLMinus.Enable(); + btnSLMinus.ColorBackground(clrDarkRed); + + // + btnSLMinusMinus.Enable(); + btnSLMinusMinus.ColorBackground(clrDarkRed); } } @@ -1490,14 +1968,18 @@ class XCBackTesterEA : public XCBase // int btnWidth = 25; + int btnHeight = 25; // - int lastX = lblPositionIdSizeX + 5; + CRect iRect = lblPositionId.Rect(); + + // + int lastX = iRect.left + iRect.Width() + 5; int lastSizeX = lastX + btnWidth; // - int lastY = lblPositionIdStartY; - int lastSizeY = lblPositionIdSizeY; + int lastY = iRect.top; + int lastSizeY = lastY + iRect.Height(); // for (int i = 0; i < count; i++) @@ -1588,18 +2070,21 @@ class XCBackTesterEA : public XCBase return; } + // + NormalizeProps(); + // bool isBullish = IsSpecifiedBullish(dir); // - double r2r = 1.5; - double volume = 0.01; - double riskInPoints = 100; + double r2r = riskToRewardRatio; + double _volume = volume; + double _riskInPoints = riskInPoint; double point = GetPoints(symbol); double entry = GetEntry(symbol, dir); // - double risk = riskInPoints * point; + double risk = _riskInPoints * point; double reward = risk * r2r; // @@ -1620,7 +2105,7 @@ class XCBackTesterEA : public XCBase eaTrader.Buy( symbol, period, - volume, + _volume, entry, sl, tp, @@ -1633,7 +2118,7 @@ class XCBackTesterEA : public XCBase eaTrader.Sell( symbol, period, - volume, + _volume, entry, sl, tp, @@ -1677,9 +2162,190 @@ class XCBackTesterEA : public XCBase } } + // + void HandleTPChange( + ENUM_X_DIRECTION dir, + int multiplier = 1 // + ) + { + // + // Validate ... + if (selectedPositionID == 0 || !HasDirection(dir)) + { + return; + } + + // + NormalizeProps(); + + // + // Normalize Multiplier ... + multiplier = NormalizeInt(multiplier, 1, 2); + + // + // Select Position ... + XPosition position; + bool has = eaTrader.GetPosition( + selectedPositionID, + position // + ); + if (!has) + { + // + position.Clean(); + return; + } + + // + bool isLong = IsLong(position.type); + bool isBullish = IsSpecifiedBullish(dir); + + // + double point = GetPoints(position.symbol); + double stepValue = multiplier * (point * allowedTPSLStep); + + // + bool mustIncrease = + isBullish + ? isLong + : !isLong; + + // + double tp = position.tp; + tp = + mustIncrease + ? tp + stepValue + : tp - stepValue; + bool isModified = eaTrader.Modify( + position.ticket, + position.sl, + tp, + objSuffix + "Change TP" // + ); + if (isModified) + { + UpdateGUIState(); + } + + // + position.Clean(); + } + + // + void HandleSLChange( + ENUM_X_DIRECTION dir, + int multiplier = 1 // + ) + { + // + // Validate ... + if (selectedPositionID == 0 || !HasDirection(dir)) + { + return; + } + + // + NormalizeProps(); + + // + // Normalize Multiplier ... + multiplier = NormalizeInt(multiplier, 1, 2); + + // + // Select Position ... + XPosition position; + bool has = eaTrader.GetPosition( + selectedPositionID, + position // + ); + if (!has) + { + // + position.Clean(); + return; + } + + // + bool isLong = IsLong(position.type); + bool isBullish = IsSpecifiedBullish(dir); + + // + double point = GetPoints(position.symbol); + double stepValue = multiplier * (point * allowedTPSLStep); + + // + bool mustIncrease = + isBullish + ? !isLong + : isLong; + + // + double risk = position.GetRiskInPoint(); + if (risk <= minAllowedRiskInPoint) + { + // + position.Clean(); + return; + } + + // + double sl = position.sl; + sl = + mustIncrease + ? sl + stepValue + : sl - stepValue; + bool isModified = eaTrader.Modify( + position.ticket, + sl, + position.tp, + objSuffix + "Change SL" // + ); + if (isModified) + { + UpdateGUIState(); + } + + // + position.Clean(); + } + // // Custom Tools ... + // + void NormalizeProps() + { + // + if (volume < 0.01) + { + volume = 0.01; + } + + // + if (riskInPoint < 0) + { + riskInPoint = 50; + } + + // + if (allowedTPSLStep < 5) + { + allowedTPSLStep = 5; + } + + // + if (riskToRewardRatio < 0.5) + { + riskToRewardRatio = 2; + } + + // + if (minAllowedRiskInPoint < 10) + { + minAllowedRiskInPoint = 10; + } + } + // ulong ExtractPositionIDFromButtonName(string name) { diff --git a/Experts/x-saherelm.backtester.ea.mq5 b/Experts/x-saherelm.backtester.ea.mq5 index c8f2d242..2c66bbac 100644 --- a/Experts/x-saherelm.backtester.ea.mq5 +++ b/Experts/x-saherelm.backtester.ea.mq5 @@ -121,6 +121,14 @@ int OnInit() eaExpert.AddOnForceClosePositionEventHandler(OnPositionForceClosed); eaExpert.AddOnPartialClosePositionEventHandler(OnPositionPartialClosed); + // + // Configure Other Requirements ... + // eaExpert.volume = 0; + // eaExpert.riskInPoint = 0; + // eaExpert.allowedTPSLStep = 0; + // eaExpert.riskToRewardRatio = 0; + // eaExpert.minAllowedRiskInPoint = 0; + // // Try to Initialize eaExpert ... bool isInited = eaExpert.HandleOnInit(); diff --git a/Experts/x-saherelm.xfima.backtester.ea.mq5 b/Experts/x-saherelm.xfima.backtester.ea.mq5 index 18cb7d97..8fcc3d6f 100644 --- a/Experts/x-saherelm.xfima.backtester.ea.mq5 +++ b/Experts/x-saherelm.xfima.backtester.ea.mq5 @@ -50,6 +50,64 @@ input bool eaMailAlerts = false; // Mail Alerts input bool eaPushAlerts = false; // Push Alerts input bool eaTerminalAlerts = false; // Terminal Alerts +// +// Indicator Inputs ... +// +input group "Calculation"; + +// +// Short ... +input ENUM_X_PERIOD_METHOD scMethod = X_PERIOD_AUTO; // How to Find Short Period +input ENUM_TIMEFRAMES scPeriod = NULL; // Short Period + +// +// Medium ... +input ENUM_X_PERIOD_METHOD mcMethod = X_PERIOD_AUTO; // How to Find Medium Period +input ENUM_TIMEFRAMES mcPeriod = NULL; // Medium Period + +// +// Long ... +input ENUM_X_PERIOD_METHOD lcMethod = X_PERIOD_AUTO; // How to Find Long Period +input ENUM_TIMEFRAMES lcPeriod = NULL; // Long Period + +// +// Hind ... +input ENUM_X_PERIOD_METHOD hcMethod = X_PERIOD_AUTO; // How to Find Hind Period +input ENUM_TIMEFRAMES hcPeriod = NULL; // Hind Period + +// +// PV ... +input ENUM_SERIESMODE upperMode = MODE_HIGH; // Peak Method +input ENUM_SERIESMODE lowerMode = MODE_LOW; // Vale Method + +// +// Others ... +input ENUM_X_FIBO_LEVELS upperZoneLevel = X_FIBO_LEVEL_618; // Upper Zone Level +input ENUM_X_FIBO_LEVELS lowerZoneLevel = X_FIBO_LEVEL_382; // Lower Zone Level +input double sarStep = 0.02; // SAR Step +input double sarMax = 0.2; // SAR Maximum +input ENUM_MA_METHOD maMethod = MODE_EMA; // MA Method +input ENUM_APPLIED_PRICE maAppliedTo = PRICE_CLOSE; // MA Applied To +input int maFastLength = 7; // Fast MA Length +input int maSlowLength = 20; // Slow MA Length + +// +// Presentation ... +input group "Presentation"; +input bool showPV = true; // Show PV +input bool showSAR = true; // Show Sar +input bool showMAFast = true; // Show MA Fast +input bool showMASlow = true; // Show MA Slow +input bool showFiboZone = false; // Show Fibo Zone + +// +input int startCalculationForLastBars = 1500; // Calculate Last n Bars + +// +input int sarArrowCode = 159; // Parabolic Sar Arrow Code +input int peakArrowCode = 159; // Peaks Arrow Code +input int valeArrowCode = 159; // Vales Arrow Code + // // Define Local Variables ... @@ -57,6 +115,9 @@ input bool eaTerminalAlerts = false; // Terminal Alerts string eaLogTag; // EA Log Prefix ... XCBackTesterEA *eaExpert; // EA Expert ... +// +int eaHandler = INVALID_HANDLE; // Indicator Handler ... + // // Define Indicators Here ... @@ -125,6 +186,14 @@ int OnInit() eaExpert.AddOnForceClosePositionEventHandler(OnPositionForceClosed); eaExpert.AddOnPartialClosePositionEventHandler(OnPositionPartialClosed); + // + // Configure Other Requirements ... + eaExpert.volume = 0.01; + eaExpert.riskInPoint = 200; + eaExpert.allowedTPSLStep = 10; + eaExpert.riskToRewardRatio = 2; + eaExpert.minAllowedRiskInPoint = 20; + // // Try to Initialize eaExpert ... bool isInited = eaExpert.HandleOnInit(); @@ -135,6 +204,51 @@ int OnInit() return INIT_FAILED; } + // + // Initial Indicator Handler ... + eaHandler = iCustom( + _Symbol, + _Period, + "x-saherelm.xom1", + "", // Calculation ... + scMethod, + scPeriod, + mcMethod, + mcPeriod, + lcMethod, + lcPeriod, + hcMethod, + hcPeriod, + upperMode, + lowerMode, + upperZoneLevel, + lowerZoneLevel, + sarStep, + sarMax, + maMethod, + maAppliedTo, + maFastLength, + maSlowLength, + "", // Presentation ... + showPV, + showSAR, + showMAFast, + showMASlow, + showFiboZone, + startCalculationForLastBars, + sarArrowCode, + peakArrowCode, + valeArrowCode + // + ); + isInited = eaHandler != INVALID_HANDLE; + if (!isInited) + { + // + Print(ShortName, ": Initialization Failed ..."); + return INIT_FAILED; + } + // Print(ShortName, ": Initialized Successfully ..."); return INIT_SUCCEEDED; @@ -160,6 +274,10 @@ void OnDeinit(const int reason) // Destroy Timer ... eaExpert.HandleOnDeInit(); + // + // De Init Indicator ... + IndicatorRelease(eaHandler); + // delete eaExpert; ZeroMemory(eaExpert); @@ -218,7 +336,25 @@ bool ValidateInputs() bool isCommonValid = ( // eaSlippage > 0 && - eaMagicNumber > 0 + eaMagicNumber > 0 && + // + // Indicator Inputs ... + // + // MA ... + maFastLength >= 2 && + maSlowLength >= 2 && + maSlowLength > maFastLength && + // + // SAR ... + sarMax > 0 && + sarStep > 0 && + sarMax > sarStep && + // + // CYCLES ... + (IsValid(scMethod, scPeriod) && + IsValid(mcMethod, mcPeriod) && + IsValid(lcMethod, lcPeriod) && + IsValid(hcMethod, hcPeriod)) // ); if (!isCommonValid) diff --git a/Libraries/x-saherelm.common.extensions.lib.mq5 b/Libraries/x-saherelm.common.extensions.lib.mq5 index f8be0216..b92136b9 100644 --- a/Libraries/x-saherelm.common.extensions.lib.mq5 +++ b/Libraries/x-saherelm.common.extensions.lib.mq5 @@ -860,6 +860,27 @@ double GetXSpread( return GetSpread(mSymbol); } +/** + * Get SPecified Symbols Volume Step ... + * + * @param mSymbol: string ... + * + * @return ( double ) + */ +double GetVolumeStep( + string mSymbol = NULL // +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double result = SymbolInfoDouble(mSymbol, SYMBOL_VOLUME_STEP); + + // + return result; +} + /** * Get Point Price ... * @@ -3904,7 +3925,8 @@ template void Clean(T &buffer[]) { // - if (!HasChild(buffer)) { + if (!HasChild(buffer)) + { return; } diff --git a/Libraries/x-saherelm.x-trade.lib.mq5 b/Libraries/x-saherelm.x-trade.lib.mq5 index 4667e0fa..fe622816 100644 --- a/Libraries/x-saherelm.x-trade.lib.mq5 +++ b/Libraries/x-saherelm.x-trade.lib.mq5 @@ -1224,6 +1224,19 @@ struct XPosition return result; } + // + double GetRiskInPoint() + { + // + double result = 0; + + // + result = GetRisk() / GetPoints(); + + // + return result; + } + // // Find Reward ... double GetReward()