From ab6ddf0b43c35cdf2f9ac2527a9b195296c069fc Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Sun, 13 Apr 2025 22:16:17 +0330 Subject: [PATCH] last ... --- Classes/x-saherelm.x-volume.class.mq5 | 792 ++++++++++++++++++ Experts/x-saherelm.xstrcci.ea.mq5 | 152 +++- Libraries/x-saherelm.x-trade.lib.mq5 | 27 + .../Classes/xstrcci.x-trade.manager.class.mq5 | 693 +++++++++++++++ XSTRCCI/Libraries/xstrcci.signaller.lib.mq5 | 43 +- XSTRCCI/Signals/xstrcci.signaller.class.mq5 | 116 ++- 6 files changed, 1768 insertions(+), 55 deletions(-) create mode 100644 Classes/x-saherelm.x-volume.class.mq5 create mode 100644 XSTRCCI/Classes/xstrcci.x-trade.manager.class.mq5 diff --git a/Classes/x-saherelm.x-volume.class.mq5 b/Classes/x-saherelm.x-volume.class.mq5 new file mode 100644 index 00000000..09720c36 --- /dev/null +++ b/Classes/x-saherelm.x-volume.class.mq5 @@ -0,0 +1,792 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XCVolume +// Description: provides all Requirements for Volume Managing ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Template Variables of Inputs for Using ... +// input group "Volume"; +// input ENUM_X_VOLUME_SELECT_TYPE eaVolumeSelect = X_VOLUME_STATIC; // Volume Applying Type +// input double eaStaticVoluem = X_MIN_VOLUME; // 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 = 0.0; // Constant Percent of Balance Per Trade +// input double eaConstantBalance = 0.0; // Constant Balance for Calculations +// XCVolume *eaVolume; +// eaVolume = new XCVolume(); +// bool result = eaVolume.Init( +// eaVolumeSelect, +// eaStaticVoluem, +// eaDynamicVolumeStepBalance, +// eaDynamicVolumeStepVolume, +// eaConstantRiskBalance, +// eaConstantPercent, +// eaConstantBalance // +// ); +// if (!result) { +// return INIT_FAILED; +// } + +// +// Imports ... +#include "../Classes/x-saherelm.x-account.class.mq5" +#include "../Libraries/x-saherelm.x-trade.lib.mq5" + +// +// Definitions ... +#define X_MIN_VOLUME 0.01 + +// +enum ENUM_X_VOLUME_SELECT_TYPE +{ + X_VOLUME_NONE, // None + X_VOLUME_STATIC, // Static Volume + X_VOLUME_CURRENT, // Current Balance + X_VOLUME_EQUITY, // Current Equity + X_VOLUME_CONSTANT // Constant Value +}; + +// +bool IsValid(ENUM_X_VOLUME_SELECT_TYPE value) +{ + // + bool result = false; + + // + result = value != X_VOLUME_NONE; + + // + return result; +} + +// +string ToString(ENUM_X_VOLUME_SELECT_TYPE value) +{ + // + string result = NULL; + + // + result = EnumToString(value); + + // + return result; +} + +// +// Implementation ... +class XCVolume : public XCBase +{ + // + // Public ... + public: + // + // Props ... + XCAccount *account; + + // + // Constructor ... + XCVolume() + { + // + account = new XCAccount(); + + // + Default(); + } + + // + // Deconstructor ... + ~XCVolume() + { + // + ZeroMemory(account); + } + + // + bool Init( + ENUM_X_VOLUME_SELECT_TYPE _SelectType, + double _StaticVolume, + double _DynamicVolumeStepBalance, + double _DynamicVolumeStepVolume, + double _ConstantRiskBalance, + double _ConstantPercent, + double _ConstantBalance // + ) + { + // + bool result = false; + + // + mVolumeType = _SelectType; + mStaticVolume = _StaticVolume; + mConstantPercent = _ConstantPercent; + mConstantBalance = _ConstantBalance; + mConstantRiskBalance = _ConstantRiskBalance; + mDynamicVolumeStepVolume = _DynamicVolumeStepVolume; + mDynamicVolumeStepBalance = _DynamicVolumeStepBalance; + + // + result = + // + CanUseStaticVolume() || + CanUseDynamicVolume() || + CanUseConstantRiskBalance() || + CanUseConstantBalancePercent() + // + ; + + // + return result; + } + + // + // Prperties ... + + /** + * Get Volume Calculating Method ... + * + * @return (ENUM_X_VOLUME_SELECT_TYPE) + */ + ENUM_X_VOLUME_SELECT_TYPE VolumeType() + { + return mVolumeType; + } + + /** + * Set Volume Calculating Method ... + * + * @param value: ENUM_X_VOLUME_SELECT_TYPE member ... + */ + void VolumeType(ENUM_X_VOLUME_SELECT_TYPE value) + { + mVolumeType = value; + } + + /** + * Get Static Volume ... + * + * @return ( double ) + */ + double StaticVolume() + { + return mStaticVolume; + } + + /** + * Set Static Volume ... + * + * @param value: double + */ + void StaticVolume(double value) + { + // + value = NormalizeDouble(value, 0.01, 1); + + // + mStaticVolume = value; + } + + /** + * Get Dynamic Volume Step Balance ... + * used to Calculate Final Lottage ... + * + * @return ( double ) + */ + double DynamicVolumeStepBalance() + { + return mDynamicVolumeStepBalance; + } + + /** + * Set Dynamic Volume Step Balance ... + * used to Calculate Final Lottage ... + * + * @param value: Argument 1 + */ + void DynamicVolumeStepBalance(double value) + { + // + value = NormalizeDouble(value, 0); + + // + mDynamicVolumeStepBalance = value; + } + + /** + * Get Dynamic Volume Step Volume ... + * used to Calculate Final Lottage ... + * how much increase Final Volume based oBalance Step ... + * + * @return ( double ) + */ + double DynamicVolumeStepVolume() + { + return mDynamicVolumeStepVolume; + } + + /** + * Get Dynamic Volume Step Volume ... + * used to Calculate Final Lottage ... + * how much increase Final Volume based oBalance Step ... + * + * @param value: double + */ + void DynamicVolumeStepVolume(double value) + { + // + value = NormalizeDouble(value, 0.01, 0.1); + + // + mDynamicVolumeStepVolume = value; + } + + /** + * Get Constant Balance Use for Dyamic Volume Calculation ... + * + * @return ( double ) + */ + double ConstantBalance() + { + return mConstantBalance; + } + + /** + * Set Constant Balance Use for Dyamic Volume Calculation ... + * + * @param value: Argument 1 + */ + void ConstantBalance(double value) + { + // + value = NormalizeDouble(value, 0); + + // + mConstantBalance = value; + } + + /** + * Get Constant Risk Value Based on Account Currency ... + * + * @return ( double ) + */ + double ConstantRiskBalance() + { + return mConstantRiskBalance; + } + + /** + * Get Constant Risk Value Based on Account Currency ... + * + * @param value: double + */ + void ConstantRiskBalance(double value) + { + // + value = NormalizeDouble(value, 0); + + // + mConstantRiskBalance = value; + } + + /** + * Get Constant Percent Based On Selected Balance ... + * + * @return ( double ) + */ + double ConstantPercent() + { + return mConstantPercent; + } + + /** + * Set Constant Percent Based On Selected Balance ... + * + * @param value: double ... + */ + void ConstantPercent(double value) + { + // + value = NormalizeDouble(value, 0, 100); + + // + mConstantPercent = value; + } + + // + // Tools ... + + /** + * Retrieve Balance based on Provided Volume Type ... + * + * @return ( double ) + */ + double GetBalance() + { + // + double result = 0; + + // + if (!IsValid(mVolumeType)) + { + return result; + } + + // + if (mConstantBalance > 0 && + mVolumeType == X_VOLUME_CONSTANT) + { + result = mConstantBalance; + } + else if (mVolumeType == X_VOLUME_CURRENT) + { + result = account.GetBalance(); + } + else if (mVolumeType == X_VOLUME_EQUITY) + { + result = account.GetEquity(); + } + + // + return result; + } + + /** + * Retrieve Balance based on Provided Volume Type ... + * + * @return ( double ) + */ + double GetBalance(ENUM_X_VOLUME_SELECT_TYPE type) + { + // + double result = 0; + + // + if (!IsValid(type)) + { + return result; + } + + // + if (mConstantBalance > 0 && + type == X_VOLUME_CONSTANT) + { + result = mConstantBalance; + } + else if (type == X_VOLUME_CURRENT) + { + result = account.GetBalance(); + } + else if (type == X_VOLUME_EQUITY) + { + result = account.GetEquity(); + } + + // + return result; + } + + /** + * Calculate Volume Based On Given Configuration ... + * + * @param symbol: string, Trading Symbol ... + * @param entry: double, Entry Price ... + * @param sl: double, Stop Loss Price ... + * + * @return ( double ) + */ + double CalculateVolume( + string symbol, + double entry, + double sl // + ) + { + // + double result = X_MIN_VOLUME; + + // + bool has = false; + + // + // Validate Args ... + has = + sl > 0 && + entry > 0 && + IsValid(symbol); + if (!has) + { + return result; + } + + // + // Retrieve Balance Type ... + double balance = GetBalance(); + double points = GetPoints(symbol); + double riskPrice = MathAbs(entry - sl); + double riskInPoints = riskPrice / points; + + // + has = CanUseStaticVolume(); + if (has) + { + result = mStaticVolume; + } + + // + has = CanUseDynamicVolume(); + if (has) + { + // + double multiplier = balance / mDynamicVolumeStepBalance; + if (multiplier < 0) + { + multiplier = 1; + } + + // + result = multiplier * mDynamicVolumeStepVolume; + } + + // + has = CanUseConstantRiskBalance(); + if (has) + { + // + result = account.CalculateVolume( + symbol, + mConstantRiskBalance, + riskInPoints // + ); + } + + // + has = CanUseConstantBalancePercent(); + if (has) + { + // + double riskAmountPerBalance = (mConstantPercent * balance) / 100; + + // + result = account.CalculateVolume( + symbol, + riskAmountPerBalance, + riskInPoints // + ); + } + + // + if (result < X_MIN_VOLUME) + { + result = X_MIN_VOLUME; + } + + // + // Normalize Volume ... + result = NormalizeVolume(result, symbol); + + // + return result; + } + + /** + * Calculate Volume Based On Given Configuration ... + * + * @param signal: XSignal instance reference, provided required Data ... + * + * @return ( double ) + */ + double CalculateVolume(XSignal &signal) + { + // + double result = X_MIN_VOLUME; + + // + if (!signal.IsValid()) + { + return result; + } + + // + result = CalculateVolume( + signal.symbol, + signal.entry, + signal.sl // + ); + + // + return result; + } + + /** + * Calculate Specified Percent of Selected Balance for Volume ... + * + * @param percent: double, percent of Balance Risking ... + * @param symbol: string, Trading Symbol ... + * @param entry: double, Entry Price ... + * @param sl: double Stop Loss Price ... + * + * @return ( double ) + */ + double CalculateVolume( + ENUM_X_VOLUME_SELECT_TYPE selectType, + double percent, + string symbol, + double entry, + double sl // + ) + { + // + double result = X_MIN_VOLUME; + + // + bool has = false; + + // + // Validate Args ... + has = + sl > 0 && + entry > 0 && + percent > 0 && + IsValid(symbol) && + IsValid(selectType) && + (selectType == X_VOLUME_EQUITY || + selectType == X_VOLUME_CURRENT); + if (!has) + { + return result; + } + + // + // Retrieve Balance Type ... + double points = GetPoints(symbol); + double riskPrice = MathAbs(entry - sl); + double balance = GetBalance(selectType); + double riskInPoints = riskPrice / points; + + // + double riskAmountPerBalance = (percent * balance) / 100; + + // + result = account.CalculateVolume( + symbol, + riskAmountPerBalance, + riskInPoints // + ); + + // + return result; + } + + // + // Protected ... + protected: + // + // Tools ... + + /** + * Set Default Props ... + */ + void Default() + { + // + VolumeType(X_VOLUME_STATIC); + StaticVolume(0.01); + + // + ConstantBalance(0); + ConstantPercent(0); + ConstantRiskBalance(0); + + // + DynamicVolumeStepBalance(0); + DynamicVolumeStepVolume(0.01); + } + + /** + * Check Configuration is Valid For Static Volume ... + * + * @return ( bool ) + */ + bool CanUseStaticVolume() + { + // + bool result = false; + + // + result = IsValid(mVolumeType); + if (!result) + { + return result; + } + + // + // Static Volume ... + result = + // + mVolumeType == X_VOLUME_STATIC && + mStaticVolume > 0 && + // + mDynamicVolumeStepBalance == 0 && + // + mConstantBalance == 0 && + mConstantPercent == 0 && + mConstantRiskBalance == 0 + // + ; + + // + return result; + } + + /** + * Check Configuration is Valid For Dynamic Volume ... + * + * @return ( bool ) + */ + bool CanUseDynamicVolume() + { + // + bool result = false; + + // + result = IsValid(mVolumeType); + if (!result) + { + return result; + } + + // + result = + // + (mVolumeType == X_VOLUME_CURRENT || + mVolumeType == X_VOLUME_EQUITY || + (mVolumeType == X_VOLUME_CONSTANT && + mConstantBalance > 0)) && + // + mDynamicVolumeStepBalance > 0 && + mDynamicVolumeStepVolume > 0 && + // + mStaticVolume == 0 && + mConstantPercent == 0 && + mConstantRiskBalance == 0 + // + ; + + // + return result; + } + + /** + * Check Configuration is Valid For Constant Risk Balance ... + * + * @return ( bool ) + */ + bool CanUseConstantRiskBalance() + { + // + bool result = false; + + // + result = IsValid(mVolumeType); + if (!result) + { + return result; + } + + // + result = + // + (mVolumeType == X_VOLUME_CURRENT || + mVolumeType == X_VOLUME_EQUITY || + (mVolumeType == X_VOLUME_CONSTANT && + mConstantBalance > 0)) && + // + mConstantRiskBalance > 0 && + // + mStaticVolume == 0 && + mConstantPercent == 0 && + mDynamicVolumeStepBalance == 0 + // + ; + + // + return result; + } + + /** + * Check Configuration is Valid For Constant Risk Percent ... + * + * @return ( bool ) + */ + bool CanUseConstantBalancePercent() + { + // + bool result = false; + + // + result = IsValid(mVolumeType); + if (!result) + { + return result; + } + + // + result = + // + (mVolumeType == X_VOLUME_CURRENT || + mVolumeType == X_VOLUME_EQUITY || + (mVolumeType == X_VOLUME_CONSTANT && + mConstantBalance > 0)) && + // + mConstantPercent > 0 && + // + mStaticVolume == 0 && + mConstantRiskBalance == 0 && + mDynamicVolumeStepBalance == 0 + // + ; + + // + return result; + } + + // + // Private ... + private: + // + // Props ... + + // + ENUM_X_VOLUME_SELECT_TYPE mVolumeType; // Balance Type ... + + // + // Static Volume ... + double mStaticVolume; // Static Volume ... + + // + double mDynamicVolumeStepBalance; // Step of Balance ... + double mDynamicVolumeStepVolume; // Step of Volume ... + + // + double mConstantBalance; // Constant Balance .... + double mConstantRiskBalance; // Constant Risk Balance ... + double mConstantPercent; // Constant Percent of Balance ... +}; + +// \ No newline at end of file diff --git a/Experts/x-saherelm.xstrcci.ea.mq5 b/Experts/x-saherelm.xstrcci.ea.mq5 index a7050f92..90c15f8f 100644 --- a/Experts/x-saherelm.xstrcci.ea.mq5 +++ b/Experts/x-saherelm.xstrcci.ea.mq5 @@ -22,6 +22,8 @@ // Imports ... #include "../Classes/x-saherelm.x-alert.class.mq5" #include "../Classes/x-saherelm.x-trade.class.mq5" +#include "../Classes/x-saherelm.x-volume.class.mq5" +#include "../XSTRCCI/Classes/xstrcci.x-trade.manager.class.mq5" #include "../XSTRCCI/Signals/xstrcci.signaller.class.mq5" // @@ -37,6 +39,17 @@ input long eaMagicNumber = 78692110; // Magic Number input int eaSlippage = 10; // Slippgae input string eaLogSuffix = ""; // Log Suffix +// +// Volume ... +input group "Volume"; +input ENUM_X_VOLUME_SELECT_TYPE eaVolumeSelect = X_VOLUME_EQUITY; // 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 = 0.5; // Constant Percent of Balance Per Trade +input double eaConstantBalance = 0.0; // Constant Balance for Calculations + // // Alert ... // Here we Provider All Requirements for @@ -60,6 +73,8 @@ input bool eaReportNewHours = false; // Report New Hours // Variables, Instances ... XCAlert *eaAlert; XCTrade *eaTrade; +XCVolume *eaVolume; +XCXSTRCCITradeManager *eaTradeManager; // XSignal eaSignal; @@ -100,6 +115,13 @@ int OnInit() // Initial Requirements ... InitRequirements(); + // + // Initialize Volume Manger ... + if (!InitVolume()) + { + return INIT_FAILED; + } + // // Init Succeed ... return INIT_SUCCEEDED; @@ -122,7 +144,17 @@ void OnDeinit(const int reason) // REASON_CLOSE 9 Terminal closed // - // Destroy Timer ... + ZeroMemory(eaAlert); + ZeroMemory(eaTrade); + ZeroMemory(eaVolume); + ZeroMemory(eaSignaller); + + // + eaSignal.Clean(); + eaConditions.Clean(); + + // + DestroyTimer(); } // @@ -134,18 +166,16 @@ void OnTick() int count = 0; bool has = false; + // + // Handle Position Management / Protections ... + eaTradeManager.Manage(); + // eaSignal.Clean(); eaConditions.Clean(); // - double sl = 0; - double tp = 0; double r2r = 5; - double risk = 0; - double entry = 0; - double reward = 0; - double volume = 0.01; string provider = "XSTRCCI"; ENUM_POSITION_TYPE type = POSITION_TYPE_BUY; ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET; @@ -154,9 +184,6 @@ void OnTick() bool hasLong = false; bool hasShort = false; - // - double selectedSL = 0; - // // Start Calculations ... @@ -239,6 +266,23 @@ void OnTick() return; } + // + // Setting Time to Conditions ... + eaConditions.time = cTime; + has = ToPositionType( + type, + eaConditions.type // + ); + if (!has) + { + // + eaSignal.Clean(); + eaConditions.Clean(); + + // + return; + } + // // Checking Trigger Direction ... hasLong = eaConditions.HasBullishSignal(); @@ -248,23 +292,29 @@ void OnTick() if (!has) { // + eaSignal.Clean(); eaConditions.Clean(); + + // return; } // // Preparing Signal ... // - eaSignal.sl = sl; - eaSignal.tp = tp; - eaSignal.type = type; eaSignal.mode = mode; - eaSignal.entry = entry; - eaSignal.volume = volume; - eaSignal.symbol = symbol; - eaSignal.period = period; + eaSignal.type = type; + eaSignal.entry = GetEntry( + eaConditions.symbol, + eaConditions.dir // + ); eaSignal.provider = provider; - eaSignal.time = TimeCurrent(); + eaSignal.sl = eaConditions.sl; + eaSignal.tp = eaConditions.tp; + eaSignal.volume = X_MIN_VOLUME; + eaSignal.time = eaConditions.time; + eaSignal.symbol = eaConditions.symbol; + eaSignal.period = eaConditions.period; // Copy( @@ -282,6 +332,15 @@ void OnTick() return; } + // + // Handle Volume Management ... + double iVolume = eaVolume.CalculateVolume(eaSignal); + if (iVolume > X_MIN_VOLUME && + iVolume != eaSignal.volume) + { + eaSignal.volume = iVolume; + } + // // Draw Signal ... @@ -289,7 +348,16 @@ void OnTick() // Execute Signal ... // - Print("Execute Signal ..."); + has =eaTradeManager.Execute( + eaSignal, + eaConditions // + ); + if (has) + { + // + // Do What we Want on Successfully Execution Signal ... + Print("Signal Executed ..."); + } // eaSignal.Clean(); @@ -329,6 +397,7 @@ void OnChartEvent( */ void OnStopLossTriggered(const XDeal &deal) { + eaTradeManager.HandleSL(deal); } /** @@ -338,6 +407,7 @@ void OnStopLossTriggered(const XDeal &deal) */ void OnTakeProfitTriggered(const XDeal &deal) { + eaTradeManager.HandleTP(deal); } /** @@ -353,6 +423,7 @@ void OnPositionForceClosed( const string comment // ) { + eaTradeManager.HandleForceClose(position); } /** @@ -464,6 +535,34 @@ void DestroyTimer() // EventKillTimer(); } +/** + * Initial Volume Manager Class Based on Given Configuration ... + * + * @return ( bool ) + */ +bool InitVolume() +{ + // + bool result = false; + + // + eaVolume = new XCVolume(); + + // + result = eaVolume.Init( + eaVolumeSelect, + eaStaticVoluem, + eaDynamicVolumeStepBalance, + eaDynamicVolumeStepVolume, + eaConstantRiskBalance, + eaConstantPercent, + eaConstantBalance // + ); + + // + return result; +} + /** * Initial Requirements of EA ... * @@ -498,6 +597,21 @@ void InitRequirements() eaMaxAllowedPositions, eaMaxAllowedDrawdownFactor // ); + eaTrade.AddOnStopLossEventHandler(OnStopLossTriggered); + eaTrade.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); + eaTrade.AddOnForceClosePositionEventHandler(OnPositionForceClosed); + + // + // EA Trae Manager ... + eaTradeManager = new XCXSTRCCITradeManager( + eaTrade // + ); + eaTradeManager.SetAlertEnableAlerts(eaEnableAlerts); + eaTradeManager.SetAlertPrefix(eaTag); + eaTradeManager.SetAlertLogAlerts(eaLogAlerts); + eaTradeManager.SetAlertMailAlerts(eaMailAlerts); + eaTradeManager.SetAlertPushAlerts(eaPushAlerts); + eaTradeManager.SetAlertTerminalAlerts(eaTerminalAlerts); // // EA Signaller ... diff --git a/Libraries/x-saherelm.x-trade.lib.mq5 b/Libraries/x-saherelm.x-trade.lib.mq5 index 0b6b1078..2a708c25 100644 --- a/Libraries/x-saherelm.x-trade.lib.mq5 +++ b/Libraries/x-saherelm.x-trade.lib.mq5 @@ -1980,6 +1980,33 @@ struct XSignal // return result; } + + // + bool IsSameAs(XSignal &item) { + // + bool result = false; + + // + result = + // + IsValid() && + item.IsValid() && + // + tp == item.tp && + sl == item.sl && + mode == item.mode && + time == item.time && + type == item.type && + entry == item.entry && + symbol == item.symbol && + period == item.period && + provider == item.provider + // + ; + + // + return result; + } }; // diff --git a/XSTRCCI/Classes/xstrcci.x-trade.manager.class.mq5 b/XSTRCCI/Classes/xstrcci.x-trade.manager.class.mq5 new file mode 100644 index 00000000..c1cc44d6 --- /dev/null +++ b/XSTRCCI/Classes/xstrcci.x-trade.manager.class.mq5 @@ -0,0 +1,693 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XCXSTRCCITradeManager +// Description: provides all Requirements for Managing Trades ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../../Classes/x-saherelm.x-alert.class.mq5" +#include "../../Classes/x-saherelm.x-poi.drawer.class.mq5" +#include "../../Classes/x-saherelm.x-trade.class.mq5" +#include "../Libraries/xstrcci.signaller.lib.mq5" + +// +// Definitions ... + +// +enum ENUM_XSTRCCI_TRADE_FINALIZATION +{ + XSTRCCI_TRADE_FINAL_NONE, + XSTRCCI_TRADE_FINAL_TP, + XSTRCCI_TRADE_FINAL_SL, + XSTRCCI_TRADE_FINAL_CLOSE_IN_PROFIT, + XSTRCCI_TRADE_FINAL_CLOSE_IN_LOSE, +}; + +// +struct XSTRCCITrade +{ + // + // Props ... + double swap; + double profit; + XSignal signal; + ulong positionID; + double commission; + XSTRCCIStrategyConditions conditions; + ENUM_XSTRCCI_TRADE_FINALIZATION finalize; + + // + // Constructor ... + XSTRCCITrade() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup Model ... + */ + void Clean() + { + // + swap = 0; + profit = 0; + signal.Clean(); + commission = 0; + positionID = 0; + conditions.Clean(); + finalize = XSTRCCI_TRADE_FINAL_NONE; + + // + ZeroMemory(this); + } + + /** + * Check Has Signal ... + * + * @return ( bool ) + */ + bool HasSignal() + { + // + bool result = false; + + // + result = signal.IsValid(); + + // + return result; + } + + /** + * Check Signal Executed or Not ... + * + * @return ( bool ) + */ + bool IsExecuted() + { + // + bool result = false; + + // + result = positionID > 0; + + // + return result; + } + + /** + * Check a Trade is Finalized or not ... + * + * @return ( bool ) + */ + bool IsFinalized() + { + // + bool result = false; + + // + result = HasSignal() && + IsExecuted() && + finalize != XSTRCCI_TRADE_FINAL_NONE; + + // + return result; + } +}; + +// +// Implementations ... +class XCXSTRCCITradeManager : public XCBaseAlert +{ + // + // Public ... + public: + // + // Props ... + XCTrade *trader; + bool drawSignal; + XCPOIDrawer *drawer; + + // + // Constructors ... + XCXSTRCCITradeManager(XCTrade *&_trader) + { + // + trader = _trader; + drawSignal = true; + drawer = new XCPOIDrawer(); + } + + // + // De Constructors ... + ~XCXSTRCCITradeManager() + { + // + ZeroMemory(trader); + ZeroMemory(drawer); + } + + // + // Tools ... + + /** + * Do All Position Managing Senaros ... + */ + void Manage() + { + // + bool has = HasChild(trades); + if (!has) + { + return; + } + + // + int count = ArraySize(trades); + for (int i = 0; i < count; i++) + { + // + has = trades[i].IsExecuted() && + !trades[i].IsFinalized(); + if (!has) + { + continue; + } + + // + XPosition iPosition; + has = trader.GetPosition( + trades[i].positionID, + iPosition // + ); + if (!has) + { + continue; + } + + // + // Update Trade Data ... + trades[i].swap = iPosition.swap; + trades[i].profit = iPosition.profit; + } + + // + // After Update All Trades we can Do Protection ... + Protect(); + } + + /** + * Do All Position Protection Here ... + */ + void Protect() + { + // + bool has = HasChild(trades); + if (!has) + { + return; + } + + // + XPosition ownPosition[]; + XPosition ownLongPosition[]; + XPosition ownShortPosition[]; + + // + int count = ArraySize(trades); + for (int i = 0; i < count; i++) + { + // + has = + trades[i].IsExecuted() && + !trades[i].IsFinalized(); + if (!has) + { + continue; + } + + // + XPosition iPosition; + has = trader.GetPosition( + trades[i].positionID, + iPosition // + ); + if (!has) + { + continue; + } + + // + AddRef( + iPosition, + ownPosition // + ); + + // + if (IsLong(iPosition.type)) + { + // + AddRef( + iPosition, + ownLongPosition // + ); + } + else + { + // + AddRef( + iPosition, + ownShortPosition // + ); + } + } + + // + has = HasChild(ownPosition); + if (!has) + { + // + Clean(ownPosition); + Clean(ownLongPosition); + Clean(ownShortPosition); + + // + return; + } + + // + double swapSum = 0; + double profitSum = 0; + double commissionSum = 0; + + // + // Calculate Required Data On Collection ... + count = ArraySize(ownPosition); + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = ownPosition[i]; + + // + swapSum += iPosition.swap; + profitSum += iPosition.profit; + commissionSum += iPosition.commission; + } + + // + // Do Collection Protectiong ... + // TODO: Implement this ... + + // + // Do Signle Protections ... + for (int i = 0; i < count; i++) + { + // + // Select Position ... + XPosition iPosition = ownPosition[i]; + + // + // Handle RF ... + } + } + + /** + * Execute Specified Signal ... + * + * @param signal: XSignal instance reference ... + * @param conditions: XSTRCCIStrategyConditions instance reference ... + * + * @return ( bool ) + */ + bool Execute( + XSignal &signal, + XSTRCCIStrategyConditions &conditions // + ) + { + // + bool result = false; + + // + result = signal.IsValid(); + if (!result) + { + return result; + } + + // + int idx = -1; + bool isExists = HasTrade( + idx, + signal // + ); + result = !isExists; + if (!result) + { + return result; + } + + // + ENUM_X_SIGNAL_EXECUTION_RESULT executionResult; + result = trader.ExecuteSignal( + signal, + executionResult // + ); + + // + // Alert Signal Execution ... + string executionMessage = ToString(executionResult); + Alert(executionMessage); + + // + if (result) + { + // + if (drawSignal) + { + // + XCSignalObject *iObj; + isExists = drawer.DrawSignal( + signal, + iObj // + ); + + // + if (isExists) + { + // + mObjects.Add(iObj); + ZeroMemory(iObj); + } + } + + // + XSTRCCITrade iTrade; + + // + ulong positionID = trader.GetLastOpenPositionTicket(); + double commission = trader.GetPositionCommission(positionID); + + // + iTrade.signal = signal; + iTrade.conditions = conditions; + iTrade.positionID = positionID; + iTrade.commission = commission; + + // + AddRef( + iTrade, + trades // + ); + } + + // + return result; + } + + /** + * Handle Position Take Profit ... + * + * @param deal: XDeal instance reference ... + */ + void HandleTP(const XDeal &deal) + { + // + // Check Ticket Exists or not ... + int idx = -1; + bool isExists = HasTrade( + idx, + deal.positionId // + ); + if (!isExists) + { + return; + } + + // + // Apply Required Data ... + trades[idx].swap = deal.swap; + trades[idx].profit = deal.profit; + trades[idx].commission = deal.commission; + trades[idx].finalize = XSTRCCI_TRADE_FINAL_TP; + + // + tpCount++; + managedTPCount++; + + // + } + + /** + * Handle Position Stop Loss ... + * + * @param deal: XDeal instance reference ... + */ + void HandleSL(const XDeal &deal) + { + // + // Check Ticket Exists or not ... + int idx = -1; + bool isExists = HasTrade( + idx, + deal.positionId // + ); + if (!isExists) + { + return; + } + + // + // Apply Required Data ... + trades[idx].swap = deal.swap; + trades[idx].profit = deal.profit; + trades[idx].commission = deal.commission; + trades[idx].finalize = XSTRCCI_TRADE_FINAL_SL; + + // + slCount++; + managedSLCount++; + + // + } + + /** + * Handle Position Force Close ... + * + * @param deal: XDeal instance reference ... + */ + void HandleForceClose(const XPosition &position) + { + // + // Check Ticket Exists or not ... + int idx = -1; + bool isExists = HasTrade( + idx, + position.ticket // + ); + if (!isExists) + { + return; + } + + // + bool isInProfit = position.profit > 0; + + // + // Apply Required Data ... + trades[idx].swap = position.swap; + trades[idx].profit = position.profit; + trades[idx].commission = position.commission; + trades[idx].finalize = isInProfit + ? XSTRCCI_TRADE_FINAL_CLOSE_IN_PROFIT + : XSTRCCI_TRADE_FINAL_CLOSE_IN_LOSE; + + // + if (isInProfit) + { + // + tpCount++; + managedTPCount++; + } + else + { + // + slCount++; + managedSLCount++; + } + + // + } + + // + // TODO: Complete this ... + void HandleGuard() + { + } + + /** + * Find Executed Trade by Providing Position Ticket ... + * + * @param index: int reference, holding founded item index ... + * @param ticket: ulong, Specified Position Ticket ... + * + * @return ( bool ) + */ + bool HasTrade( + int &index, + ulong ticket // + ) + { + // + bool result = false; + + // + index = -1; + + // + result = + ticket > 0 && + HasChild(trades); + if (!result) + { + return result; + } + + // + int count = ArraySize(trades); + for (int i = 0; i < count; i++) + { + // + XSTRCCITrade iTrade = trades[i]; + + // + result = + iTrade.HasSignal() && + iTrade.IsExecuted() && + iTrade.positionID == ticket; + if (result) + { + // + index = i; + + // + iTrade.Clean(); + break; + } + + // + iTrade.Clean(); + } + + // + result = IsValidIndex(index); + + // + return result; + } + + /** + * Find Trade Item By Signal ... + * + * @param index: int reference, holding founded item index ... + * + * @return ( bool ) + */ + bool HasTrade( + int &index, + XSignal &signal // + ) + { + // + bool result = false; + + // + index = -1; + + // + result = + signal.IsValid() && + HasChild(trades); + if (!result) + { + return result; + } + + // + int count = ArraySize(trades); + for (int i = 0; i < count; i++) + { + // + XSTRCCITrade iTrade = trades[i]; + + // + result = + iTrade.HasSignal() && + iTrade.signal.IsSameAs(signal); + if (result) + { + // + index = i; + + // + iTrade.Clean(); + break; + } + + // + iTrade.Clean(); + } + + // + result = IsValidIndex(index); + + // + return result; + } + + // + // Protected ... + protected: + // + // Tools ... + + // + // Private ... + private: + // + // Props ... + + // + int slCount; + int tpCount; + + // + int managedSLCount; + int managedTPCount; + + // + CArrayObj mObjects; + + // + XSTRCCITrade trades[]; +}; + +// diff --git a/XSTRCCI/Libraries/xstrcci.signaller.lib.mq5 b/XSTRCCI/Libraries/xstrcci.signaller.lib.mq5 index e23a7b1b..0d7500a0 100644 --- a/XSTRCCI/Libraries/xstrcci.signaller.lib.mq5 +++ b/XSTRCCI/Libraries/xstrcci.signaller.lib.mq5 @@ -66,7 +66,6 @@ struct XSTRCCIStrategyConditions double tp; double pivot; double point; - double sls[]; string provider; double targets[]; @@ -79,7 +78,7 @@ struct XSTRCCIStrategyConditions XBoxZone signalBox; ENUM_X_DIRECTION dir; ENUM_X_POSITION_TYPES type; - ENUM_X_DIRECTION signalDir; + XSTRCCIConditions conditions; // // Constructor ... @@ -113,16 +112,15 @@ struct XSTRCCIStrategyConditions triggerTime = NULL; // - Clean(sls); Clean(targets); // signalBox.Clean(); + conditions.Clean(); // dir = X_DIRECTION_NONE; type = X_POSITION_TYPE_NONE; - signalDir = X_DIRECTION_NONE; // } @@ -164,7 +162,7 @@ struct XSTRCCIStrategyConditions (sl > 0 || tp > 0) && IsValid() && - HasDirection(signalDir); + HasDirection(dir); if (!result) { return result; @@ -172,7 +170,7 @@ struct XSTRCCIStrategyConditions // result = - IsBullish(signalDir); + IsBullish(dir); // return result; @@ -193,7 +191,7 @@ struct XSTRCCIStrategyConditions (sl > 0 || tp > 0) && IsValid() && - HasDirection(signalDir); + HasDirection(dir); if (!result) { return result; @@ -201,7 +199,7 @@ struct XSTRCCIStrategyConditions // result = - IsBearish(signalDir); + IsBearish(dir); // return result; @@ -421,6 +419,7 @@ int AddGuard( // bool DetectXSTRCCIConditions( + XSTRCCIConditions &conditions, XBoxZone &box, ENUM_X_DIRECTION &dir, XCXSTRCCIHelper *helper, @@ -433,6 +432,7 @@ bool DetectXSTRCCIConditions( // box.Clean(); + conditions.Clean(); dir = X_DIRECTION_NONE; // @@ -447,7 +447,6 @@ bool DetectXSTRCCIConditions( ENUM_TIMEFRAMES period = helper.GetPeriod(); // - XSTRCCIConditions conditions; result = helper.GetConditions( conditions, barIndex, @@ -505,6 +504,10 @@ bool DetectXSTRCCIConditions( p3Bar.Clean(); p4Bar.Clean(); + // + box.Clean(); + conditions.Clean(); + // return result; } @@ -750,17 +753,6 @@ bool DetectXSTRCCIConditions( // box.type = ToString(dir) + "_Signal_" + conditions.symbol + "_" + ToString(conditions.period); - - // - XCBoxObject *iObj; - bool isCreated = helper.poiDrawer.DrawBox( - box, - iObj // - ); - if (isCreated) - { - Print("Signal Box ..."); - } } // @@ -770,6 +762,14 @@ bool DetectXSTRCCIConditions( // // Cleanup Resources ... + // + if (!result) + { + // + box.Clean(); + conditions.Clean(); + } + // zBar.Clean(); cBar.Clean(); @@ -778,9 +778,6 @@ bool DetectXSTRCCIConditions( p3Bar.Clean(); p4Bar.Clean(); - // - conditions.Clean(); - // return result; } diff --git a/XSTRCCI/Signals/xstrcci.signaller.class.mq5 b/XSTRCCI/Signals/xstrcci.signaller.class.mq5 index c285be76..295ebb57 100644 --- a/XSTRCCI/Signals/xstrcci.signaller.class.mq5 +++ b/XSTRCCI/Signals/xstrcci.signaller.class.mq5 @@ -37,8 +37,6 @@ class XCXSTRCCISignaller : XCBase // // Props ... bool useGuards; - double rfReward; - bool isPassedBoxes; XSTRCCIInputs inputs; XBarTracker barTraker; XCXSTRCCIHelper *helper; @@ -123,10 +121,6 @@ class XCXSTRCCISignaller : XCBase datetime cTime = TimeCurrent(); double points = GetPoints(symbol); - // - mConditions.symbol = symbol; - mConditions.period = period; - // XOHCL zBar; XOHCL cBar; @@ -160,11 +154,6 @@ class XCXSTRCCISignaller : XCBase // // Setup Conditions ... - double sls[]; - double sl = 0; - double pivot = 0; - double point = 0; - double targets[]; XBoxZone signalBox; bool hasSignalBox = false; ENUM_X_DIRECTION signalBoxDir = X_DIRECTION_NONE; @@ -173,7 +162,9 @@ class XCXSTRCCISignaller : XCBase // Checking Conditions ... // + XSTRCCIConditions conditions; hasSignalBox = DetectXSTRCCIConditions( + conditions, signalBox, signalBoxDir, helper, @@ -197,6 +188,103 @@ class XCXSTRCCISignaller : XCBase // // Do What we Want ... barTraker.Waits(); + + // + // Draw Signal Box ... + XCBoxObject *iObj; + bool isCreated = helper.poiDrawer.DrawBox( + signalBox, + iObj // + ); + if (isCreated) + { + // + mObjects.Add(iObj); + ZeroMemory(iObj); + + // + Print("Signal Box ..."); + } + + // + // Prepare Conditions ... + mConditions.symbol = symbol; + mConditions.period = period; + + // + double spread = GetSpread(symbol); + + // + double entry = + isBullish + ? signalBox.upper + : signalBox.lower; + + // + double sl = + isBullish + ? signalBox.lower + : signalBox.upper; + + // + double risk = + isBullish + ? entry - sl + : sl - entry; + risk += spread; + + // + double rewardTP = risk * tpReward; + + // + double tp = + isBullish + ? entry + rewardTP + : entry - rewardTP; + + // + // Filling ... + mConditions.sl = sl; + mConditions.tp = tp; + mConditions.pivot = + isBullish + ? sl + : entry; + mConditions.point = + isBullish + ? entry + : sl; + mConditions.dir = signalBoxDir; + mConditions.provider = "XSTRCCI"; + mConditions.signalBox = signalBox; + mConditions.setupTime = zBar.time; + mConditions.conditions = conditions; + + // + // Select RF Rewards ... + if (continuesRFTillTarget) + { + // + double rfReward = 1; + while (rfReward < tpReward) + { + // + double rewardRF = risk * rfReward; + double rfTP = + isBullish + ? entry + rewardRF + : entry - rewardRF; + + // + Add( + rfTP, + mConditions.targets // + ); + + // + rfReward++; + } + } } // @@ -208,6 +296,10 @@ class XCXSTRCCISignaller : XCBase pBar.Clean(); pPBar.Clean(); + // + signalBox.Clean(); + conditions.Clean(); + // return result; } @@ -410,9 +502,7 @@ class XCXSTRCCISignaller : XCBase void Init() { // - rfReward = 2; useGuards = false; - isPassedBoxes = false; continuesRFTillTarget = true; //