/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class Library // ---------------------------------------------- // Name: XSCBaseEA // Description: provides all Base EA 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 #include "../Classes/x-saherelm.xalert.class.mq5" #include "../Classes/x-saherelm.xtrade.class.mq5" // // Define On Signal Event Handler Type ... typedef void (*TOnSignal)(XSignal &signals[]); // // Tokens ... string XINProfitToken = "INP"; string XINDrawdownToken = "IND"; string XProfitsToken = "PFS"; string XTimesToken = "TMS"; string XPricessToken = "PCS"; // enum ENUM_X_PROFIT_TRACK_FIELDS { X_PROFIT_TRACK_PROFIT, X_PROFIT_TRACK_LONGS_PROFIT, X_PROFIT_TRACK_SHORTS_PROFIT, }; // // Model Account Profits ... struct XProfitTrack { // int longs; // Number of Long ... int shorts; // Number of Short ... // double profit; // Profit of All ... double longsProfit; // Profits of Longs ... double shortsProfit; // Profits of Shorts ... // double profitFrom; // Profit of All ... double longsProfitFrom; // Profits of Longs ... double shortsProfitFrom; // Profits of Shorts ... // double volume; // Volume ... double longsVolume; // Volume of Longs ... double shortsVolume; // Volume of Shorts ... // datetime time; // Check Time ... // XProfitTrack() { Clean(); } // // Tools ... // // Initialization ... bool Init(XSCTrade *mTrader) { // bool result = false; // XPosition positions[]; int positionsCount = mTrader.GetPositions(positions); result = positionsCount > 0; if (!result) { return result; } // for (int i = 0; i < positionsCount; i++) { // XPosition iPosition = positions[i]; // bool isLong = IsLong(iPosition.type); // if (isLong) { // longs++; longsVolume += iPosition.volume; longsProfit += iPosition.profit; } else { // shorts++; shortsVolume += iPosition.volume; shortsProfit += iPosition.profit; } // profit += iPosition.profit; volume += iPosition.volume; } // result = IsValid(); if (result) { time = TimeCurrent(); } // return result; } // double SelectField(ENUM_X_PROFIT_TRACK_FIELDS field) { // double result = profit; // switch (field) { // case X_PROFIT_TRACK_LONGS_PROFIT: result = longsProfit; break; // case X_PROFIT_TRACK_SHORTS_PROFIT: result = shortsProfit; break; // default: case X_PROFIT_TRACK_PROFIT: result = profit; break; } // return result; } // // Cleanup ... void Clean() { // longs = 0; shorts = 0; profit = 0; volume = 0; profitFrom = 0; longsVolume = 0; longsProfit = 0; shortsVolume = 0; shortsProfit = 0; longsProfitFrom = 0; shortsProfitFrom = 0; // time = NULL; } // // Validate ... bool IsValid() { // bool result = false; // result = // (longs > 0 || shorts > 0) // && // volume > 0 // ; // return result; } // }; // // Track Specific Position ... struct XPositionTrack { // ulong ticket; // Position Ticket string symbol; // Position Symbol ENUM_POSITION_TYPE type; // Position Type ENUM_TIMEFRAMES period; // Position Period // double price[]; // Check Price ... double profit[]; // Check Profit ... datetime time[]; // Check Time ... // double tp; // Current TP double sl; // Current SL double volume; // Current Volume double entry; // Position Entry datetime openAt; // Position Open Time // int inProfitCount; // Number of Cross in DrawDown int inDrawdownCount; // Number of Crossed in Profit // // Constructor ... XPositionTrack() { Clean(); } // // Tools ... // // Initialization ... bool Init( XPosition &position // Source Position ) { // bool result = false; // Clean(); // result = position.IsValid(); if (!result) { return result; } // ticket = position.ticket; symbol = position.symbol; period = position.period; type = position.type; tp = position.tp; sl = position.sl; entry = position.entry; volume = position.volume; openAt = position.openAt; // datetime cTime = TimeCurrent(); Add( cTime, time // ); // Add( position.profit, profit // ); // Add( position.price, price // ); // result = IsValid(); // return result; } // bool Update( XPosition &position // Source Position ) { // bool result = false; // // Check Current Model is Valid or not ... result = IsValid(); if (!result) { return result; } // // Check Position is a Valid Model ... result = position.IsValid(); if (!result) { return result; } // // Check Current Model belongs to Given Position ... result = // entry == position.entry && openAt == position.openAt && symbol == position.symbol && period == position.period && type == position.type && ticket == position.ticket // ; if (!result) { return result; } // tp = position.tp; sl = position.sl; volume = position.volume; // datetime cTime = TimeCurrent(); // SetArrayStates(false); // Add( cTime, time // ); // Add( position.profit, profit // ); // Add( position.price, price // ); // SetArrayStates(true); // result = IsValid(); if (!result) { return result; } // // Fill In Profit or Drawdown Counters ... // bool isCrossInProfit = IsCrossedInProfit(); if (isCrossInProfit) { inProfitCount++; } // bool isCrossedInDrawdown = IsCrossedInDrawdown(); if (isCrossedInDrawdown) { inDrawdownCount++; } // return result; } // // Cleanup ... void Clean() { // ticket = 0; type = NULL; symbol = NULL; period = NULL; // tp = 0; sl = 0; volume = 0; entry = 0; openAt = NULL; // inProfitCount = 0; inDrawdownCount = 0; // Clean(price); Clean(profit); Clean(time); } // // Validate ... bool IsValid() { // bool result = false; // result = // ticket > 0 && type != NULL && period != NULL && volume > 0 && entry > 0 && openAt > 0 // ; // return result; } // void SetArrayStates(bool state) { // ArraySetAsSeries(price, state); ArraySetAsSeries(profit, state); ArraySetAsSeries(time, state); } // bool IsCrossedInProfit() { // bool result = false; // result = IsValid(); if (!result) { return result; } // result = ArraySize(time) > 1; if (!result) { return result; } // result = // profit[0] > 0 && profit[1] < 0 // ; // return result; } // bool IsCrossedInDrawdown() { // bool result = false; // result = IsValid(); if (!result) { return result; } // result = ArraySize(time) > 1; if (!result) { return result; } // result = // profit[0] < 0 && profit[1] > 0 // ; // return result; } // // Collector Tools ... // string GetToken() { return GetToken(this); } // bool IsModelValid() { return IsValid(); } // bool IsSameAs(XPositionTrack &track) { // bool result = false; // result = // track.IsValid() && type == track.type && ticket == track.ticket && symbol == track.symbol && period == track.period && openAt == track.openAt // ; // return result; } // int FindIndex( const XPositionTrack &values[] // Collection ) { // return FindIndex( this, values // ); } // // Converts a Model to String Representation ... string ToModelString() { // string result = NULL; // if (!IsValid()) { return result; } // // For Modeling a PositionTrack Object ... // - tp // - sl // - type // - entry // - ticket // - symbol // - period // - openAt // - volume // - inProfitCount // - inDrawdownCount // - time[] // - price[] // - profit[] // // Ticket ... string ticketStr = Surround(XIDToken, ticket); // // Symbol ... string SymbolStr = Surround(XSymbolToken, symbol); // // Type ... string typeStr = Surround(XTypeToken, type); // // Period ... int iPeriodInt = (int)period; string periodStr = Surround(XPeriodToken, iPeriodInt); // // TP ... string tpStr = Surround(XTPToken, tp); // // SL ... string slStr = Surround(XSLToken, sl); // // Volume ... string volumeStr = Surround(XVolumeToken, volume); // // Entry ... string entryStr = Surround(XEntryToken, entry); // // OpenAt ... string timeStr = Surround(XTimeToken, openAt); // // InProfitCount ... string inProfitCountStr = Surround(XINProfitToken, inProfitCount); // // InDrawdownCount ... string inDrawdownCountStr = Surround(XINDrawdownToken, inDrawdownCount); // // Time(s) ... string timesContentStr = ToString(time); string timesStr = Surround(XTimesToken, timesContentStr); // // Price(s) ... string pricesContentStr = ToString(price); string pricesStr = Surround(XPricessToken, pricesContentStr); // // Profit(s) ... string profitsContentStr = ToString(profit); string profitsStr = Surround(XProfitsToken, profitsContentStr); // string token = GetToken(); // result = // token + "[" + // ticketStr + SymbolStr + typeStr + periodStr + tpStr + slStr + volumeStr + entryStr + timeStr + inProfitCountStr + inDrawdownCountStr + timesStr + pricesStr + profitsStr + // "]" // ; // return result; } // // Pres and Fill Model based on it's String Representation ... bool ParseModel(string value) { // bool result = false; // Clean(); // result = IsValid(value); if (!result) { return result; } // // For Modeling a PositionTrack Object ... // - tp // - sl // - type // - entry // - ticket // - symbol // - period // - openAt // - volume // - inProfitCount // - inDrawdownCount // - time[] // - price[] // - profit[] // // TP ... tp = ParseDoubleSurrounded(value, XTPToken); // // SL ... tp = ParseDoubleSurrounded(value, XSLToken); // // Type ... type = ((ENUM_POSITION_TYPE)ParseIntSurrounded(value, XTypeToken)); // // Entry ... entry = ParseDoubleSurrounded(value, XEntryToken); // // Ticket ... ticket = ParseLongSurrounded(value, XIDToken); // // Symbol ... symbol = ParseStringSurrounded(value, XSymbolToken); // // Period ... period = ((ENUM_TIMEFRAMES)ParseIntSurrounded(value, XPeriodToken)); // // Open At ... openAt = ParseTimeSurrounded(value, XTimeToken); // // Volume ... volume = ParseDoubleSurrounded(value, XVolumeToken); // // InProfitCount ... inProfitCount = ParseIntSurrounded(value, XINProfitToken); // // InDrawdownCount ... inDrawdownCount = ParseIntSurrounded(value, XINDrawdownToken); // // Time(s) ... ParseTimeArraySurrounded( time, value, XTimesToken // ); // // Price(s) ... ParseDoubleArraySurrounded( price, value, XPricessToken // ); // // Profit(s) ... ParseDoubleArraySurrounded( profit, value, XProfitsToken // ); // result = IsValid(); // return result; } }; // // Type Definitions for XPosition Tracker Events ... typedef void (*TOnPositionState)(const XPositionTrack &track); // class XSCPositionHolder { // // Public ... public: // // Props ... // // Constructor(s) ... // XSCPositionHolder() { Clear(); } // // Tools ... // // Cleanup ... void Clear() { Clean(mItems); } // bool AddItem(XPosition &item) { // bool result = false; // result = item.IsValid(); if (!result) { return result; } // result = !HasItem(item); if (!result) { return result; } // AddRef( item, mItems // ); // return result; } // int AddItems(XPosition &items[]) { // int result = 0; // int itemsCount = ArraySize(items); if (itemsCount <= 0) { return result; } // for (int i = 0; i < itemsCount; i++) { // XPosition iItem = items[i]; // bool isAdded = AddItem(iItem); if (isAdded) { result++; } } // return result; } // bool AddOrUpdateItem(XPosition &item) { // bool result = false; // result = item.IsValid(); if (!result) { return result; } // bool hasItem = HasItem(item); if (!hasItem) { result = AddItem(item); } else { // result = RemoveItem(item); if (result) { result = AddItem(item); } } // return result; } // int AddOrUpdateItem(XPosition &items[]) { // int result = 0; // int itemsCount = ArraySize(items); if (itemsCount <= 0) { return result; } // for (int i = 0; i < itemsCount; i++) { // XPosition iItem = items[i]; // bool isAddOrUpdated = AddOrUpdateItem(iItem); if (isAddOrUpdated) { result++; } } // return result; } // bool HasItem(XPosition &item) { // bool result = false; // int itemIDX = FindItem(item); result = itemIDX >= 0; // return result; } // int FindItem(XPosition &item) { // int result = -1; // if (!item.IsValid()) { return result; } // int itemsCount = CountItems(); if (itemsCount <= 0) { return result; } // for (int i = 0; i < itemsCount; i++) { // XPosition iItem = mItems[i]; // bool isSame = IsItemSameAs(item, iItem); if (isSame) { // result = i; break; } } // return result; } // bool GetByIndex( int index, XPosition &item // ) { // bool result = false; // NormalizeIndex( index, mItems // ); // item = mItems[index]; // result = item.IsValid(); // return result; } // bool RemoveItem(XPosition &item) { // bool result = false; // result = HasItem(item); if (!result) { return result; } // int itemIDX = FindItem(item); result = ArrayRemove( mItems, itemIDX, 1 // ); // return result; } // int RemoveItems(XPosition &items[]) { // int result = 0; // int itemsCount = ArraySize(items); if (itemsCount <= 0) { return result; } // for (int i = 0; i < itemsCount; i++) { // XPosition iItem = items[i]; // bool isRemoved = RemoveItem(iItem); if (isRemoved) { result++; } } // return result; } // int CountItems() { return ArraySize(mItems); } // bool IsItemSameAs( XPosition &source, XPosition &dest // Compare Source with this ... ) { // bool result = false; // result = // dest.IsValid() && source.IsValid() && source.symbol == dest.symbol && source.period == dest.period && source.ticket == dest.ticket && source.openAt == dest.openAt && source.provider == dest.provider // ; // return result; } // // Custom Functions ... // bool GetMaxInDrawdown( XPosition &item // Result ) { // bool result = false; // item.Clean(); // int itemsCount = CountItems(); result = IsValidSize(itemsCount); if (!result) { return result; } // int maxIDX = -1; for (int i = 0; i < itemsCount; i++) { // XPosition iItem = mItems[i]; // bool canSelect = // iItem.profit < 0 // && // ( // (maxIDX == -1 && !item.IsValid()) ? true : item.profit < iItem.profit // ) // ; if (canSelect) { // maxIDX = i; item = iItem; } } // result = maxIDX > -1 && item.IsValid(); // return result; } // bool GetMaxInProfit( XPosition &item // Result ) { // bool result = false; // item.Clean(); // int itemsCount = CountItems(); result = IsValidSize(itemsCount); if (!result) { return result; } // int maxIDX = -1; for (int i = 0; i < itemsCount; i++) { // XPosition iItem = mItems[i]; // bool canSelect = // iItem.profit > 0 // && // ( // (maxIDX == -1 && !item.IsValid()) ? true : item.profit < iItem.profit // ) // ; if (canSelect) { // maxIDX = i; item = iItem; } } // result = maxIDX > -1 && item.IsValid(); // return result; } // bool GetFarestEntry( XPosition &item, // Result string symbol = NULL, string provider = NULL, ENUM_TIMEFRAMES period = NULL, ENUM_X_POSITION_TYPE type = NULL // ) { // bool result = false; // item.Clean(); // int itemsCount = CountItems(); result = IsValidSize(itemsCount); if (!result) { return result; } // for (int i = 0; i < itemsCount; i++) { // XPosition iItem = mItems[i]; // bool isFiltersPassed = // iItem.IsFiltersPassed( symbol, provider, period, type // ) // ; // if (!isFiltersPassed) { continue; } // // Do Additional Filtering ... bool isValidEntry = // !item.IsValid() ? true : item.entry < iItem.entry // ; if (isValidEntry) { // item = iItem; } } // result = item.IsValid(); // return result; } // bool GetNearestEntry( XPosition &item, // Result string symbol = NULL, string provider = NULL, ENUM_TIMEFRAMES period = NULL, ENUM_X_POSITION_TYPE type = NULL // ) { // bool result = false; // item.Clean(); // int itemsCount = CountItems(); result = IsValidSize(itemsCount); if (!result) { return result; } // for (int i = 0; i < itemsCount; i++) { // XPosition iItem = mItems[i]; // bool isFiltersPassed = // iItem.IsFiltersPassed( symbol, provider, period, type // ) // ; // if (!isFiltersPassed) { continue; } // // Do Additional Filtering ... bool isValidEntry = // !item.IsValid() ? true : item.entry > iItem.entry // ; if (isValidEntry) { // item = iItem; } } // result = item.IsValid(); // return result; } // bool GetFarestSL( XPosition &item, // Result string symbol = NULL, string provider = NULL, ENUM_TIMEFRAMES period = NULL, ENUM_X_POSITION_TYPE type = NULL // ) { // bool result = false; // item.Clean(); // int itemsCount = CountItems(); result = IsValidSize(itemsCount); if (!result) { return result; } // for (int i = 0; i < itemsCount; i++) { // XPosition iItem = mItems[i]; // bool isFiltersPassed = // iItem.IsFiltersPassed( symbol, provider, period, type // ) // ; // if (!isFiltersPassed) { continue; } // // Do Additional Filtering ... bool isValidEntry = // !item.IsValid() ? true : item.sl < iItem.sl // ; if (isValidEntry) { // item = iItem; } } // result = item.IsValid(); // return result; } // bool GetNearestSL( XPosition &item, // Result string symbol = NULL, string provider = NULL, ENUM_TIMEFRAMES period = NULL, ENUM_X_POSITION_TYPE type = NULL // ) { // bool result = false; // item.Clean(); // int itemsCount = CountItems(); result = IsValidSize(itemsCount); if (!result) { return result; } // for (int i = 0; i < itemsCount; i++) { // XPosition iItem = mItems[i]; // bool isFiltersPassed = // iItem.IsFiltersPassed( symbol, provider, period, type // ) // ; // if (!isFiltersPassed) { continue; } // // Do Additional Filtering ... bool isValidEntry = // !item.IsValid() ? true : item.sl > iItem.sl // ; if (isValidEntry) { // item = iItem; } } // result = item.IsValid(); // return result; } // bool GetFarestTP( XPosition &item, // Result string symbol = NULL, string provider = NULL, ENUM_TIMEFRAMES period = NULL, ENUM_X_POSITION_TYPE type = NULL // ) { // bool result = false; // item.Clean(); // int itemsCount = CountItems(); result = IsValidSize(itemsCount); if (!result) { return result; } // for (int i = 0; i < itemsCount; i++) { // XPosition iItem = mItems[i]; // bool isFiltersPassed = // iItem.IsFiltersPassed( symbol, provider, period, type // ) // ; // if (!isFiltersPassed) { continue; } // // Do Additional Filtering ... bool isValidEntry = // !item.IsValid() ? true : item.tp < iItem.tp // ; if (isValidEntry) { // item = iItem; } } // result = item.IsValid(); // return result; } // bool GetNearestTP( XPosition &item, // Result string symbol = NULL, string provider = NULL, ENUM_TIMEFRAMES period = NULL, ENUM_X_POSITION_TYPE type = NULL // ) { // bool result = false; // item.Clean(); // int itemsCount = CountItems(); result = IsValidSize(itemsCount); if (!result) { return result; } // for (int i = 0; i < itemsCount; i++) { // XPosition iItem = mItems[i]; // bool isFiltersPassed = // iItem.IsFiltersPassed( symbol, provider, period, type // ) // ; // if (!isFiltersPassed) { continue; } // // Do Additional Filtering ... bool isValidEntry = // !item.IsValid() ? true : item.tp > iItem.tp // ; if (isValidEntry) { // item = iItem; } } // result = item.IsValid(); // return result; } // // Private ... private: // // Props ... XPosition mItems[]; }; // // Class Definition ... class XSCBaseEA : public XSCBaseAlert { // // Public ... public: // // Props ... // // Constructor ... XSCBaseEA( // // XTrade Class Requirements ... int slippage, // Specify Slippage ulong magicNumber, // Specify Magic Number // // 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 ) { // // Instance XSCTrade Class ... mTrader = new XSCTrade( slippage, magicNumber // ); // mIsInTestMode = IsRunningOnTestMode(); // // Set Event Handlers ... mOnStopLossTriggered = onStopLossTriggered; mOnTakeProfitTriggered = onTakeProfitTriggered; mOnDealsChangedHandler = onDealsChangedHandler; mOnOrdersChangedHandler = onOrdersChangedHandler; mOnPositionsChangedHandler = onPositionsChangedHandler; mOnTradeStateChangedHandler = onTradeStateChangedHandler; // // Add Event Listeners to XTrade Class if they Provided ... if (mOnStopLossTriggered != NULL) { mTrader.AddOnStopLossEventHandler(mOnStopLossTriggered); } // if (mOnTakeProfitTriggered != NULL) { mTrader.AddOnTakeProfitEventHandler(mOnTakeProfitTriggered); } // if (mOnDealsChangedHandler != NULL) { mTrader.AddOnDealsChangedEventHandler(mOnDealsChangedHandler); } // if (mOnOrdersChangedHandler != NULL) { mTrader.AddOnOrdersChangedEventHandler(mOnOrdersChangedHandler); } // if (mOnPositionsChangedHandler != NULL) { mTrader.AddOnPositionsChangedEventHandler(mOnPositionsChangedHandler); } // if (mOnTradeStateChangedHandler != NULL) { mTrader.AddOnTradeStateChangedEventHandler(mOnTradeStateChangedHandler); } } // // Deconstractor ... ~XSCBaseEA() { // delete mTrader; } // // Properties Getter(s) / Setter(s) ... // // Retrieve Slippage ... int GetSlippage() { return mTrader.GetSlippage(); } // // Retrieve Magic Number ... ulong GetMagicNumber() { return mTrader.GetMagicNumber(); } // // Overrides ... // // Customize Token ... virtual string GetToken() { return GetSpecificToken(this); } // virtual string GetTag() { return this.GetToken(); } // // Virtual Functions ... // // Handle Chart Events ... virtual void OnChartEvent( const int id, // event ID const long &lparam, // long type event parameter const double &dparam, // double type event parameter const string &sparam // string type event parameter ) { } // // OnTick Handler ... virtual void OnTick() { // // Draw ... Draw(); // // Check Trade Events ... OnTrade(); // HandleProfitManageMent(); // // First Check For Any Guard Actions ... // then Handle Guards if Provided ... XGuard guards[]; bool hasGuard = CheckForGuard(guards); if (hasGuard) { DoGuards(guards); } // XSignal signals[]; // // Second Check for Position Management or Equity Management // Actions like Supports or etc ... bool isIgnored = HandleStateManagement(signals); if (isIgnored) { return; } // // Second Check For Signals ... // then Execute Signals if Provided ... int signalsCount = RequestForSignal(signals); if (signalsCount <= 0) { return; } // // Execute Signals ... HandleSignalsExecution(signals); } // // Handle StopLoss Event ... virtual void OnStopLossTriggered(const XDeal &deal) {} // // Handle TakeProfit Event ... virtual void OnTakeProfitTriggered(const XDeal &deal) {} // // Handle Deals Changed Event ... virtual void OnDealsChangedHandler(int count) {} // // Handle Order Changed Event ... virtual void OnOrdersChangedHandler(int count) {} // // Handle Position Changed Event ... virtual void OnPositionsChangedHandler(int count) {} // // Handle Trade State Changed ... virtual void OnTradeStateChangedHandler(const XOnTradeHandlerState &state) {} // // Handle On Trade ... virtual void OnTrade() { // XOnTradeHandlerState state = mTrader.HandleOnTrade(); // if ( !state.hasNewDeal && !state.hasNewOrder && !state.hasNewPosition && !state.hasNewHistoryOrder) { return; } // // STATE ... // // Notfy Trade State Changed Event ... OnTradeStateChangedHandler(state); // // DEALS ... if (state.hasNewDeal) { // // Notfy Deals Changed Event ... OnDealsChangedHandler(state.newDeals); // // Retrieve Last Deal ... XDeal deals[]; mTrader.GetDeals(deals); int dealsCount = ArraySize(deals); if (dealsCount > 0) { // XDeal lastDeal = deals[0]; // if (lastDeal.reason == DEAL_REASON_TP) { OnTakeProfitTriggered(lastDeal); } else if (lastDeal.reason == DEAL_REASON_SL) { OnStopLossTriggered(lastDeal); } } } // // ORDERS ... if (state.hasNewOrder || state.hasNewHistoryOrder) { // // Notfy Orders Changed Event ... OnOrdersChangedHandler(state.newOrders + state.newHistoryOrders); } // // POSITIONS ... if (state.hasNewPosition) { // // Notfy Positions Changed Event ... OnPositionsChangedHandler(state.newPositions); } } // // Retrieve Dept Of Market ... virtual void OnBookEvent(const string &symbol) { // // TODO: Implement this ... } // // Draw On Chart if anything is required ... virtual void Draw() {} // // Check For any Guard Actions ... virtual bool CheckForGuard(XGuard &guards[]) { return false; } // // When a Guard Notified to Do Support Signal ... // this Method Calls For Retrieve Support Signal ... // if it's Provided, Execute it ... virtual bool RequestForSupport( XSignal &support, // Holds Support Signal, if Provided string provider, // Positions Provided by Specific Provider string symbol, // Trading Symbol ENUM_X_POSITION_TYPE type, // Trading Type ENUM_TIMEFRAMES period // Specified Time Frame ) { return false; } // // Handle Position(s)/ Order(s) or EQM Supporting Action ... // if returns true, prevent for process Tick ... virtual bool HandleStateManagement(XSignal &signals[]) { return false; } // // Regulary Filtered Signals passed to this // and here we can do Additional Signal Filtering // for Signal Management such as (Providers and etc) ... virtual int HandleSignalManagement(XSignal &signals[]) { // int result = ArraySize(signals); // return result; } // // Here we Have to Check Market based // on our Strategy for Trading ... // and if a Good Entry founded ... // model it as an XSignal struct and passed it to result ... virtual int RequestForSignal( XSignal &signals[] // Holds Signals ... ) { return 0; } // // When Some Errors happens in Executing Signals ... virtual void ManageUnExecutedSignals( ENUM_X_SIGNAL_EXECUTION_RESULT &states[], XSignal &unExecutedSignals[] // ) { } // // Execute Provided Signals ... virtual void HandleSignalsExecution(XSignal &signals[]) { // int signalsCount = ArraySize(signals); if (signalsCount <= 0) { return; } // int managedSignalsCount = HandleSignalManagement(signals); if (managedSignalsCount <= 0) { return; } // // Try to Execute Signals ... XSignal notExecuteds[]; ENUM_X_SIGNAL_EXECUTION_RESULT reasons[]; int executedSignalsCount = mTrader.ExecuteSpecifiedSignals( signals, notExecuteds, // Not Executed Signals reasons // ); // string message = NULL; if (executedSignalsCount == 0) { // message = "(" + ToString(managedSignalsCount) + ") Signals Execution Failed ..."; // for (int j = 0; j < ArraySize(reasons); j++) { // string iReason = ToString(reasons[j]); // message += "\n" + ToString(j) + ": " + iReason; } } else if (executedSignalsCount < managedSignalsCount) { // int diff = managedSignalsCount - executedSignalsCount; // message = "Failed to Execute (" + ToString(diff) + ") Signals ..."; } else if (executedSignalsCount == managedSignalsCount) { message = "(" + ToString(executedSignalsCount) + ") Signals Executed Successfully ..."; } // if (ArraySize(notExecuteds) > 0) { // ManageUnExecutedSignals( reasons, notExecuteds // ); } // if (IsValid(message)) { mAlert.Alert(message); } } // virtual void OnGoingToProfit(XProfitTrack &track) {} virtual void OnLongsGoingToProfit(XProfitTrack &track) {} virtual void OnShortsGoingToProfit(XProfitTrack &track) {} // virtual void OnGoingToDrawdown(XProfitTrack &track) {} virtual void OnLongsGoingToDrawdown(XProfitTrack &track) {} virtual void OnShortsGoingToDrawdown(XProfitTrack &track) {} // virtual void OnPositionGoingInProfit(XPositionTrack &track) {} virtual void OnPositionGoingToDrawdown(XPositionTrack &track) {} // // Protected ... protected: // // Props ... // // Trade Class Instance ... XSCTrade *mTrader; // // Check in Test Mode or not ... bool mIsInTestMode; // // Tools ... // // Signal Event Listeners ... void NotifyOnSignalEventHandlers(XSignal &signals[]) { // int listenersCount = ArraySize(mOnSignalEventHandlers); if (listenersCount <= 0) { return; } // for (int i = 0; i < listenersCount; i++) { // TOnSignal iListener = mOnSignalEventHandlers[i]; // iListener(signals); } } // // Profit Tracker ... // XProfitTrack mProfitTracks[]; // bool GetProfitTrack( XProfitTrack &track, int index = 0 // ) { // bool result = false; // if (index < 0) { index = 0; } // int tracksCount = CountProfitTracks(); result = tracksCount > 0 && index < tracksCount; if (!result) { return result; } // track.Clean(); // track = mProfitTracks[index]; // result = track.IsValid(); // return result; } // int CountProfitTracks() { return ArraySize(mProfitTracks); } // void AddProfitTrack() { // XProfitTrack track; bool isValid = track.Init(mTrader); if (!isValid) { return; } // ArraySetAsSeries(mProfitTracks, false); // AddRef( track, mProfitTracks // ); // ArraySetAsSeries(mProfitTracks, true); } // // Extract Specified Field Vales of XProfit Track Struct ... int ExtractProfitTrackField( double &result[], ENUM_X_PROFIT_TRACK_FIELDS field, int start = 0, int count = 10 // ) { // Clean(result); // if (start < 0) { start = 0; } // int end = start + count; // int tracksCount = CountProfitTracks(); if (end > tracksCount) { end = tracksCount; } // for (int i = start; i < end; i++) { // XProfitTrack iTrack; bool isValid = GetProfitTrack( iTrack, i // ); // if (!isValid) { continue; } // double iValue = iTrack.SelectField(field); Add( iValue, result // ); } // int mResult = ArraySize(result); // return mResult; } // double AverageProfitTrackField( ENUM_X_PROFIT_TRACK_FIELDS field, int start = 0, int count = 10 // ) { // double result = EMPTY_VALUE; // double items[]; int itemsCount = ExtractProfitTrackField( items, field, start, count // ); if (itemsCount <= 0) { return result; } // result = GetAverage(items); // return result; } // bool IsProfitTrackFieldIncreasing( ENUM_X_PROFIT_TRACK_FIELDS field, int start = 0, int count = 10 // ) { // bool result = false; // double items[]; int itemsCount = ExtractProfitTrackField( items, field, start, count // ); if (itemsCount <= 0) { return result; } // int from = itemsCount - 1; int to = 0; // result = IsIncreasing( from, to, items // ); // return result; } // bool IsProfitTrackFieldDecreasing( ENUM_X_PROFIT_TRACK_FIELDS field, int start = 0, int count = 10 // ) { // bool result = false; // double items[]; int itemsCount = ExtractProfitTrackField( items, field, start, count // ); if (itemsCount <= 0) { return result; } // int from = itemsCount - 1; int to = 0; // result = IsDecreasing( from, to, items // ); // return result; } // void HandleProfitManageMent() { // // Check Tracking Interval ... // static datetime lastProfitTracked = NULL; datetime cTime = TimeCurrent(); // int profitManagementInterval = PeriodSeconds(PERIOD_M5); int timeDiff = (int)cTime - (int)lastProfitTracked; // bool canManage = // lastProfitTracked == NULL ? true : timeDiff >= profitManagementInterval // ; if (!canManage) { return; } // XPosition positions[]; int positionsCount = mTrader.GetPositions(positions); if (!IsValidSize(positionsCount)) { // Clean(mProfitTracks); return; } // lastProfitTracked = cTime; // // Do Track ... // AddProfitTrack(); // int profitsCount = CountProfitTracks(); if (profitsCount <= 1) { return; } // XProfitTrack cT; bool isValid = GetProfitTrack( cT, 0 // ); if (!isValid) { return; } // XProfitTrack pT; isValid = GetProfitTrack( pT, 1 // ); if (!isValid) { return; } // cT.profitFrom = pT.profit; cT.longsProfitFrom = pT.longsProfit; cT.shortsProfitFrom = pT.shortsProfit; // bool isGoningToProfit = // cT.profit > 0 && pT.profit <= 0 // ; if (isGoningToProfit) { // OnGoingToProfit(cT); } // bool isLongsGoningToProfit = // cT.longsProfit > 0 && pT.longsProfit <= 0 // ; if (isLongsGoningToProfit) { OnLongsGoingToProfit(cT); } // bool isShortsGoningToProfit = // cT.shortsProfit > 0 && pT.shortsProfit <= 0 // ; if (isShortsGoningToProfit) { OnShortsGoingToProfit(cT); } // bool isGoningToDrawdown = // cT.profit < 0 && pT.profit >= 0 // ; if (isGoningToDrawdown) { OnGoingToDrawdown(cT); } bool isLongsGoningToDrawdown = // cT.longsProfit < 0 && pT.longsProfit >= 0 // ; if (isLongsGoningToDrawdown) { OnLongsGoingToDrawdown(cT); } bool isShortsGoningToDrawdown = // cT.shortsProfit < 0 && pT.shortsProfit >= 0 // ; if (isShortsGoningToDrawdown) { OnShortsGoingToDrawdown(cT); } } // // Guards ... // // Do All Provided Guards ... void DoGuards(XGuard &guards[]) { // int guardsCount = ArraySize(guards); if (guardsCount <= 0) { return; } // for (int i = 0; i < guardsCount; i++) { // XGuard iGuard = guards[i]; // switch (iGuard.action) { // // Hedge In Profit Specified Positions ... case X_GUARD_ACTION_HEDGE: HandleGuardHedgeAction( iGuard.provider, iGuard.symbol, iGuard.type, iGuard.period); break; // // Trail Stop Loss in Specified Positions ... case X_GUARD_ACTION_TRAIL_STOP: HandleGuardTrailingStopAction( iGuard.provider, iGuard.symbol, iGuard.type, iGuard.period, iGuard.dblPayLoad); break; // // Force Close Specified Positions ... case X_GUARD_ACTION_FORCE_CLOSE: HandleGuardForceCloseAction( iGuard.provider, iGuard.symbol, iGuard.type, iGuard.period); break; // // Generate and Place Support Signals ... case X_GUARD_ACTION_ADD_SUPPORT_SIGNAL: HandleGuardAddSupportPositionAction( iGuard.provider, iGuard.symbol, iGuard.type, iGuard.period); break; // // Delete All Placed Pending Orders ... case X_GUARD_ACTION_CANCEL_PENDING_ORDERS: HandleGuardCancelPendingOrdersAction( iGuard.provider, iGuard.symbol, iGuard.type, iGuard.period); break; } } } // // Close All Specified Provider's Positions in Profit Summary ... void HandleGuardHedgeAction( string provider, // Positions Provided by Specific Provider string symbol, // Trading Symbol ENUM_X_POSITION_TYPE type, // Trading Type ENUM_TIMEFRAMES period, // Specified Time Frame double minProfitForHedging = 1, // Specified Profit for Hedge double minProfitForHedgingVolumeFactor = 0.01 // Specified Volume Factor for Hedge ) { // XPosition positions[]; int positionsCount = mTrader .GetPositions( positions, symbol, provider, period, type // ); if (positionsCount <= 1) { return; } // double profit = SpecifiedCalculatePositionsProfit(positions); double requiredProfit = SpecifiedCalculateRequiredProfitForHedge( positions, minProfitForHedging, minProfitForHedgingVolumeFactor // ); // bool isReadyForHedge = profit >= requiredProfit; if (!isReadyForHedge) { return; } // string comment = "Guard Hedge " + provider; int closed = mTrader.Close( positions, comment // ); if (closed > 0) { // string message = "Guard Hedge " + provider + "'s Positions on Profit: " + ToString(profit); // mAlert.Alert(message); } } // // Close Max In Profit Trade Guard Action ... void HandleGuardCloseInProfitAction( string provider, // Positions Provided by Specific Provider string symbol, // Trading Symbol ENUM_X_POSITION_TYPE type, // Trading Type ENUM_TIMEFRAMES period, // Specified Time Frame ENUM_X_POSITION_SELECT_METHODS method = NULL // Select Method ) { // XPosition positions[]; int positionsCount = mTrader .GetInProfitPositions( positions, symbol, provider, period, type, method // ); if (positionsCount <= 0) { return; } // string comment = "Close InProfit ..."; mTrader.Close( positions, comment // ); // string message = "Guard Close (" + ToString(positionsCount) + ") Postion(s) In Profit ..."; // mAlert.Alert(message); } // // Close Max In Drawdown Trade Guard Action ... void HandleGuardCloseInDrawdownAction( string provider, // Positions Provided by Specific Provider string symbol, // Trading Symbol ENUM_X_POSITION_TYPE type, // Trading Type ENUM_TIMEFRAMES period, // Specified Time Frame ENUM_X_POSITION_SELECT_METHODS method = NULL // Select Method ) { // XPosition positions[]; int positionsCount = mTrader .GetInDrawdownPositions( positions, symbol, provider, period, type, method // ); if (positionsCount <= 0) { return; } // string comment = "Close InDrawdown ..."; mTrader.Close( positions, comment // ); // string message = "Guard Close (" + ToString(positionsCount) + ") Position(s) In Drawdown ..."; // mAlert.Alert(message); } // // Force Close Specified Set Of Position ... void HandleGuardForceCloseAction( string provider, // Positions Provided by Specific Provider string symbol, // Trading Symbol ENUM_X_POSITION_TYPE type, // Trading Type ENUM_TIMEFRAMES period, // Specified Time Frame ulong ticket = 0 // Specific Ticket ) { // string comment = ""; // // Close All Positions ... if (ticket == 0) { // XPosition positions[]; int positionsCount = mTrader.GetPositions( positions, symbol, provider, period, type // ); if (positionsCount <= 0) { return; } // comment = provider + " Force Close Guard ..."; // mTrader.Close( positions, comment // ); } // // Close Specific Position ... else { // XPosition position; bool hasPosition = mTrader .GetPosition( ticket, position // ); // if (hasPosition) { // comment = provider + "(" + ToString(ticket) + ")" + " Force Close Guard ..."; // mTrader.Close( ticket, comment // ); } } // if (IsValid(comment)) { mAlert.Alert(comment); } } // // Trailing Specified Set Of Positions Stop Losses ... void HandleGuardTrailingStopAction( string provider, // Positions Provided by Specific Provider string symbol, // Trading Symbol ENUM_X_POSITION_TYPE type, // Trading Type ENUM_TIMEFRAMES period, // Specified Time Frame double sl // Desired SL Value ... ) { // if (sl <= 0) { return; } // NormalizePrice( sl, symbol // ); // XPosition positions[]; int positionsCount = mTrader .GetPositions( positions, symbol, provider, period, type // ); if (positionsCount <= 0) { return; } // int modified = 0; for (int i = 0; i < positionsCount; i++) { // XPosition iPosition = positions[i]; // string comment = PrepareSLTrailTag(iPosition.comment); // if (iPosition.sl == sl) { continue; } // bool isModified = mTrader.Modify( iPosition.ticket, sl, iPosition.tp, comment); if (isModified) { modified++; } } // if (modified > 0) { // string message = "(" + ToString(modified) + ") Position's Stop Trailed Successfully ..."; // mAlert.Alert(message); } } // // Add Support Signal for Specified Positions ... void HandleGuardAddSupportPositionAction( string provider, // Positions Provided by Specific Provider string symbol, // Trading Symbol ENUM_X_POSITION_TYPE type, // Trading Type ENUM_TIMEFRAMES period // Specified Time Frame ) { // XSignal support; bool hasSupport = RequestForSupport( support, provider, symbol, type, period // ); // if (!hasSupport || !support.IsValid()) { return; } // // TODO: May be need to add Support Tag to comments ... // ENUM_X_SIGNAL_EXECUTION_RESULT reason = NULL; bool isExecuted = mTrader.ExecuteSignal( support, reason); // string comment = NULL; if (!isExecuted) { comment = "Support Execution Failed doue " + ToString(reason); } else { comment = "Guard Support Signal Executed Successfully ..."; } // if (IsValid(comment)) { mAlert.Alert(comment); } } // // Cancel all Placed Orders ... void HandleGuardCancelPendingOrdersAction( string provider, // Positions Provided by Specific Provider string symbol, // Trading Symbol ENUM_X_POSITION_TYPE type, // Trading Type ENUM_TIMEFRAMES period // Specified Time Frame ) { // XOrder orders[]; int ordersCount = mTrader.GetOrders( orders, symbol, provider, period, type, ORDER_STATE_PLACED, true // Filter by Magic ... // ); if (ordersCount <= 0) { return; } // int canceledOrdersCount = mTrader.CancelOrders(orders); // if (canceledOrdersCount > 0) { // string message = "Guard Cancel (" + ToString(canceledOrdersCount) + ") Pending Orders ..."; // mAlert.Alert(message); } } // // Position Filter ... // int FilterSymbolBasedPositions( string &symbols[], // Hold Symbols ... XSCPositionHolder *&holders[] // Holder Class Instances ... ) { // int result = 0; // XPosition positions[]; int positionsCount = mTrader.GetPositions( positions // ); if (!IsValidSize(positionsCount)) { return result; } // // Create a HashMap for Holding Positions ... CHashMap symbolMap; // // Loop Through Positions ... for (int i = 0; i < positionsCount; i++) { // XPosition iPosition = positions[i]; // bool hasIKey = symbolMap.ContainsKey(iPosition.symbol); // // Empty Class Pointer ... XSCPositionHolder *mHolder = NULL; // // Add new to Map ... if (!hasIKey) { // mHolder = new XSCPositionHolder(); if (symbolMap.TrySetValue(iPosition.symbol, mHolder)) { mHolder.AddOrUpdateItem(iPosition); } } // // Update Exists in Map ... else { // if (symbolMap.TryGetValue(iPosition.symbol, mHolder)) { mHolder.AddOrUpdateItem(iPosition); } } } // // Now we Have a Map which Filled Based on Separate Symbols and InDrawDown Positions ... int mapCount = symbolMap.Count(); if (!IsValidSize(mapCount)) { return result; } // result = symbolMap.CopyTo( symbols, holders // ); // return result; } // // Private ... private: // // Props ... // // Signal Event Listeners ... TOnSignal mOnSignalEventHandlers[]; // // Event Handlers ... TOnStopLoss mOnStopLossTriggered; TOnTakeProfit mOnTakeProfitTriggered; TOnDealsChanged mOnDealsChangedHandler; TOnOrdersChanged mOnOrdersChangedHandler; TOnPositionsChanged mOnPositionsChangedHandler; TOnTradeStateChanged mOnTradeStateChangedHandler; }; //