/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class Library // ---------------------------------------------- // Name: XSCX121EA // Description: provides all X121 EA requirements ... // - X5 Provider; // // // 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.xea.class.mq5" #include "../Classes/x-saherelm.x121.provider.class.mq5" // // Define On Signal Event Handler Type Specified for X5 ... typedef void (*TX121OnSignal)(X121ProviderDescriptor &descriptor); // // Class Definition ... class XSCX121EA : public XSCBaseEA { // // Public ... public: // // Props ... // // Constructors ... XSCX121EA( // // XTrade Class Requirements ... int slippage, // Specify Slippage ulong magicNumber, // Specify Magic Number int manageInterval, // Manager Check Intervals Seconds double maxAllowedSpread, // Max Allowed Spred for Opening Trades int maxAllowedPositions, // Max Allowed Positions double maxAllowedDrawdownFactor, // Max Allowed Drawdown Factor double staticVolume, // Static Volume for Positions // // Position Management ... bool allowLong = true, // Allow Long Trades bool allowShort = true, // Allow Short Trades double minProfitPerTrade = 0, // Min Profit Per Trade based On Volume Factor (Hedge) double minProfitPerVolumeFactor = 0, // Min Volume Factor for Calculating Profit (Hedge) // // Event Handlers ... TOnStopLoss onStopLossTriggered = NULL, // On StopLoass Triggered Event Handler TOnTakeProfit onTakeProfitTriggered = NULL, // On TakeProfit Triggered Event Handler TOnDealsChanged onDealsChangedHandler = NULL, // On Deals Changed Event Handler TOnOrdersChanged onOrdersChangedHandler = NULL, // On Orders Changed Event Handler TOnPositionsChanged onPositionsChangedHandler = NULL, // On Positions Changed Event Handler TOnTradeStateChanged onTradeStateChangedHandler = NULL, // On Trade State Changed Event Handler // TOnSignal onSignalHandler = NULL, // On Signal Event Handler // // Log Handler ... bool enableAlerts = true, // Enable Alerts bool logAlerts = true, // Log Alerts bool terminalAlerts = false, // Terminal Alerts bool mailAlerts = false, // Mail Alerts bool pushAlerts = false // Push Alerts ) : XSCBaseEA(slippage, magicNumber, manageInterval, maxAllowedSpread, maxAllowedPositions, maxAllowedDrawdownFactor, staticVolume, allowLong, allowShort, minProfitPerTrade, minProfitPerVolumeFactor, onStopLossTriggered, onTakeProfitTriggered, onDealsChangedHandler, onOrdersChangedHandler, onPositionsChangedHandler, onTradeStateChangedHandler, enableAlerts, logAlerts, terminalAlerts, mailAlerts, pushAlerts // ) { } // // Deconstructor ... ~XSCX121EA() {} // // Properties Getter(s) / Setter(s) ... // // Add X5 Specified Signal Event Handler ... void AddOnSignalEventHandler(TX121OnSignal listener) { // Add( listener, mX121OnSignalEventHandlers // ); } // // Add Specified X5 Provider ... bool AddProvider(X121ProviderDescriptor &descriptor) { // bool result = false; // // Validate Inputs ... result = descriptor.Init(); if (!result) { return result; } // AddRef( descriptor, mDescriptors // ); // return result; } // // Overrides ... // // Customize Token ... string GetToken() override { return GetSpecificToken(this); } // string GetTag() override { return this.GetToken(); } // void Draw() override { // int descriptorsCount = CountDescriptors(); if (descriptorsCount <= 0) { return; } // for (int i = 0; i < descriptorsCount; i++) { // X121ProviderDescriptor iDescriptor = mDescriptors[i]; // iDescriptor.provider.Draw(); } } // // Check Provider for any Guards ... bool CheckForGuard(XGuard &guards[]) override { // bool result = false; // Clean(guards); // int descriptorsCount = CountDescriptors(); result = descriptorsCount > 0; if (!result) { return result; } // for (int i = 0; i < descriptorsCount; i++) { // X121ProviderDescriptor iDescriptor = mDescriptors[i]; // XGuard iGuards[]; bool iHasGuard = iDescriptor.provider.HasGuard(iGuards); if (iHasGuard) { // Copy( iGuards, guards, false // ); } } // result = ArraySize(guards) > 0; // return result; } // // Request Provider to Collect all // Potentially Signals and then // filters theme here and passed them // for Executing ... int RequestForSignal( XSignal &signals[] // Holds Signals ... ) override { // bool result = 0; // Clean(signals); // int descriptorsCount = CountDescriptors(); if (descriptorsCount <= 0) { return result; } // for (int i = 0; i < descriptorsCount; i++) { // X121ProviderDescriptor iDescriptor = mDescriptors[i]; // bool iHasSignal = iDescriptor.HasSignal(); if (iHasSignal) { // // Here we Can double check Signals by Conditions // for Score Base Filtering ... // AddRef( iDescriptor.signal, signals // ); // NotifyX121OnSignalEventHandlers(iDescriptor); } } // result = ArraySize(signals); // return result; } // // Handl Management Actions ... // if returns true, it is going to prevent for processing forward ... bool HandleStateManagement(XSignal &signals[]) override { // bool result = false; // XPosition positions[]; int positionsCount = mTrader.GetPositions(positions); if (positionsCount <= 0) { return result; } // // Synch Position Tracker ... SyncPositionTracker(); // HandleEQMState(signals); // HandleEQMHedge(positions); // HandleTrailManagement(positions); // // Close all Positions on 22 ... // TODO: Make it Configurable ... int closeHour = -1; MqlDateTime cTime = GetCurrentTime(); if (closeHour >= 0 && cTime.hour == closeHour) { // string comment = "EQM Close on Time ..."; // XPosition positions[]; int positionsCount = mTrader.GetPositions(positions); if (positionsCount <= 0) { return result; } // int closed = mTrader.Close( positions, comment // ); if (closed > 0) { mAlert.Alert(comment); } } // // Must false ... return result; } // void HandleEQMHedge(XPosition &positions[]) { // // TODO: // Make them Configurable ... int numberOfPositionsForHege = 3; // if (!IsHedgeEnable()) { return; } // int positionsCount = ArraySize(positions); if (positionsCount <= 0) { return; } // // Hedge ... if (positionsCount >= numberOfPositionsForHege) { // int maxAllowedPositions = GetMaxAllowedPositions(); // double profit = CalculatePositionsProfit(positions); double requiredProfit = CalculateRequiredProfitForHedge(positions); // bool isReadyForHedge = positionsCount < maxAllowedPositions ? profit >= requiredProfit : positionsCount >= maxAllowedPositions && profit >= (requiredProfit * 0.80) ? true : false; if (!isReadyForHedge) { return; } // string comment = "EQM Hedge ..."; int closed = mTrader.Close( positions, comment); if (closed > 0) { // string message = "EQM Hedge Positions on Profit: " + ToString(profit); // mAlert.Alert(message); // RemoveEQMOrders(); // for (int i = 0; i < positionsCount; i++) { RemoveTrail(positions[i].ticket); } } } } // void HandleEQMState(XSignal &signals[]) { // XSignal accepted[]; bool equityReached = !mTrader.CheckEquityForTrade(); bool maxAllowedReached = !mTrader.CheckPositionsForTrade(); bool enableEQM = equityReached || maxAllowedReached; if (!enableEQM) { return; } // int signalsCount = ArraySize(signals); if (IsValidSize(signalsCount)) { // // Extract required Data ... XPosition positions[]; int positionsCount = mTrader.GetPositions( positions); if (!IsValidSize(positionsCount)) { return; } // int longs = 0; double longProfits = 0; double longVolumes = 0; // int shorts = 0; double shortProfits = 0; double shortVolumes = 0; // CountPositions( positions, longs, longProfits, longVolumes, shorts, shortProfits, shortVolumes // ); // for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = signals[i]; bool isLong = IsLong(iSignal.type); // bool canAccept = // iSignal.provider == XEQMSupportToken ? true : isLong ? longs < shorts || longProfits > shortProfits : shorts < longs || shortProfits > longProfits // ; if (!canAccept) { continue; } iSignal.comment = ""; iSignal.provider = XEQMSupportToken; // iSignal.volume *= 2; // AddRef( iSignal, accepted // ); } // int acceptedCount = ArraySize(accepted); if (!IsValidSize(acceptedCount)) { return; } // // Execute EQM Signals ... ENUM_X_SIGNAL_EXECUTION_RESULT reasons[]; int executed = mTrader.ExecuteSignals( accepted, reasons, ORDER_TIME_GTC, NULL, false // ); if (executed > 0) { // string message = "EQM Execute " + ToString(executed) + " Signals ..."; // mAlert.Alert(message); } } } // // Add Or Update EQM Orders ... void PlaceEQMOrders(XPosition &position) { // // TODO: Make It Configurable ... int maxEQMCount = 5; return; // // Position Protection Senarioos ... if (!position.IsValid()) { return; } // int descriptorIDX = FindDescriptorIndex(position); if (descriptorIDX <= -1) { return; } // X121ProviderDescriptor descriptor = mDescriptors[descriptorIDX]; // XOHCLSupRes slSupRes; bool hasSupRes = descriptor .provider .GenerateSupRes( slSupRes, position.type, 5 // ); // XDrawSpecifications supDrawSpecs; supDrawSpecs.draw = true; supDrawSpecs.rayRight = true; supDrawSpecs.clr = clrLightGreen; //, XDrawSpecifications resDrawSpecs; resDrawSpecs.draw = true; resDrawSpecs.rayRight = true; resDrawSpecs.clr = clrLightCoral; // // DrawSupRes( // slSupRes, // supDrawSpecs, // resDrawSpecs // // ); // XSignal supports[]; int supportsCount = GenerateEQMOrders( supports, position, slSupRes // ); if (!IsValidSize(supportsCount)) { return; } // XOrder untriggeredOrders[]; int untriggeredOrdersCount = mTrader.GetOrders( untriggeredOrders, position.symbol, XEQMSupportToken, position.period, NULL, // All Types ... ORDER_STATE_PLACED, true // ); // XPosition triggereSupports[]; int tiggeredSupportsCount = mTrader.GetPositions( triggereSupports, position.symbol, XEQMSupportToken, position.period, NULL, // All Types ... true // ); // if (untriggeredOrdersCount + tiggeredSupportsCount >= maxEQMCount) { return; } // XSignal filteredSignals[]; for (int i = 0; i < supportsCount; i++) { // XSignal iSupport = supports[i]; // double sl; iSupport.RegularSL(sl); // double tp; iSupport.RegularTP(tp); // if (!IsValidSize(untriggeredOrdersCount) && !IsValidSize(tiggeredSupportsCount)) { // AddRef( iSupport, filteredSignals // ); // continue; } // bool isOrdersPassed = true; if (!IsValidSize(untriggeredOrdersCount)) { isOrdersPassed = true; } else { // for (int j = 0; j < untriggeredOrdersCount; j++) { // XOrder jOrder = untriggeredOrders[j]; // bool isSame = // jOrder.symbol == iSupport.symbol && jOrder.period == iSupport.period && jOrder.openPrice == iSupport.entry && jOrder.sl == sl && jOrder.tp == tp // ; if (isSame) { // isOrdersPassed = false; break; } } } // bool isPositionsPassed = true; if (!IsValidSize(tiggeredSupportsCount)) { isPositionsPassed = true; } else { // for (int j = 0; j < tiggeredSupportsCount; j++) { // XPosition jPosition = triggereSupports[j]; // bool isSame = // jPosition.symbol == iSupport.symbol && jPosition.period == iSupport.period && jPosition.entry == iSupport.entry && jPosition.sl == sl && jPosition.tp == tp // ; if (isSame) { // isPositionsPassed = false; break; } } } // if (isOrdersPassed && isPositionsPassed) { // AddRef( iSupport, filteredSignals // ); } } int filteredSignalsCount = ArraySize(filteredSignals); if (!IsValidSize(filteredSignalsCount)) { return; } // ENUM_X_SIGNAL_EXECUTION_RESULT states[]; int placedOrders = mTrader.ExecuteSignals( filteredSignals, states, ORDER_TIME_GTC, NULL, false // Ignore Policies ... ); if (placedOrders > 0) { // string message = "EQM Placed (" + ToString(placedOrders) + ") Support Orders ..."; // mAlert.Alert(message); } } // void RemoveEQMOrders() { // XOrder untriggeredOrders[]; int untriggeredOrdersCount = mTrader.GetOrders( untriggeredOrders, NULL, XEQMSupportToken, NULL, NULL, // All Types ... ORDER_STATE_PLACED, true // ); if (!IsValidSize(untriggeredOrdersCount)) { return; } // int canceleds = mTrader.CancelOrders( untriggeredOrders // ); if (canceleds > 0) { // string message = "EQM Cancel Support ..."; // mAlert.Alert(message); } } // void HandleTrailManagement(XPosition &positions[]) { // return; // // TODO: // Make them Configurable ... int maxTrailTPs = 5; // int levelsOnClose = 6; int riskFreeLevel = 0; int requiredAgeForTrail = 0; int requiredDistanceForTrail = 50; // int positionsCount = ArraySize(positions); if (positionsCount <= 0) { return; } // double profit = CalculatePositionsProfit(positions); // // Trail Positions Stop ... for (int i = 0; i < positionsCount; i++) { // XPosition iPosition = positions[i]; // bool canManageState = // iPosition.provider == XEQMSupportToken // ; // // Position Management for X786 ... if (canManageState) { // // When Position in Profit, Trail SL ... if (profit > 0) { // if (iPosition.profit > 0) { // XTrail trail; bool isTrailedBefore = GetSLTrail( iPosition.ticket, trail // ); // if (!isTrailedBefore) { // // Add First Time ... // // Check Position Age ... int iPositionAge = iPosition.GetAge(iPosition.period); if (iPositionAge < requiredAgeForTrail) { continue; } // // Check Position Profit Distance ... // double reward = MathAbs(iPosition.tp - iPosition.entry); double priceDistanceInPoint = PriceToPoint(iPosition.profit / iPosition.volume, iPosition.symbol); double priceDistance = PointToPrice(priceDistanceInPoint, iPosition.symbol); if (priceDistance < requiredDistanceForTrail) { continue; } // double slDiff = PointToPrice(priceDistance, iPosition.symbol); double appliedSL = slDiff / 2; // // double sl = // IsLong(iPosition.type) // ? iPosition.sl + appliedSL // : iPosition.sl - appliedSL; // double sl = IsLong(iPosition.type) ? iPosition.entry + appliedSL : iPosition.entry - appliedSL; // // double sl = // IsLong(iPosition.type) // ? iPosition.entry + appliedSL // : iPosition.entry - appliedSL; // bool isInit = trail.Init( iPosition.ticket, iPosition.type, iPosition.profit, iPosition.sl, sl // ); if (!isInit) { continue; } } else { // // Update Exists ... // // Check Profit ... bool isProfitPassed = iPosition.profit > trail.profit; if (!isProfitPassed) { continue; } // // Check Age Distance from Last ... int age = iBarShift( iPosition.symbol, iPosition.period, trail.time, false // ); if (age < requiredAgeForTrail) { continue; } // double priceDistanceInPoint = PriceToPoint((iPosition.profit - trail.profit) / iPosition.volume, iPosition.symbol); double priceDistance = PointToPrice(priceDistanceInPoint, iPosition.symbol); if (priceDistance < requiredDistanceForTrail) { continue; } // bool isLong = IsLong(iPosition.type); // double slDiff = PointToPrice(priceDistance, iPosition.symbol); double appliedSL = (slDiff / 2); // double selectedValue = // (riskFreeLevel > 0 && trail.level == riskFreeLevel) || (isLong ? iPosition.sl < iPosition.entry : iPosition.sl > iPosition.entry) ? iPosition.entry : iPosition.sl // ; if (riskFreeLevel > 0 && trail.level > riskFreeLevel) { appliedSL = slDiff; } // double sl = isLong ? selectedValue + appliedSL : selectedValue - appliedSL; // // Update Trail Values ... bool isUpdated = trail.Update( sl, iPosition.profit // ); if (!isUpdated) { continue; } } // if (trail.IsValid()) { // string comment = trail.GenerateTag(); bool isModified = mTrader.Modify( trail.ticket, trail.after, iPosition.tp, comment // ); if (isModified) { // RemoveTrail(trail.ticket); // AddSLTrail(trail); // string message = "Position (" + ToString(trail.ticket) + ") Trailed SL on Level: " + ToString(trail.level); mAlert.Alert(message); } } } } // // When Position in Drawdown Trail TP ... if (profit < 0) { // if (iPosition.profit < 0) { // XTrail trail; bool isTrailedBefore = GetTPTrail( iPosition.ticket, trail // ); // if (!isTrailedBefore) { // // Add First Time ... // // Check Position Age ... int iPositionAge = iPosition.GetAge(iPosition.period); if (iPositionAge < requiredAgeForTrail) { continue; } // // Check Position Profit Distance ... double priceDistanceInPoint = PriceToPoint(MathAbs(iPosition.profit) / iPosition.volume, iPosition.symbol); double priceDistance = PointToPrice(priceDistanceInPoint, iPosition.symbol); if (priceDistance < requiredDistanceForTrail) { continue; } // double tpDiff = PointToPrice(priceDistance, iPosition.symbol); double appliedTP = tpDiff / 2; // double tp = IsLong(iPosition.type) ? iPosition.tp - appliedTP : iPosition.tp + appliedTP; // bool isInit = trail.Init( iPosition.ticket, iPosition.type, iPosition.profit, iPosition.tp, tp // ); if (!isInit) { continue; } } else { // // Update Exists ... // if (trail.level >= maxTrailTPs) { continue; } // // Check Profit ... bool isProfitPassed = MathAbs(iPosition.profit) > MathAbs(trail.profit); if (!isProfitPassed) { continue; } // // Check Age Distance from Last ... int age = iBarShift( iPosition.symbol, iPosition.period, trail.time, false // ); if (age < requiredAgeForTrail) { continue; } // double priceDistanceInPoint = PriceToPoint((MathAbs(iPosition.profit) - MathAbs(trail.profit)) / iPosition.volume, iPosition.symbol); double priceDistance = PointToPrice(priceDistanceInPoint, iPosition.symbol); // bool isLong = IsLong(iPosition.type); // double tpDiff = PointToPrice(priceDistance, iPosition.symbol); double appliedTP = tpDiff / 2; // double tp = isLong ? iPosition.tp - appliedTP : iPosition.tp + appliedTP; // // Update Trail Values ... bool isUpdated = trail.Update( tp, iPosition.profit // ); if (!isUpdated) { continue; } } // if (trail.IsValid()) { // string comment = trail.GenerateTag(); bool isModified = mTrader.Modify( trail.ticket, iPosition.sl, trail.after, comment // ); if (isModified) { // RemoveTrail(trail.ticket); // AddTPTrail(trail); // string message = "Position (" + ToString(trail.ticket) + ") Trailed TP on Level: " + ToString(trail.level); mAlert.Alert(message); } } } } } } } // // Here we Can Filter Signals before Sending them to Execution ... // based on Providers and etc ... // for Volumes and Benefits ... int HandleSignalManagement(XSignal &signals[]) override { // // TODO: Make this Configurable ... int minDistanceBetweenTwoSameProviderSignal = 7; // int result = 0; // if (ArraySize(signals) <= 0) { return result; } // // Create temp Array for Filtering ... XSignal tmps[]; Copy( signals, tmps // ); int tmpsCount = ArraySize(tmps); // // Cleaning Source ... Clean(signals); // XSignal mEQMManaged[]; // // Loop through Signals for Management ... for (int i = 0; i < tmpsCount; i++) { // XSignal iSignal = tmps[i]; // // dont Manage NON Signal Provider's signals ... string provider = iSignal.provider; bool canIgnore = !IsValid(provider) || provider == "EQM"; if (canIgnore) { // AddRef( iSignal, signals // ); // continue; } // XPosition positions[]; int positionsCount = mTrader.GetPositions( positions, iSignal.symbol, iSignal.provider, NULL, // All Periods ... iSignal.type // ); XPosition symbolPositions[]; int symbolPositionsCount = mTrader.GetPositions( positions, iSignal.symbol, NULL, // All Providers ... NULL, // All Periods ... iSignal.type // ); double profit = CalculatePositionsProfit(positions); double symbolProfit = CalculatePositionsProfit(symbolPositions); if (positionsCount <= 0) { // // First Signal in a While of Specific Provider ... // AddRef( iSignal, signals // ); // continue; } // else if (positionsCount < GetMaxAllowedPositions()) { // // Next Signal in a While of Specific Provider ... // AddRef( iSignal, signals // ); // continue; } // else { // AddRef( iSignal, mEQMManaged // ); } // else if (profit > 0 && symbolProfit > 0) // { // // // AddRef( // iSignal, // signals // // ); // } } // if (IsValidSize(ArraySize(mEQMManaged))) { HandleEQMState(mEQMManaged); } // result = ArraySize(signals); // return result; } // // Request for Support Signals using Guard ... bool RequestForSupport( XSignal &support, // Holds Support Signal, if Provided string provider, // Positions Provided by Specific Provider string symbol, // Trading Symbol ENUM_POSITION_TYPE type, // Trading Type ENUM_TIMEFRAMES period // Specified Time Frame ) override { // // TODO: Implement this ... // // Support Senario ... // Check Support Position Exists or not ... // Check Positions for Support based on Types ... // Update Untriggered Positions ... return false; } // // Tools ... // // Management Tracker/Profit etc ... // // Handle Position Changed Event ... void OnPositionsChangedHandler(int count) override { // // Synchronize Tracker ... SyncPositionTracker(); } // // Called when a Position Going in Profit ... void OnPositionGoingInProfit(XPositionTrack &track) override { // string message = "Position (" + ToString(track.ticket) + ", " + track.symbol + ") Dropped in Profit ..."; // mAlert.Alert(message); } // // Called when a Position Going to Drawdown ... void OnPositionGoingToDrawdown(XPositionTrack &track) override { // string message = "Position (" + ToString(track.ticket) + ", " + track.symbol + ") Dropped in Drawdown ..."; // mAlert.Alert(message); // XPosition position; bool isRecieved = mTrader.GetPosition( track.ticket, position // ); if (!isRecieved) { return; } // XSignal signals[]; // XSignal signal; bool isPrepared = signal.PrepareOpposit(position); if (!isPrepared) { return; } // signal.comment = ""; signal.provider = XEQMSupportToken; // AddRef( signal, signals // ); // HandleEQMState(signals); } // // Called when Account Going in Profit ... void OnGoingToProfit(XProfitTrack &track) override { // string message = "Account In Profit ..."; // mAlert.Alert(message); // RemoveEQMOrders(); } // // Called when Account Going in Drawdown ... void OnGoingToDrawdown(XProfitTrack &track) override { // string message = "Account In Drawdown ..."; // mAlert.Alert(message); // // Here i Have to Detect In DrawDown Positions ... // RemoveEQMOrders(); // string mSymbols[]; XSCPositionHolder *mHolders[]; int symbolsCount = FilterSymbolBasedPositions( mSymbols, mHolders // ); // for (int i = 0; i < symbolsCount; i++) { // string iSymbol = mSymbols[i]; XSCPositionHolder *iHolder = mHolders[i]; // XPosition iMaxInDP; bool hasMaxInDP = iHolder.GetMaxInDrawdown(iMaxInDP); if (!hasMaxInDP) { continue; } // // Try to Protect a Position ... ProtectPosition(iMaxInDP); } } // void ManageUnExecutedSignals( ENUM_X_SIGNAL_EXECUTION_RESULT &states[], XSignal &unExecutedSignals[] // ) override { // XSignal filteredSignals[]; // int unExecutedSignalsCount = ArraySize(unExecutedSignals); if (!IsValidSize(unExecutedSignalsCount)) { return; } // for (int i = 0; i < unExecutedSignalsCount; i++) { // ENUM_X_SIGNAL_EXECUTION_RESULT iState = states[i]; bool isStateValid = // iState == X_SIGNAL_EXECUTION_FAILED_NO_EQUITY || iState == X_SIGNAL_EXECUTION_FAILED_MAX_REACHED // ; if (!isStateValid) { continue; } // AddRef( unExecutedSignals[i], filteredSignals // ); } // int filteredSignalsCount = ArraySize(filteredSignals); if (!IsValidSize(filteredSignalsCount)) { return; } // HandleEQMState(filteredSignals); } // // Protected ... protected: // // Tools ... // void NotifyX121OnSignalEventHandlers(X121ProviderDescriptor &descriptor) { // int listenersCount = ArraySize(mX121OnSignalEventHandlers); if (listenersCount <= 0) { return; } // for (int i = 0; i < listenersCount; i++) { // TX121OnSignal iListener = mX121OnSignalEventHandlers[i]; // iListener(descriptor); } } // // Protect Specified Position ... void ProtectPosition(XPosition &position) { // // Here i Can Protect Position ... // This Protect Include One Position in Market Mode ... // If Provided ... // the Positions Selection must passed Some conditions ... // string message = "For (" + position.symbol + ") Max In Drawdown Position is: (" + ToString(position.ticket) + "), by Profit: " + ToString(position.profit); // mAlert.Alert(message); } // // Private ... private: // // Props ... // // Collection of Signal Event Listeners ... TX121OnSignal mX121OnSignalEventHandlers[]; // // a Collection of X5 Provider Descriptors ... X121ProviderDescriptor mDescriptors[]; // int CountDescriptors() { return ArraySize(mDescriptors); } // // Find Specifc Descriptor ... int FindDescriptorIndex( string symbol, ENUM_TIMEFRAMES period // ) { // int result = -1; // if (!IsValid(symbol) || !IsValid(period)) { return result; } // int descriptorsCount = CountDescriptors(); if (!IsValidSize(descriptorsCount)) { return result; } // for (int i = 0; i < descriptorsCount; i++) { // X121ProviderDescriptor iDescriptor = mDescriptors[i]; // bool isPassed = // iDescriptor.symbol == symbol && iDescriptor.period == period // ; if (isPassed) { // result = i; break; } } // return result; } template int FindDescriptorIndex( T &item // ) { return FindDescriptorIndex( item.symbol, item.period // ); } // // Trails Holding ... // XTrail mSLTrails[]; XTrail mTPTrails[]; // int CountSLTrails() { return ArraySize(mSLTrails); } int CountTPTrails() { return ArraySize(mTPTrails); } // bool RemoveTrail(ulong ticket) { // bool isSLRemoved = RemoveSLTrail(ticket); bool isTPRemoved = RemoveTPTrail(ticket); // bool result = isSLRemoved || isTPRemoved; // return result; } bool RemoveSLTrail(ulong ticket) { // bool result = false; // int idx = FindSLTrailIndex(ticket); result = idx >= 0; if (!result) { return result; } // result = ArrayRemove( mSLTrails, idx, 1 // ); // return result; } bool RemoveTPTrail(ulong ticket) { // bool result = false; // int idx = FindTPTrailIndex(ticket); result = idx >= 0; if (!result) { return result; } // result = ArrayRemove( mTPTrails, idx, 1 // ); // return result; } // int FindSLTrailIndex(ulong ticket) { // int result = -1; // int trailsCount = CountSLTrails(); if (ticket <= 0 || trailsCount <= 0) { return result; } // for (int i = 0; i < trailsCount; i++) { // XTrail iTrail = mSLTrails[i]; // if (iTrail.ticket == ticket) { // result = i; break; } } // return result; } int FindTPTrailIndex(ulong ticket) { // int result = -1; // int trailsCount = CountTPTrails(); if (ticket <= 0 || trailsCount <= 0) { return result; } // for (int i = 0; i < trailsCount; i++) { // XTrail iTrail = mTPTrails[i]; // if (iTrail.ticket == ticket) { // result = i; break; } } // return result; } // bool GetSLTrail( ulong ticket, XTrail &trail // ) { // bool result = false; // int idx = FindSLTrailIndex(ticket); result = idx >= 0; if (!result) { return result; } // trail = mSLTrails[idx]; // return result; } bool GetTPTrail( ulong ticket, XTrail &trail // ) { // bool result = false; // int idx = FindTPTrailIndex(ticket); result = idx >= 0; if (!result) { return result; } // trail = mTPTrails[idx]; // return result; } // void AddSLTrail( XTrail &trail // ) { // if (!trail.IsValid()) { return; } // AddRef( trail, mSLTrails // ); } void AddTPTrail( XTrail &trail // ) { // if (!trail.IsValid()) { return; } // AddRef( trail, mTPTrails // ); } // // Tools ... }; // // Tools ... //