From 96bbe9263043f39865b9f3f0fc1fe4422ef3c981 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Sat, 8 Jun 2024 17:48:42 +0330 Subject: [PATCH] last works ... --- Classes/x-saherelm.x121.xea.class.mq5 | 1028 ++++++++++++++++- Classes/x-saherelm.xtrade.class.mq5 | 89 +- Experts/x-test.x121ea.mq5 | 48 +- Libraries/x-saherelm.common.lib.mq5 | 13 + Libraries/x-saherelm.xtrade.lib.mq5 | 88 ++ .../x-saherelm.x110.signaller.class.mq5 | 56 +- .../x-saherelm.x121.signaller.class.mq5 | 30 + .../x-saherelm.x786.signaller.class.mq5 | 34 +- Signallers/x-saherelm.x92.signaller.class.mq5 | 30 + 9 files changed, 1314 insertions(+), 102 deletions(-) diff --git a/Classes/x-saherelm.x121.xea.class.mq5 b/Classes/x-saherelm.x121.xea.class.mq5 index d5705567..41e0d02e 100644 --- a/Classes/x-saherelm.x121.xea.class.mq5 +++ b/Classes/x-saherelm.x121.xea.class.mq5 @@ -29,6 +29,986 @@ // Define On Signal Event Handler Type Specified for X5 ... typedef void (*TX121OnSignal)(X121ProviderDescriptor &descriptor); +// +// Position Protect Structure ... +struct XProtectedPosition +{ + // + ulong ticket; // Position Ticket + string symbol; // Position Symbol + string provider; // Position Signaller + ENUM_TIMEFRAMES period; // Position Time Frame + ENUM_POSITION_TYPE type; // Position Type + double volume; // Position Volume + double entry; // Position Entry + double sl; // Position Stop Loss + double tp; // Position Take Profit + datetime openAt; // Position Opening Time + + // + // Working Variables ... + double recoveryZoneStep; // Used Recovery Zone Step + int lastRecoveryLevel; // Last Recovery Level + double lastVolume; // Last Recovery Volume + ulong tickets[]; // Recovery Trades Tickets + + // + // Constructor ... + XProtectedPosition() + { + Clean(); + } + + // + // Tools ... + + // + // Initialized ... + bool Init( + double mRecoveryZoneStep, + XPosition &mPosition // + ) + { + // + bool result = false; + + // + // Validate Params ... + result = + // + mPosition.IsValid() && + mRecoveryZoneStep > 0 + // + ; + if (!result) + { + return result; + } + + // + Clean(); + + // + sl = mPosition.sl; + tp = mPosition.tp; + type = mPosition.type; + entry = mPosition.entry; + ticket = mPosition.ticket; + symbol = mPosition.symbol; + period = mPosition.period; + volume = mPosition.volume; + openAt = mPosition.openAt; + provider = mPosition.provider; + recoveryZoneStep = mRecoveryZoneStep; + + // + result = IsValid(); + + // + return result; + } + + // + // Cleanup ... + void Clean() + { + // + ticket = 0; + symbol = NULL; + period = NULL; + provider = NULL; + volume = 0; + entry = 0; + sl = 0; + tp = 0; + openAt = NULL; + lastRecoveryLevel = 0; + lastVolume = 0; + Clean(tickets); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + ticket > 0 && + volume > 0 && + entry > 0 && + tp > 0 && + sl > 0 && + IsSpecifiedValid(symbol) && + IsSpecifiedValid(provider) && + IsSpecifiedValid(period) + // + ; + + // + return result; + } + + // + // Check Protected Type ... + bool IsLong() + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + result = IsLong(this.type); + + // + return result; + } + + // + // Retrieve Tick Based on Protected ... + bool GetTick( + MqlTick &tick // + ) + { + // + bool result = false; + + // + // Validate ... + result = IsValid(); + if (!result) + { + return result; + } + + // + result = GetTick( + this.symbol, + tick // + ); + + // + return result; + } + + // + // Retrieve Current Exit Price based on Protected ... + double GetExit() + { + // + double result = GetExit( + this.symbol, + this.type // + ); + + // + return result; + } + + // + // Retrieve Current Entry Price based on Protected ... + double GetEntry() + { + // + double result = GetEntry( + this.symbol, + this.type // + ); + + // + return result; + } + + // + // Calculate Recovery Step Price ... + double GetRecoveryAreaPrice() + { + // + double result = 0; + + // + // Validate ... + if (!IsValid()) + { + return result; + } + + // + double stepPrice = PointToPrice( + recoveryZoneStep, + symbol // + ); + + // + bool isLong = IsLong(type); + + // + result = + isLong + ? entry - stepPrice + : entry + stepPrice; + + // + return result; + } + + // + // Check Protected Has Recovery or not ... + // it it's true ... fill signal by proper info ... + bool GetRecoverySignal( + XSignal &signal // Result ... + ) + { + // + bool result = false; + + // + signal.Clean(); + + // + // Validate ... + result = IsValid(); + if (!result) + { + return result; + } + + // + // Check Position is Reoverable or not ... + bool isLong = IsLong(); + double recoveryPrice = GetRecoveryAreaPrice(); + + // + int currRecoveryLevel = lastRecoveryLevel + 1; + + // + double mExit = GetExit(); + double mEntry = GetEntry(); + double recoveryDiff = MathAbs(mEntry - recoveryPrice); + + // + // First Check Opposite Direction ... + bool canOppositDirectionRecover = + // + // Check State for Opposit Recovery ... + lastRecoveryLevel % 2 == 0 && + // + (isLong + ? mExit < recoveryPrice + : mExit > recoveryPrice) + // + ; + + // + // Check Same Direction Recovery ... + bool canSameDirectionRecover = + // + // Since for Same Direction Recover we have to at leaset 1 Opposite Recovery ... + lastRecoveryLevel % 2 == 1 && + // + (isLong + ? mEntry >= entry + : mEntry <= entry) + // + ; + + // + // Check Protected Can Recoverable or not ... + result = + // + lastRecoveryLevel < 5 && + (canSameDirectionRecover || + canOppositDirectionRecover) + // + ; + if (!result) + { + return result; + } + + // + // Now we have to Prepare Signal based on Recovery Mode ... + + // + // Recovery Position Type ... + ENUM_POSITION_TYPE mType = + canSameDirectionRecover + ? this.type + : GetOpposit(this.type); + + // + bool isMLong = IsLong(mType); + + // + // Recovery Position Entry Price ... + mEntry = GetEntry( + this.symbol, + mType // + ); + + // + // SL and TP ... + double mTP = + canSameDirectionRecover + ? this.tp + : this.sl; + mTP = + isMLong + ? mTP + recoveryDiff + : mTP - recoveryDiff; + + // + double mSL = + canSameDirectionRecover + ? this.sl + : this.tp; + mSL = + isMLong + ? mSL - recoveryDiff + : mSL + recoveryDiff; + + // + // Volume ... + // For Volume Calculating we have to use Recovery Level ... + double mVolume = + lastVolume == 0 + ? volume * 3 + : lastVolume * 3; + + // + result = signal.Prepare( + this.symbol, + this.provider, + this.period, + mType, + X_ORDER_MODE_MARKET, + mEntry, + mVolume, + mSL, + mTP // + ); + + // + return result; + } +}; + +// +// a Position Protector Class ... +class XSCPositionProtector : public XSCBaseAlert +{ + // + // Public ... +public: + // + // Props ... + + // + // Protected Positions ... + XProtectedPosition protecteds[]; + + // + // Trader Class Instance ... + XSCTrade *mTrader; + + // + // Constructor ... + void XSCPositionProtector() + { + // + Clean(protecteds); + + // + SetRecoveryStepDivider(5); + SetRecoveryStepPeriod(PERIOD_D1); + } + + // + // Deconstructor ... + void ~XSCPositionProtector() + { + delete mTrader; + } + + // + // Setter(s) / Getter(s) ... + + // + void SetRecoveryStepPeriod(ENUM_TIMEFRAMES value) + { + this.recoveryStepPeriod = value; + } + + // + ENUM_TIMEFRAMES GetRecoveryStepPeriod() + { + return this.recoveryStepPeriod; + } + + // + void SetRecoveryStepDivider(int value) + { + // + if (value <= 3) + { + value = 3; + } + + // + this.recoveryStepDivider = value; + } + + // + int GetRecoveryStepDivider() + { + return this.recoveryStepDivider; + } + + // + void SetMinRequiredProfitPerTrade(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + this.minRequiredProfitPerTrade = value; + } + + // + double GetMinRequiredProfitPerTrade() + { + return this.minRequiredProfitPerTrade; + } + + // + void SetMinRequiredProfitPerTradeVolumeFactor(double value) + { + // + if (value < 0) + { + value = 0; + } + + // + this.minRequiredProfitPerTradeVolumeFactor = value; + } + + // + double GetMinRequiredProfitPerTradeVolumeFactor() + { + return this.minRequiredProfitPerTradeVolumeFactor; + } + + // + // Tools ... + + // + // Initial Class ... + bool + Init( + XSCTrade *trader, + double mMinRequiredProfitPerTrade = 0.35, + double mMinRequiredProfitPerTradeVolumeFactor = 0.01 // + ) + { + // + bool result = false; + + // + result = trader != NULL; + if (!result) + { + return result; + } + + // + this.mTrader = trader; + + // + SetMinRequiredProfitPerTrade(mMinRequiredProfitPerTrade); + SetMinRequiredProfitPerTradeVolumeFactor(mMinRequiredProfitPerTradeVolumeFactor); + + // + return result; + } + + // + // Handle Trades for Processing ... + // this used for Automating Recovery Positions ... + // we have to call this in our EA Class ... + void HandleState(const XOnTradeHandlerState &state) + { + // + if ( + !state.hasNewDeal && + !state.hasNewOrder && + !state.hasNewPosition && + !state.hasNewHistoryOrder) + { + return; + } + + // + // Here we Can Handle new Positions ... + // To Protect ... + + // + // Detect New Positions ... + if (!state.hasNewPosition) + { + // + // This means a Position SL or TP or Close ... + return; + } + + // + ulong lastPositionTicket = mTrader.GetLastOpenPositionTicket(); + if (lastPositionTicket <= 0) + { + return; + } + + // + // Retrieve XPosition ... + XPosition position; + bool isRetrieved = mTrader.GetPosition( + lastPositionTicket, + position // + ); + if (!isRetrieved) + { + return; + } + + // + // Now we Have Position Struct ... + // - First Check Position is new Regular Position or + // it is a Support Position; + // - then We have to Decide what to Do ... + + // + // Check Position is New Or Not ... + ulong parentTicket = ExtractEQMSupportedTicket(position.comment); + if (!NotEmptyZero(parentTicket)) + { + // + AddPosition(position); + } + else + { + // + UpdatePosition( + parentTicket, + position // + ); + } + } + + // + // Here we Process all Protected Positions ... + // for Handling Zone Recovery ... + void Process() + { + // + int protectedsCount = ArraySize(protecteds); + if (!IsValidSize(protectedsCount)) + { + return; + } + + // + // Loop through Exists ... + for (int i = 0; i < protectedsCount; i++) + { + // + // Do Protection ... + HandlePositionsProtecting(protecteds[i]); + } + + // + // Handle Hedging All Positions ... + bool allowHedge = AllowHedge(); + if (!allowHedge) + { + return; + } + + // + XPosition positions[]; + int positionsCount = mTrader.GetPositions(positions); + if (!IsValidSize(positions) || positionsCount <= 1) + { + return; + } + + // + double profit = SpecifiedCalculatePositionsProfit(positions); + double requiredProfit = SpecifiedCalculateRequiredProfitForHedge( + positions, + minRequiredProfitPerTrade, + minRequiredProfitPerTradeVolumeFactor // + ); + bool canHedge = SpecifiedIsPositionsReadyForHedge( + positions, + minRequiredProfitPerTrade, + minRequiredProfitPerTradeVolumeFactor // + ); + if (!canHedge) + { + return; + } + + // + string comment = XEQMSupportToken + " Hege ..."; + ENUM_X_SIGNAL_EXECUTION_RESULT states[]; + int closed = mTrader.Close( + positions, + comment // + ); + if (IsValidSize(closed)) + { + Clean(protecteds); + } + } + + // + // Sync Positions ... + + // + // Remove Support ... + bool Remove(ulong ticket) + { + // + bool result = false; + + // + int protectedIDX = FindProtectedIndex(ticket); + result = protectedIDX >= 0; + if (!result) + { + return result; + } + + // + // Close all Protected Support Positions if Exists ... + string comment = "EQM Close In Profit ..."; + + // + int ticketsCount = ArraySize(protecteds[protectedIDX].tickets); + if (IsValidSize(ticketsCount)) + { + // + for (int i = 0; i < ticketsCount; i++) + { + // + XPosition iPosition; + bool isRetrieved = mTrader.GetPosition( + protecteds[protectedIDX].tickets[i], + iPosition // + ); + if (!isRetrieved) + { + continue; + } + + // + bool isClosed = mTrader.Close( + iPosition.ticket, + comment // + ); + } + } + + // + result = ArrayRemove( + protecteds, + protectedIDX, + 1 // + ); + + // + // TODO: Update Collection here ... + + // + return result; + } + + // + // Protected ... +protected: + // + // Props ... + double minRequiredProfitPerTrade; // Minimum Required Profit Per Trade for Hedging + double minRequiredProfitPerTradeVolumeFactor; // Calculate Required Profit Based on Volume Factor for Hedging + int recoveryStepDivider; // Recovery Step Divider + ENUM_TIMEFRAMES recoveryStepPeriod; // Recovery Step Period + + // + // Tools ... + + // + // Here we recieve a new Position and + // Prepare it for Protecting ... + void AddPosition(XPosition &position) + { + // + // - Recieve Last Day Up and Low Boundary + // - Divided to 5 + // - Find Recovery Zone Step + // - Calculate Recoery Zone for this Specific Position + // - Prepare it's Structure + // - Add it to Collection + + // + // Validate Params ... + if (!position.IsValid()) + { + return; + } + + // + double recoveryStep = CalculateRecoveryZoneStep(position); + if (recoveryStep <= 0) + { + return; + } + + // + XProtectedPosition item; + bool isInited = item.Init( + recoveryStep, + position // + ); + if (!isInited) + { + return; + } + + // + AddRef( + item, + protecteds // + ); + + // + // TODO: Also Here We Can Collect Data ... + } + + // + // Here we recieve a Support Position and + // need to Update Parent Protected Position's + // info ... + void UpdatePosition( + ulong parentTicket, // Parent Position Ticket + XPosition &position // Support Position + ) + { + // + Print("Update Protected Position: " + ToString(parentTicket)); + } + + // + // Calculate Position Recovery one Step ... + double CalculateRecoveryZoneStep(XPosition &position) + { + // + double result = 0; + + // + // Validate Position ... + if (!position.IsValid()) + { + return result; + } + + // + // Validate Position must have TP and SL ... + if (position.tp == 0 || position.sl == 0) + { + return result; + } + + // + // Calculate Position Risk at Point ... + double point = GetPoints(position.symbol); + int digits = GetDigits(position.symbol); + double riskPoint = NormalizeDouble(MathAbs(position.entry - position.sl), digits) / point; + + // + // Retrieve Bar for finding Recovery Step ... + XOHCL rBar; + bool isInited = rBar.Init( + position.symbol, + recoveryStepPeriod, + 1 // + ); + if (!isInited) + { + return result; + } + + // + // Calculate Recovery Step ... + double riskPointRecoveryStep = riskPoint / 2; + double recoveryStep = (NormalizeDouble(MathAbs(rBar.high - rBar.low), digits) / point) / recoveryStepDivider; + result = MathMin(riskPointRecoveryStep, recoveryStep); + + // + return result; + } + + // + // Here we Implement all Protecting Senarios here ... + void HandlePositionsProtecting(XProtectedPosition &item) + { + // + // Check protected Validation ... + if (!item.IsValid()) + { + return; + } + + // + // Check Has Recovery Signal Or Not ... + XSignal signal; + bool hasRecovery = item.GetRecoverySignal(signal); + if (!hasRecovery) + { + return; + } + + // + signal.provider = XEQMSupportToken; + string comment = GenerateEQMSupportTag(item.ticket); + signal.comment = comment; + + // + ENUM_X_SIGNAL_EXECUTION_RESULT state; + bool isExecuted = mTrader.ExecuteSignal( + signal, + state, + ORDER_TIME_GTC, + NULL, + false // Ignore Policies ... + ); + if (isExecuted) + { + // + // Do What we Want ... + item.lastRecoveryLevel++; + item.lastVolume = signal.volume; + Add( + signal.positionId, + item.tickets // + ); + + // + int protectedIDX = FindProtectedIndex(item.ticket); + if (protectedIDX < 0) + { + return; + } + + // + protecteds[protectedIDX] = item; + + // + // TODO: Update Collect here ... + } + } + + // + // Check Hedging is Enabled ... + bool AllowHedge() + { + // + bool result = + // + minRequiredProfitPerTrade > 0 && + minRequiredProfitPerTradeVolumeFactor > 0 + // + ; + + // + return result; + } + + // + // Protected Collection Management ... + + // + int CountProtecteds() + { + return ArraySize(protecteds); + } + + // + int FindProtectedIndex(XProtectedPosition &item) + { + // + int result = -1; + + // + if (!item.IsValid()) + { + return result; + } + + // + result = FindProtectedIndex(item.ticket); + + // + return result; + } + + // + int FindProtectedIndex(ulong ticket) + { + // + int result = -1; + + // + if (!NotEmptyZero(ticket)) + { + return result; + } + + // + int protectedsCount = CountProtecteds(); + if (!IsValidSize(protectedsCount)) + { + return result; + } + + // + for (int i = 0; i < protectedsCount; i++) + { + // + if (protecteds[i].ticket == ticket) + { + // + result = i; + break; + } + } + + // + return result; + } +}; + // // Class Definition ... @@ -71,11 +1051,17 @@ public: onTradeStateChangedHandler // ) { + // + mProtector = new XSCPositionProtector(); + mProtector.Init(mTrader); } // // Deconstructor ... - ~XSCX121EA() {} + ~XSCX121EA() + { + delete mProtector; + } // // Properties Getter(s) / Setter(s) ... @@ -650,16 +1636,37 @@ public: } // - void HandleAccountProtect() { + void OnStopLossTriggered(const XDeal &deal) override + { // - XPosition positions[]; - int positionsCount = mTrader.GetPositions(positions); - if (!IsValidSize(positionsCount)) { - return; - } + // Remove Position Protecting ... + mProtector.Remove(deal.positionId); + } + // + void OnTakeProfitTriggered(const XDeal &deal) override + { // - + // Remove Position Protecting ... + mProtector.Remove(deal.positionId); + } + + // + void OnTradeStateChangedHandler( + const XOnTradeHandlerState &state // + ) override + { + // + // Calling Protector to Handle State ... + mProtector.HandleState(state); + } + + // + void HandleAccountProtect() + { + // + // Position Protector Calls to Process State ... + mProtector.Process(); } // @@ -1010,7 +2017,10 @@ private: } // - // Tools ... + // Position Protector ... + XSCPositionProtector *mProtector; + + // }; // diff --git a/Classes/x-saherelm.xtrade.class.mq5 b/Classes/x-saherelm.xtrade.class.mq5 index 260140aa..c165e84f 100644 --- a/Classes/x-saherelm.xtrade.class.mq5 +++ b/Classes/x-saherelm.xtrade.class.mq5 @@ -3180,6 +3180,52 @@ public: return result; } + // + // Tools ... + + // + // Retrieve Last Open Position Ticket ... + ulong GetLastOpenPositionTicket() + { + // + ulong result = 0; + + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + result = PositionGetTicket(PositionsTotal() - 1); + + // + return result; + } + + // + // Retrieve Last Placed Order Ticket ... + ulong GetLastPlacedOrderTicket() + { + // + ulong result = 0; + + int ordersCount = OrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + if (mOrderInfo.SelectByIndex(ordersCount - 1)) + { + result = mOrderInfo.Ticket(); + } + + // + return result; + } + // // Protected ... protected: @@ -3340,49 +3386,6 @@ protected: return result; } - // - // Retrieve Last Open Position Ticket ... - ulong GetLastOpenPositionTicket() - { - // - ulong result = 0; - - int positionsCount = PositionsTotal(); - if (positionsCount <= 0) - { - return result; - } - - // - result = PositionGetTicket(PositionsTotal() - 1); - - // - return result; - } - - // - // Retrieve Last Placed Order Ticket ... - ulong GetLastPlacedOrderTicket() - { - // - ulong result = 0; - - int ordersCount = OrdersTotal(); - if (ordersCount <= 0) - { - return result; - } - - // - if (mOrderInfo.SelectByIndex(ordersCount - 1)) - { - result = mOrderInfo.Ticket(); - } - - // - return result; - } - // // Extract Specific Deals Position's Pack ... // this used when a Position SL or TP triggered and we want to close diff --git a/Experts/x-test.x121ea.mq5 b/Experts/x-test.x121ea.mq5 index d4ae2b65..ae7cacfe 100644 --- a/Experts/x-test.x121ea.mq5 +++ b/Experts/x-test.x121ea.mq5 @@ -45,6 +45,7 @@ input bool x121EAAllowLong = true; // Allow Long Trades input bool x121EAAllowShort = true; // Allow Short Trades input double x121EAMaxAllowedDrawdownFactor = 0.002; // Max Allowed Drawdown Factor input double x121EAVolume = 0.01; // Static Volume +input double x121EAR2R = 1; // Risk to Reward Ratio // // Vars ... @@ -226,10 +227,11 @@ bool InitialEA() // X786 Signaller ... X786Signaller *x786Signaller = new X786Signaller(); x786Signaller.Default(); - x786Signaller.maxAllowedLong = 0; - x786Signaller.maxAllowedShort = 0; - x786Signaller.allowLong = false; // x121EAAllowLong; - x786Signaller.allowShort = false; // x121EAAllowShort; + x786Signaller.r2r = x121EAR2R; + x786Signaller.maxAllowedLong = 1; + x786Signaller.maxAllowedShort = 1; + x786Signaller.allowLong = x121EAAllowLong; + x786Signaller.allowShort = x121EAAllowShort; x786Signaller.maxAllowedOpenPositionAge = 0; x786Signaller.minRequiredProfitPerTrade = 0; x786Signaller.openNextPositionOnProfit = false; @@ -241,10 +243,11 @@ bool InitialEA() // X121 Signaller ... X121Signaller *x121Signaller = new X121Signaller(); x121Signaller.Default(); - x121Signaller.maxAllowedLong = 0; - x121Signaller.maxAllowedShort = 0; - x121Signaller.allowLong = false; // x121EAAllowLong; - x121Signaller.allowShort = false; // x121EAAllowShort; + x121Signaller.r2r = x121EAR2R; + x121Signaller.maxAllowedLong = 1; + x121Signaller.maxAllowedShort = 1; + x121Signaller.allowLong = x121EAAllowLong; + x121Signaller.allowShort = x121EAAllowShort; x121Signaller.maxAllowedOpenPositionAge = 0; x121Signaller.minRequiredProfitPerTrade = 0; x121Signaller.openNextPositionOnProfit = false; @@ -256,8 +259,9 @@ bool InitialEA() // X110 Signaller ... X110Signaller *x110Signaller = new X110Signaller(); x110Signaller.Default(); - x110Signaller.maxAllowedLong = 0; - x110Signaller.maxAllowedShort = 0; + x110Signaller.r2r = x121EAR2R; + x110Signaller.maxAllowedLong = 1; + x110Signaller.maxAllowedShort = 1; x110Signaller.allowLong = x121EAAllowLong; x110Signaller.allowShort = x121EAAllowShort; x110Signaller.maxAllowedOpenPositionAge = 0; @@ -271,12 +275,13 @@ bool InitialEA() // X92 Signaller ... X92Signaller *x92Signaller = new X92Signaller(); x92Signaller.Default(); + x92Signaller.r2r = x121EAR2R; x92Signaller.SetSymbol(iSymbol); x92Signaller.SetPeriod(iPeriod); - x92Signaller.maxAllowedLong = 0; - x92Signaller.maxAllowedShort = 0; - x92Signaller.allowLong = false; // x121EAAllowLong; - x92Signaller.allowShort = false; // x121EAAllowShort; + x92Signaller.maxAllowedLong = 1; + x92Signaller.maxAllowedShort = 1; + x92Signaller.allowLong = x121EAAllowLong; + x92Signaller.allowShort = x121EAAllowShort; x92Signaller.maxAllowedOpenPositionAge = 0; x92Signaller.minRequiredProfitPerTrade = 0; x92Signaller.openNextPositionOnProfit = false; @@ -288,8 +293,9 @@ bool InitialEA() // X128 Signaller ... X128Signaller *x128Signaller = new X128Signaller(); x128Signaller.Default(); - x128Signaller.maxAllowedLong = 0; - x128Signaller.maxAllowedShort = 0; + x128Signaller.r2r = x121EAR2R; + x128Signaller.maxAllowedLong = 1; + x128Signaller.maxAllowedShort = 1; x128Signaller.allowLong = false; // x121EAAllowLong; x128Signaller.allowShort = false; // x121EAAllowShort; x128Signaller.maxAllowedOpenPositionAge = 0; @@ -322,12 +328,12 @@ bool InitialEA() ArrayResize(iDescriptor.signallers, 1); // - // iDescriptor.signallers[idx] = x786Signaller; - // idx++; + iDescriptor.signallers[idx] = x786Signaller; + idx++; // iDescriptor.signallers[idx] = x121Signaller; // idx++; - iDescriptor.signallers[idx] = x110Signaller; - idx++; + // iDescriptor.signallers[idx] = x110Signaller; + // idx++; // iDescriptor.signallers[idx] = x92Signaller; // idx++; // iDescriptor.signallers[idx] = x128Signaller; @@ -393,7 +399,7 @@ void ConfigureDescriptor( // XASCT ... iDescriptor.inputs.asctInputs.showLongs = false; iDescriptor.inputs.asctInputs.showShorts = false; - + // // XHK ... iDescriptor.inputs.hkInputs.drawHikenAshi = false; diff --git a/Libraries/x-saherelm.common.lib.mq5 b/Libraries/x-saherelm.common.lib.mq5 index a18268e1..ab9e1095 100644 --- a/Libraries/x-saherelm.common.lib.mq5 +++ b/Libraries/x-saherelm.common.lib.mq5 @@ -5737,6 +5737,14 @@ bool NotEmpty(T value) return value != EMPTY_VALUE; } +// +// Check a Value Not Empty and Zero ... +template +bool NotEmptyZero(T value) +{ + return value != EMPTY_VALUE && value != 0; +} + // // Add Specified Item to Array ... template @@ -5836,6 +5844,11 @@ void Clean(T &buffer[]) ArrayFree(buffer); ArrayResize(buffer, 0); } +template +void SpecificClean(T &buffer[]) +{ + Clean(buffer); +} // // Copy Whole Content of Source to Dest array ... diff --git a/Libraries/x-saherelm.xtrade.lib.mq5 b/Libraries/x-saherelm.xtrade.lib.mq5 index 5eb8f70b..67f7f632 100644 --- a/Libraries/x-saherelm.xtrade.lib.mq5 +++ b/Libraries/x-saherelm.xtrade.lib.mq5 @@ -3819,6 +3819,94 @@ bool SpecifiedIsPositionsReadyForHedge( return result; } +// +// Extract a Collection of Positions SL ... +int ExtractSLs( + XPosition &positions[], + double &sls[] // +) +{ + // + int result = 0; + + // + Clean(sls); + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.sl > 0) + { + // + Add( + iPosition.sl, + sls // + ); + } + } + + // + result = ArraySize(sls); + + // + return result; +} + +// +// Extract a Colletion of Positions TP ... +int ExtractTPs( + XPosition &positions[], + double &tps[] // +) +{ + // + int result = 0; + + // + Clean(tps); + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.tp > 0) + { + // + Add( + iPosition.tp, + tps // + ); + } + } + + // + result = ArraySize(tps); + + // + return result; +} + // // Retrieve String Representation ... string ToString(ENUM_X_SIGNAL_EXECUTION_RESULT value) diff --git a/Signallers/x-saherelm.x110.signaller.class.mq5 b/Signallers/x-saherelm.x110.signaller.class.mq5 index 8dfb8d72..d7db5b7d 100644 --- a/Signallers/x-saherelm.x110.signaller.class.mq5 +++ b/Signallers/x-saherelm.x110.signaller.class.mq5 @@ -156,19 +156,19 @@ public: // result = // - // condition1 - // // - // || - // // - // condition2 - // // - // || - // // + condition1 + // + || + // + condition2 + // + || + // condition3 - // // - // || - // // - // condition4 + // + || + // + condition4 // ; @@ -176,7 +176,7 @@ public: if (result) { result = - bullishScore > bearishScore; + bullishScore > bearishScore * 1.5; } // @@ -293,27 +293,27 @@ public: // result = // - // condition1 + condition1 + + || + // + condition2 + // + || // - // || - // // - // condition2 - // // - // || - // // condition3 - // // - // || - // // - // condition4 + // + || + // + condition4 // ; - + // if (result) { result = - bearishScore > bullishScore ; + bearishScore > bullishScore * 1.5; } // @@ -325,4 +325,6 @@ public: // return result; } -}; \ No newline at end of file +}; + +// \ No newline at end of file diff --git a/Signallers/x-saherelm.x121.signaller.class.mq5 b/Signallers/x-saherelm.x121.signaller.class.mq5 index ca0aff74..7cfb6fa4 100644 --- a/Signallers/x-saherelm.x121.signaller.class.mq5 +++ b/Signallers/x-saherelm.x121.signaller.class.mq5 @@ -73,6 +73,14 @@ public: return result; } + // + double bullishScore = 0; + double bearishScore = 0; + conditions.GenerateScore( + bullishScore, + bearishScore // + ); + // result = // @@ -98,6 +106,13 @@ public: // ; + // + if (result) + { + result = + bullishScore > bearishScore * 1.5; + } + // if (result) { @@ -129,6 +144,14 @@ public: return result; } + // + double bullishScore = 0; + double bearishScore = 0; + conditions.GenerateScore( + bullishScore, + bearishScore // + ); + // result = // @@ -160,6 +183,13 @@ public: // ; + // + if (result) + { + result = + bearishScore > bullishScore * 1.5; + } + // if (result) { diff --git a/Signallers/x-saherelm.x786.signaller.class.mq5 b/Signallers/x-saherelm.x786.signaller.class.mq5 index 2afa68f7..385ba592 100644 --- a/Signallers/x-saherelm.x786.signaller.class.mq5 +++ b/Signallers/x-saherelm.x786.signaller.class.mq5 @@ -74,6 +74,14 @@ public: return result; } + // + double bullishScore = 0; + double bearishScore = 0; + conditions.GenerateScore( + bullishScore, + bearishScore // + ); + // result = // @@ -105,6 +113,13 @@ public: // ; + // + if (result) + { + result = + bullishScore > bearishScore * 1.5; + } + // if (result) { @@ -125,6 +140,10 @@ public: // bool result = false; + // + tp = 0; + sl = 0; + // result = allowShort; if (!result) @@ -133,8 +152,12 @@ public: } // - tp = 0; - sl = 0; + double bullishScore = 0; + double bearishScore = 0; + conditions.GenerateScore( + bullishScore, + bearishScore // + ); // result = @@ -167,6 +190,13 @@ public: // ; + // + if (result) + { + result = + bearishScore > bullishScore * 1.5; + } + // if (result) { diff --git a/Signallers/x-saherelm.x92.signaller.class.mq5 b/Signallers/x-saherelm.x92.signaller.class.mq5 index 21242c94..2a39dd06 100644 --- a/Signallers/x-saherelm.x92.signaller.class.mq5 +++ b/Signallers/x-saherelm.x92.signaller.class.mq5 @@ -96,6 +96,14 @@ public: return result; } + // + double bullishScore = 0; + double bearishScore = 0; + conditions.GenerateScore( + bullishScore, + bearishScore // + ); + // bool isRejected = // @@ -135,6 +143,13 @@ public: // ; + // + if (result) + { + result = + bullishScore > bearishScore * 1.5; + } + // if (result) { @@ -182,6 +197,14 @@ public: return result; } + // + double bullishScore = 0; + double bearishScore = 0; + conditions.GenerateScore( + bullishScore, + bearishScore // + ); + // bool isRejected = // @@ -221,6 +244,13 @@ public: // ; + // + if (result) + { + result = + bearishScore > bullishScore * 1.5; + } + // if (result) {