diff --git a/X121SMCEA/Classes/x-121.smc.x-tradehandler.class.mq5 b/X121SMCEA/Classes/x-121.smc.x-tradehandler.class.mq5 index 22e9d3ac..8b7e84e3 100644 --- a/X121SMCEA/Classes/x-121.smc.x-tradehandler.class.mq5 +++ b/X121SMCEA/Classes/x-121.smc.x-tradehandler.class.mq5 @@ -212,11 +212,12 @@ struct X121SMCTradeData * * @return ( bool ) */ - bool IsOwn( + bool IsOwnSignalTime( string _symbol, string _provider, ENUM_TIMEFRAMES _period, - ENUM_X_POSITION_TYPES _type // + ENUM_X_POSITION_TYPES _type, + datetime _time // ) { // @@ -225,6 +226,8 @@ struct X121SMCTradeData // result = // + IsValid(_time) && + Time() == _time && IsValid(_symbol) && IsValid(_period) && XType() == _type && @@ -241,6 +244,49 @@ struct X121SMCTradeData return result; } + /** + * Check Specified Conditions is Own to Model or not ... + * + * @param _symbol: String, Specified Symbol ... + * @param _provider: String, Specified Provider ... + * @param _period: ENUM_TIMEFRAMES member, Specified Signal Period ... + * @param _type: ENUM_X_POSITION_TYPES member, Specified Signal Type ... + * + * @return ( bool ) + */ + bool IsOwnStartTime( + string _symbol, + string _provider, + ENUM_TIMEFRAMES _period, + ENUM_X_POSITION_TYPES _type, + datetime _time // + ) + { + // + bool result = false; + + // + result = + // + IsValid(_time) && + IsValid(_symbol) && + IsValid(_period) && + XType() == _type && + IsValid(startTime) && + startTime == _time && + IsValid(_provider) && + GetPeriod() == _period && + GetSymbol() == _symbol && + Provider() == _provider && + XType() != X_POSITION_TYPE_ALL && + XType() != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + /** * Check Specified Signal is Own to Model or not ... * @@ -258,11 +304,12 @@ struct X121SMCTradeData // IsValid() && _signal.IsValid() && - IsOwn( + IsOwnSignalTime( _signal.symbol, _signal.provider, _signal.period, - ToPositionType(_signal.type)) + ToPositionType(_signal.type), + _signal.time) // ; @@ -287,11 +334,58 @@ struct X121SMCTradeData // IsValid() && _position.IsValid() && - IsOwn( + IsOwnStartTime( _position.symbol, _position.provider, _position.period, - ToPositionType(_position.type)) + ToPositionType(_position.type), + _position.openAt) + // + ; + + // + return result; + } + + /** + * Check Specified Position is Own to Model or not ... + * + * @param _position: XPosition instance Reference ... + * + * @return ( bool ) + */ + bool IsOwnPosition(XPosition &_position) + { + // + bool result = false; + + // + double tp = TP(); + double sl = SL(); + double entry = Entry(); + double volume = Volume(); + string symbol = GetSymbol(); + string provider = Provider(); + ENUM_POSITION_TYPE type = Type(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + double pVolume = _position.volume; + double pSL = NormalizePrice(_position.sl, _position.symbol); + double pEntry = NormalizePrice(_position.entry, _position.symbol); + + // + result = + // + IsValid() && + sl == pSL && + entry == pEntry && + pVolume == volume && + _position.IsValid() && + type == _position.type && + symbol == _position.symbol && + period == _position.period && + provider == _position.provider // ; @@ -395,6 +489,70 @@ struct X121SMCTradeData return result; } + /** + * Update Model Data by Providing Specified Position ... + * + * @param _position: XPosition instance Reference ... + * + * @return ( bool ) + */ + bool UpdatePosition(XPosition &_position) + { + // + bool result = false; + + // + result = + // + IsValid() && + _position.IsValid() && + IsOwnPosition(_position) + // + ; + if (!result) + { + return result; + } + + // + swap = _position.swap; + ticket = _position.ticket; + profit = _position.profit; + message = _position.comment; + startTime = _position.openAt; + + // + // Set Once ... + if (commission == 0 && + _position.commission != 0) + { + commission = _position.commission; + } + + // + // Set Once ... + if (ask == 0) + { + ask = GetAsk(_position.symbol); + } + + // + // Set Once ... + if (bid == 0) + { + bid = GetBid(_position.symbol); + } + + // + if (profit < 0 && profit < maxDrawdown) + { + maxDrawdown = profit; + } + + // + return result; + } + // // Tools Extensions ... @@ -534,6 +692,16 @@ struct X121SMCTradeData return signal.mode; } + /** + * Get Model Signal Time ... + * + * @return ( datetime ) + */ + datetime Time() + { + return signal.time; + } + // // Additional Helpers Extensions ... @@ -2387,7 +2555,18 @@ class XC121SMCTradeHandler : public XCBaseAlert // // Apply Updates on Data Collection ... - Update(position); + int idx = -1; + bool hasItem = HasItemByPosition( + position, + idx // + ); + if (!hasItem) + { + return; + } + + // + mData[idx].UpdatePosition(position); } // @@ -2973,18 +3152,18 @@ class XC121SMCTradeHandler : public XCBaseAlert : maxSameTimeTrades; // + double bepSummary = 0; + double volumeSummary = 0; double profitSummary = 0; + XPosition positions[]; // + // Loop through Open Positions ... for (int i = 0; i < count; i++) { // X121SMCTradeData iData = mData[i]; - // - // Profit Sum ... - profitSummary += iData.profit; - // XPosition iPosition; bool hasPosition = mTrader.GetPosition( @@ -2995,6 +3174,10 @@ class XC121SMCTradeHandler : public XCBaseAlert { continue; } + AddRef( + iPosition, + positions // + ); // // Calculate Break Even Point ... @@ -3019,6 +3202,11 @@ class XC121SMCTradeHandler : public XCBaseAlert reachedTPPrice // ); + // + bepSummary += bep; + volumeSummary += volume; + profitSummary += iPosition.profit; + // // All Protections Done for InProfit Positions ... if (iData.profit > 0) @@ -3058,6 +3246,82 @@ class XC121SMCTradeHandler : public XCBaseAlert } } } + + // + // Check Partial Close ... + bool canPartialClose = iData.CanPartialClose(); + if (canPartialClose && reachedTPLevel > 0) + { + // + double mainVolume = iData.Volume(); + double currentVolume = iPosition.volume; + double partialCloseOnTP = iData.PartialCloseOnTPLevel(); + double partialCloseVolumeMultiplier = iData.PartialCloseMultiplier(); + double closeVolume = currentVolume * partialCloseVolumeMultiplier; + closeVolume = NormalizeVolume(closeVolume, iPosition.symbol); + canPartialClose = + currentVolume == mainVolume && + reachedTPLevel == partialCloseOnTP; + if (canPartialClose) + { + // + string comment = "PC On TP Level: " + ToString(partialCloseOnTP) + " ..."; + bool isModified = mTrader.ClosePartial( + iData.ticket, + closeVolume, + comment // + ); + if (isModified) + { + // + string message = ToString(iData.Type()) + + " Position: " + + ToString(iData.ticket) + + " PC (" + ToString(closeVolume) + ") On TP Level: " + + ToString(partialCloseOnTP) + " Successfully ..."; + Alert(message); + } + } + } + + // + // Check for SL Trail ... + bool canTrailSL = iData.CanTrailSL(); + if (canTrailSL && reachedTPLevel > 0) + { + // + double startTrailTPLevel = iData.TrailSLStartOnReachTPLevel(); + int tSLTPIndex = (int)reachedTPLevel - 1; + double tSLTPPrice = tps[tSLTPIndex]; + canTrailSL = + reachedTPLevel >= startTrailTPLevel && + (isLong + ? iPosition.sl < tSLTPPrice + : iPosition.sl > tSLTPPrice); + if (canTrailSL) + { + // + string comment = "Trail SL on Reached TP: " + ToString(reachedTPLevel) + " ..."; + double sl = tSLTPPrice; + double tp = iPosition.tp; + bool isModified = mTrader.Modify( + iData.ticket, + sl, + tp, + comment // + ); + if (isModified) + { + // + string message = ToString(iData.Type()) + + " Position: " + + ToString(iData.ticket) + + " Trailed SL On Reached TP: " + ToString(reachedTPLevel) + + " Successfully ..."; + Alert(message); + } + } + } } } @@ -3078,10 +3342,46 @@ class XC121SMCTradeHandler : public XCBaseAlert : 0; // - // TODO: Here Implement Collection Based Protections ... + // Checking Hedge ... + bool allowHedge = AllowHedge(); + if (allowHedge) + { + // + double minHedgeVolumeStep = HedgeMinVolumeStep(); + int minRequiredPositionsForHedge = MinimumOpenPositionsForHedge(); + double minRequiredProfitPerVolumeStepForHedge = HedgeMinProfitPerVolumeStep(); - // - Print("Protection"); + // + double minRequiredAdditionalProfit = + bepSummary + + ((volumeSummary / minHedgeVolumeStep) * minRequiredProfitPerVolumeStepForHedge); + + // + bool canHedge = AllowHedge() && + profitSummary > 0 && + minHedgeVolumeStep > 0 && + minRequiredProfitPerVolumeStepForHedge > 0 && + profitSummary >= minRequiredAdditionalProfit && + (minRequiredPositionsForHedge <= 0 + ? true + : count >= minRequiredPositionsForHedge); + if (canHedge) + { + // + string comment = "Hedge (" + ToString(count) + ") Positions By: " + ToString(profitSummary) + "..."; + int closedPositionsCount = mTrader.Close( + positions, + comment // + ); + if (IsValidSize(closedPositionsCount)) + { + // + string message = "Hedge (" + ToString(count) + ") Positions By: " + + ToString(profitSummary) + " Successfully ..."; + Alert(message); + } + } + } } // @@ -3181,10 +3481,7 @@ class XC121SMCTradeHandler : public XCBaseAlert { // result = !HasItem( - item.GetSymbol(), - item.Provider(), - item.GetPeriod(), - item.XType(), + item.signal, index // ); } @@ -3250,16 +3547,35 @@ class XC121SMCTradeHandler : public XCBaseAlert ) { // - bool result = + bool result = false; + + // + index = -1; + + // + int count = Count(); + result = signal.IsValid() && + IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { // - signal.IsValid() && - HasItem(signal.symbol, - signal.provider, - signal.period, - ToPositionType(signal.type), - index) - // - ; + bool isOwn = mData[i].IsOwn(signal); + if (isOwn) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); // return result; @@ -3272,28 +3588,43 @@ class XC121SMCTradeHandler : public XCBaseAlert ) { // - bool result = + bool result = false; + + // + index = -1; + + // + int count = Count(); + result = position.IsValid() && + IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { // - position.IsValid() && - HasItem(position.symbol, - position.provider, - position.period, - ToPositionType(position.type), - index) - // - ; + bool isOwn = mData[i].IsOwn(position); + if (isOwn) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); // return result; } // - // Find Item Index ... - bool HasItem( - string symbol, - string provider, - ENUM_TIMEFRAMES period, - ENUM_X_POSITION_TYPES type, + bool HasItemByPosition( + XPosition &position, int &index // ) { @@ -3303,25 +3634,10 @@ class XC121SMCTradeHandler : public XCBaseAlert // index = -1; - // - // Validate ... - result = - // - IsValid(symbol) && - IsValid(period) && - IsValid(provider) && - type != X_POSITION_TYPE_ALL && - type != X_POSITION_TYPE_NONE - // - ; - if (!result) - { - return result; - } - // int count = Count(); - result = IsValidSize(count); + result = position.IsValid() && + IsValidSize(count); if (!result) { return result; @@ -3331,13 +3647,8 @@ class XC121SMCTradeHandler : public XCBaseAlert for (int i = 0; i < count; i++) { // - result = mData[i].IsOwn( - symbol, - provider, - period, - type // - ); - if (result) + bool isOwn = mData[i].IsOwnPosition(position); + if (isOwn) { // index = i; @@ -3345,6 +3656,9 @@ class XC121SMCTradeHandler : public XCBaseAlert } } + // + result = IsValidIndex(index); + // return result; } diff --git a/X121SMCEA/Experts/x-121.smc.expert.class.mq5 b/X121SMCEA/Experts/x-121.smc.expert.class.mq5 index 3364142f..925cc1c1 100644 --- a/X121SMCEA/Experts/x-121.smc.expert.class.mq5 +++ b/X121SMCEA/Experts/x-121.smc.expert.class.mq5 @@ -568,7 +568,7 @@ class XC121SMCExpert : public XCBaseExpert // // Configure Hedging ... - mTradeHandler.AllowHedge(false); + mTradeHandler.AllowHedge(true); mTradeHandler.HedgeMinVolumeStep(0.01); mTradeHandler.MinimumOpenPositionsForHedge(2); mTradeHandler.HedgeMinProfitPerVolumeStep(0.2); diff --git a/X121SMCEA/Strategy/x-121.smc.test.strategy.class.mq5 b/X121SMCEA/Strategy/x-121.smc.test.strategy.class.mq5 index d519aecd..2ee7e19d 100644 --- a/X121SMCEA/Strategy/x-121.smc.test.strategy.class.mq5 +++ b/X121SMCEA/Strategy/x-121.smc.test.strategy.class.mq5 @@ -294,7 +294,7 @@ class XCX121SMCTestStrategy : public XCX121SMCBaseStrategy // signal.trailSL = true; - signal.trailSLStartOnReachTPLevel = 3; + signal.trailSLStartOnReachTPLevel = 4; } //