/////////////////////////////////////////////////////// // // 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 // // 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, 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() override { // bool result = false; // int requiredAgeForSLTrail = 10; int requiredDistanceForSLTrail = 10; // XPosition positions[]; int positionsCount = mTrader.GetPositions(positions); if (positionsCount <= 0) { return result; } // // Trail Positions Stop ... for (int i = 0; i < positionsCount; i++) { // XPosition iPosition = positions[i]; // // Position Management for X786 ... if (iPosition.provider == ToString(X786) || iPosition.provider == ToString(X121)) { // // Check Position in Profit or not ... if (iPosition.profit > 0) { // XTrail trail; bool isTrailedBefore = GetTrail( iPosition.ticket, trail // ); // if (!isTrailedBefore) { // // Add First Time ... // // Check Position Age ... int iPositionAge = iPosition.GetAge(iPosition.period); if (iPositionAge < requiredAgeForSLTrail) { continue; } // // Check Position Profit Distance ... double priceDistanceInPoint = PriceToPoint(iPosition.profit / iPosition.volume, iPosition.symbol); double priceDistance = PointToPrice(priceDistanceInPoint, iPosition.symbol); if (priceDistance < requiredDistanceForSLTrail) { continue; } // double slDiff = PointToPrice(priceDistance, iPosition.symbol); // double sl = IsLong(iPosition.type) ? iPosition.sl + slDiff : iPosition.sl - slDiff; // 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 < requiredAgeForSLTrail) { continue; } // double priceDistanceInPoint = PriceToPoint((iPosition.profit - trail.profit) / iPosition.volume, iPosition.symbol); double priceDistance = PointToPrice(priceDistanceInPoint, iPosition.symbol); if (priceDistance < requiredDistanceForSLTrail) { // // int positionAge = iPosition.GetAge(iPosition.period); if (trail.level >= 3) { // string comment = "EQM Close In Profit ..."; bool isClosed = mTrader.Close( iPosition.ticket, comment // ); if (isClosed) { // RemoveTrail(iPosition.ticket); // string message = "EQM Close (" + ToString(iPosition.ticket) + ") In Profit ..."; mAlert.Alert(message); } } continue; } // double slDiff = PointToPrice(priceDistance, iPosition.symbol); // double sl = IsLong(iPosition.type) ? iPosition.sl + slDiff : iPosition.sl - slDiff; // // 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); // AddTrail(trail); // string message = "Position (" + ToString(trail.ticket) + ") Trailed SL on Level: " + ToString(trail.level); mAlert.Alert(message); } } } } } // // Must false ... 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 ... return false; } // // Tools ... // // 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); } } // // Private ... private: // // Props ... // // Collection of Signal Event Listeners ... TX121OnSignal mX121OnSignalEventHandlers[]; // // a Collection of X5 Provider Descriptors ... X121ProviderDescriptor mDescriptors[]; // int CountDescriptors() { return ArraySize(mDescriptors); } // // Trails Holding ... // XTrail mTrails[]; // int CountTrails() { return ArraySize(mTrails); } // bool RemoveTrail(ulong ticket) { // bool result = false; // int idx = FindTrailIndex(ticket); result = idx >= 0; if (!result) { return result; } // result = ArrayRemove( mTrails, idx, 1 // ); // return result; } // int FindTrailIndex(ulong ticket) { // int result = -1; // int trailsCount = CountTrails(); if (ticket <= 0 || trailsCount <= 0) { return result; } // for (int i = 0; i < trailsCount; i++) { // XTrail iTrail = mTrails[i]; // if (iTrail.ticket == ticket) { // result = i; break; } } // return result; } // bool GetTrail( ulong ticket, XTrail &trail // ) { // bool result = false; // int idx = FindTrailIndex(ticket); result = idx >= 0; if (!result) { return result; } // trail = mTrails[idx]; // return result; } // void AddTrail( XTrail &trail // ) { // if (!trail.IsValid()) { return; } // AddRef( trail, mTrails // ); } // // Tools ... }; // // Tools ... //