/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class Library // ---------------------------------------------- // Name: XCTarget // Description: provides all Positions Target requirements ... // // // 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.base.class.mq5" #include "../Classes/x-saherelm.x-trade.class.mq5" // // Implementation ... class XCTarget : public XCBase { // // Public ... public: // XCTrade *trader; XCAlert *alert; XSignal signals[]; // // Constructor ... XCTarget( XCTrade *_trader, // XCAlert *_alert // ) : XCBase() { // alert = _alert; trader = _trader; // XClean(signals); } // // Deconstructor ... ~XCTarget() { Destroy(); } // void Destroy() { // XClean(signals); } // // Actions ... /** * Manage Positions ... * * @param barIndex: int, Bar Index ... */ void Manage(int barIndex = 0) { // // Normalize ... barIndex = NormalizeInt(barIndex, 0); // // Extract In Profit Positions ... XPosition positions[]; int count = GetInProfitPositions(positions); bool has = IsValidIndex(count); if (!has) { return; } // XSignal iSignal; XTarget iTarget; int signalIDX = -1; int targetIDX = -1; XPosition iPosition; // // Loop through Positions ... for (int i = 0; i < count; i++) { // // Select Positions ... iPosition = positions[i]; has = FindSignal( signalIDX, iPosition.ticket // ); if (!has) { continue; } iSignal = signals[signalIDX]; // // Selecting Target ... targetIDX = iSignal.appliedTargetIDX; if (iSignal.isTargetApplied) { targetIDX++; } // // Validate Targets Size ... has = HasChild(iSignal.targets) && targetIDX < ArraySize(iSignal.targets); if (has) { // // Select Target ... iTarget = iSignal.targets[targetIDX]; // // Check Can Apply Target and Apply it ... has = HandleApplyTarget(iTarget, iPosition); if (has) { // // Update Target IDX ... iSignal.appliedTargetIDX++; } } // // Update Signal ... signals[signalIDX] = iSignal; // // Cleanup ... iSignal.Clean(); iTarget.Clean(); iPosition.Clean(); } // // Cleanup Resources ... iSignal.Clean(); iTarget.Clean(); iPosition.Clean(); } /** * Extract in Profit Positions ... * * @param positions: XPosition, reference collection to holds result ... * * @return ( int ) */ int GetInProfitPositions( XPosition &positions[] // ) { // int result = 0; // // Prepare ... XClean(positions); // // Validate ... if (trader == NULL) { return result; } // result = trader.GetInProfitPositions( positions, NULL, // All Symbols ... NULL, // All Providers ... NULL, // All Periods ... NULL, // All Position Types ... X_POSITION_SELECT_ALL, // Select Method ... true, // Filter by Magic ... true // Force Clean ... ); if (IsValidSize(result)) { // XPosition iPos; XPosition tmp[]; Copy( positions, tmp // ); XClean(positions); while (HasChild(tmp)) { // iPos = tmp[0]; ArrayRemove( tmp, 0, 1 // ); // int idx = -1; bool has = FindSignal( idx, iPos.ticket // ); if (has) { // AddRef( iPos, positions // ); } } // XClean(tmp); iPos.Clean(); // result = ArraySize(positions); } // return result; } /** * Add Executed Signal ... * * @param signal: XSignal, reference to Executed Signal ... */ void AddExecutedSignal(XSignal &signal) { // // Validate ... if (!signal.IsValid() || !signal.IsExecuted()) { return; } // AddRef( signal, signals // ); } // // Trade Event Handlers ... /** * Handle Stop Loss Event Triggered ... * * @param deal: XDeal instance refrence, provides Triggered Deal info ... */ void HandleOnStopLossTriggered(const XDeal &deal) { RemoveSignal(deal.positionId); } /** * Handle Take Profit Event Triggered ... * * @param deal: XDeal instance refrence, provides Triggered Deal info ... */ void HandleOnTakeProfitTriggered(const XDeal &deal) { RemoveSignal(deal.positionId); } /** * Handle Position Force Closed Event ... * * @param ticket: ulong, triggered Positions ticket ... * @param position: XPosition instance refrence, Triggered Position ... * @param comment: string, Comment ... */ void HandleOnPositionForceClosed( const ulong ticket, const XPosition &position, const string comment // ) { RemoveSignal(ticket); } // // Event Handlers Registration ... // void AddOnStopLossEventHandler(TOnStopLoss handler) { // if (handler == NULL) { return; } // Add( handler, mStopLossEventHandlers // ); } // void AddOnTakeProfitEventHandler(TOnTakeProfit handler) { // if (handler == NULL) { return; } // Add( handler, mTakeProfitEventHandlers // ); } // void AddOnForceClosePositionEventHandler(TOnForceClose handler) { // if (handler == NULL) { return; } // Add( handler, mOnForceCloseEventHandlers // ); } // // Protected ... protected: // /** * Find Specified Signal ... * * @param index: int, reference to holds detected index ... * @param signal: XSignal, reference to Specified Signal ... * * @return ( bool ) */ bool FindSignal( int &index, XSignal &signal // ) { // bool result = false; // // Prepare ... index = -1; // // Validate ... result = signal.IsValid() && HasChild(signals); if (!result) { return result; } // // Looping Through Signals ... int count = ArraySize(signals); for (int i = 0; i < count; i++) { // result = signals[i] .IsSameAs(signal); if (result) { // index = i; break; } } // result = IsValidIndex(index); // return result; } /** * Find Specified Signal ... * * @param index: int, reference to holds detected index ... * @param ticket: ulong, Specified Signal Position ID ... * * @return ( bool ) */ bool FindSignal( int &index, ulong ticket // ) { // bool result = false; // // Prepare ... index = -1; // // Validate ... result = NotEmptyZero(ticket) && HasChild(signals); if (!result) { return result; } // // Looping Through Signals ... int count = ArraySize(signals); for (int i = 0; i < count; i++) { // result = signals[i].IsValid() && signals[i].IsExecuted() && signals[i].positionId == ticket; if (result) { // index = i; break; } } // result = IsValidIndex(index); // return result; } /** * Remove Specified Signal ... * * @param ticket: ulong, Specified Ticket ... */ void RemoveSignal(ulong ticket) { // bool has = NotEmptyZero(ticket) && HasChild(signals); if (!has) { return; } // int idx = -1; has = FindSignal( idx, ticket // ); if (!has) { return; } // ArrayRemove( signals, idx, 1 // ); } /** * Check Can Apply Specified Target on Specified Position or not ... * * @param target: XTarget, reference to Specified Target for Apply ... * @param position: XPosition, reference to Specified Position ... * * @return ( bool ) */ bool CanApplyTarget( XTarget &target, XPosition &position // ) { // bool result = false; // // Validate ... result = target.IsValid() && position.IsValid(); if (!result) { return result; } // // Check Price Reached Targets Value and Distance ... double targetDistance = (target.actingDistance > 0 ? target.actingDistance : 0) * position.GetPointsValue(); result = IsLong(position.type) ? position.price >= target.target + targetDistance : position.price <= target.target - targetDistance; // return result; } /** * Apply Specified Target on Specified Position ... * * @param target: XTarget, reference to Specified Target for Apply ... * @param position: XPosition, reference to Specified Position ... * * @return ( bool ) */ bool HandleApplyTarget( XTarget &target, XPosition &position // ) { // bool result = false; // // Validate ... result = target.IsValid() && position.IsValid() && CanApplyTarget( target, position // ); if (!result) { return result; } // // Apply Target ... string comment = NULL; string message = NULL; // // Do Risk Free if Provided ... if (target.doRF) { // comment = "Taregt Manager do RF ..."; result = trader.Modify( position.ticket, target.target, // SL ... position.tp, // TP ... comment // ); // // Handle Alert ... message = "Target Manager do RF " + ToXString(position.type) + " Position (" + ToXString(position.ticket) + ") on: " + ToXString(position.price); alert.SendAlert(message); } // // Do Partial Close if Provided ... if (result && target.volumeMultiplier > 0) { // double volume = NormalizeVolume((position.volume * target.volumeMultiplier), position.symbol); if (volume != position.volume) { // comment = "Target Manager do Partial Close ..."; result = trader.ClosePartial( position.ticket, volume, comment // ); // // Handle Alert ... message = "Target Manager do Partial Close " + ToXString(position.type) + " Position (" + ToXString(position.ticket) + ") by: " + ToXString(volume); alert.SendAlert(message); } } // return result; } // // Private ... private: // // // Required Event Handlers ... TOnStopLoss mStopLossEventHandlers[]; TOnTakeProfit mTakeProfitEventHandlers[]; TOnForceClose mOnForceCloseEventHandlers[]; }; //