/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class Library // ---------------------------------------------- // Name: X121SCTradeHandler // Description: provides all Trade Handling 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.xtrade.class.mq5" #include "../Parsers/x-saherelm.x121.parser.mq5" // // Definitions ... // // an Structure for Holding Positions Data ... struct X121TradeData { // datetime time; // Issue Time (Open Position) string symbol; // Trading Symbol double entry; // Entry Price double volume; // Volume string provider; // Signaller ENUM_TIMEFRAMES period; // Trading Timeframe ENUM_X_POSITION_TYPES type; // Position Type // ulong ticket; // Position Ticket double swap; // Swap double profit; // Profit on Close double commission; // Commission double maxDrawdown; // Max Position Drawdown string message; // Close Reason datetime endTime; // End Time // XSignal signal; // Signal Object int pushers; // Signal Pushers string conditions; // Signal Conditions // int trailStep; // Trail Step bool partiallyClosed; // Partially Closed or not datetime lastProtectedOn; // Last Protected On // // Constructor ... void XTradeInfo() { Clean(); } // // Filling Trade Handler ... bool Fill(XSignal &_signal) { // bool result = false; // Clean(); // // Check Signal Validation ... result = _signal.IsValid(); if (!result) { return result; } // signal = _signal; time = _signal.time; entry = _signal.entry; symbol = _signal.symbol; volume = _signal.volume; period = _signal.period; pushers = _signal.pushers; provider = _signal.provider; conditions = _signal.conditions; type = ToPositionType(_signal.type); // if (_signal.IsExecuted()) { ticket = _signal.positionId; } // return result; } // // Filling Trade Handler ... bool Fill(XPosition &_position) { // bool result = false; // Clean(); // // Check Signal Validation ... result = _position.IsValid(); if (!result) { return result; } // time = _position.openAt; symbol = _position.symbol; entry = _position.entry; volume = _position.volume; provider = _position.provider; period = _position.period; type = ToPositionType(_position.type); // ticket = _position.ticket; // return result; } // // Update Data ... bool Update(XPosition &_position) { // bool result = false; // result = _position.IsValid(); if (!result) { return result; } // profit = _position.profit; swap = _position.swap; // if (profit < 0 && (maxDrawdown == 0 || MathAbs(profit) > MathAbs(maxDrawdown))) { maxDrawdown = profit; } // return result; } // // Tools ... // // Cleanup ... void Clean() { // time = NULL; type = NULL; symbol = NULL; period = NULL; endTime = NULL; message = NULL; provider = NULL; // swap = 0; entry = 0; ticket = 0; profit = 0; volume = 0; commission = 0; maxDrawdown = 0; // trailStep = 0; lastProtectedOn = NULL; partiallyClosed = false; // signal.Clean(); } // // Validation ... bool IsValid() { // bool result = false; // result = // ticket > 0 && IsValid(time) && IsValid(symbol) && IsValid(period) // ; // return result; } // // Retrieve Trade Data Age ... int GetAge() { // int result = -1; // if (!IsValid(symbol) || !IsValid(time) || !IsValid(endTime) || !IsValid(period)) { return result; } // int startIndex = iBarShift( symbol, period, time, false // ); // int endIndex = iBarShift( symbol, period, endTime, false // ); // result = MathAbs(startIndex - endIndex); // return result; } // // Check Own of Trade Data ... // based on Ticket ... bool IsOwn( ulong _ticket // ) { // bool result = false; // result = _ticket == ticket; // return result; } // // Check Own of Trade Data ... // based on Symbol/Provider and Period ... bool IsOwn( string _symbol, string _provider, ENUM_TIMEFRAMES _period, ENUM_X_POSITION_TYPES _type // ) { // bool result = false; // result = // IsValid(_symbol) && IsValid(_period) && IsValid(_provider) && type != X_POSITION_TYPE_ALL && type != X_POSITION_TYPE_NONE && // type == _type && period == _period && symbol == _symbol && provider == _provider // ; // return result; } // // Data Collector ... // // Get Data File Name ... string GetFileName() { // string result = NULL; // if (!IsValid()) { return result; } // result = // symbol + "\\" + ToString(type) + "\\" + (profit >= 0 ? "Profit" : "Loss") + "\\" + ToString(ticket) + "_" + ToString(period) + "_" + ToFormatString(time) // ; // return result; } // // Get Signal File Name ... string GetSignalFileName() { // string result = NULL; // result = // symbol + "\\" + ToString(type) + "\\" + provider + "_" + ToFormatString(time) // ; // return result; } // // Convert(s) To String Representation(s) ... string ToString( bool onlySignals = false // ) { // string result = NULL; // int age = GetAge(); // result = // (onlySignals ? "" : ToString("Ticket", ticket)) + ToString("Symbol", symbol) + ToString("Period", period) + ToString("Entry", entry) + ToString("Provider", provider) + ToString("Type", ToString(type)) + ToString("Time", time) + // // Attach Trade Info ... (onlySignals ? "" : // "-------------" + "\n" + ToString("Volume", volume) + ToString("Profit", profit) + ToString("Commission", commission) + ToString("Swap", swap) + ToString("Max Drawdown", maxDrawdown) + ToString("End Time", endTime) + ToString("Age", age) + ToString("Message", message) + "" // ) + // // Attach Conditions to Signals ... (!onlySignals ? "" : // "-------------" + "\n" + ToString("Pushers", pushers) + "Conditions:" + "\n" + "-------------" + "\n" + conditions + "" // ) + // "" // ; // return result; } // }; // struct XSymbolData { // string symbol; int longSL; int shortSL; datetime disableLong; datetime disableShort; // void XSymbolData() { Clean(); } // void Clean() { // symbol = NULL; longSL = 0; shortSL = 0; disableLong = NULL; disableShort = NULL; } // bool CanLong() { // bool result = false; // datetime cTime = TimeCurrent(); // result = !IsValid(disableLong) || (IsValid(disableLong) && cTime > disableLong); if (result) { disableLong = NULL; } // return result; } // bool CanShort() { // bool result = false; // datetime cTime = TimeCurrent(); // result = !IsValid(disableShort) || (IsValid(disableShort) && cTime > disableShort); if (result) { disableShort = NULL; } // return result; } }; // // Model a Position and it's Protected Positions ... struct XProtectedPosition { // XPosition main; // Main Position ... X121TradeData data; // Trade Handler Data ... // XPosition supports[]; // Support Positions ... /** * Count Supported Positions */ int CountSupports() { return ArraySize(supports); } /** * Extract All Positions into Specified Array * of Positions ... */ int ExtractPositions( XPosition &positions[] // ) { // int result = 0; // Clean(positions); // if (main.IsValid()) { // AddRef( main, positions // ); } // int supportsCount = CountSupports(); if (IsValidSize(supportsCount)) { // Copy( supports, positions, false // ); } // result = ArraySize(positions); // return result; } }; // // Implementation ... // // a Class For Read and Write Trade Info Data in Files ... class X121TradeCollector { // // Public ... public: // // Props ... // // Constructor(s) ... void X121TradeCollector( string _path = NULL // Base Path ) { // mAccount = new XSCAccount(); // if (IsValid(_path)) { mPath = _path; } else { mPath = "X121TradeData" + "\\" + mAccount.GetCompany(); } } // // Deconstructor ... void ~X121TradeCollector() { } // bool IsExists(X121TradeData &item) { // bool result = false; // int mHandler = GetFileHandlerForRead(item); result = mHandler != INVALID_HANDLE; FileClose(mHandler); // return result; } // bool Save(X121TradeData &item) { // bool result = false; // // Check info is Valid ... result = item.IsValid(); if (!result) { return result; } // string content = item.ToString(); content += "\n" + "-----------" + "\n" + "Signal: " + "\n" + "-----------" + "\n" + item.ToString(true); // result = IsValid(content); if (!result) { return result; } // int mHandler = GetFileHandlerForWrite(item); result = mHandler != INVALID_HANDLE; if (!result) { return result; } // FileWrite(mHandler, content); FileFlush(mHandler); FileClose(mHandler); // return result; } // bool SaveSignal(X121TradeData &item) { // bool result = false; // string content = item.ToString(true); result = IsValid(content); if (!result) { return result; } // int mHandler = GetSignalFileHandlerForWrite(item); result = mHandler != INVALID_HANDLE; if (!result) { return result; } // FileWrite(mHandler, content); FileFlush(mHandler); FileClose(mHandler); // return result; } // // Conditions only save for Loss Signals ... // this means the profit must be Lower than Zero ... // ans also message Contains SL ... bool SaveConditions(X121TradeData &item) { // bool result = false; // // Validate Item ... result = // item.profit < 0 && Contains("SL", item.message) // ; if (!result) { return result; } // string content = item.signal.conditions; result = IsValid(content); if (!result) { return result; } // int mHandler = GetConditionsFileHandlerForWrite(item); result = mHandler != INVALID_HANDLE; if (!result) { return result; } // FileSeek(mHandler, 0, SEEK_END); FileWrite(mHandler, content); FileFlush(mHandler); FileClose(mHandler); // return result; } // // Protected ... protected: // // Private ... private: // // Props ... // string mPath; // Base Path ... // XSCAccount *mAccount; // string GetFilePath(X121TradeData &item) { // string fileName = item.GetFileName(); // return GetFilePath(fileName); } string GetFilePath(string fileName) { // string result = ""; // result = // mPath + "\\" + "Trades" + "\\" + fileName + ".x121.log" // ; // return result; } // string GetSignalFilePath(X121TradeData &item) { // string fileName = item.GetSignalFileName(); // return GetSignalFilePath(fileName); } string GetSignalFilePath(string fileName) { // string result = ""; // result = // mPath + "\\" + "Signals" + "\\" + fileName + ".x121.log" // ; // return result; } // string GetConditionsFilePath(X121TradeData &item) { // bool isLong = IsLong(item.type); // string fileName = item.symbol + "\\" + (isLong ? "Longs" : "Shorts"); // return GetConditionsFilePath(fileName); } string GetConditionsFilePath(string fileName) { // string result = ""; // result = // mPath + "\\" + "Conditions" + "\\" + fileName + ".x121.log" // ; // return result; } // int GetFileHandlerForRead(X121TradeData &item) { // int result = INVALID_HANDLE; // string filePath = GetFilePath(item); if (!IsValid(filePath)) { return result; } // result = FileOpen( filePath, FILE_READ | FILE_TXT // ); // return result; } int GetFileHandlerForWrite(X121TradeData &item) { // int result = INVALID_HANDLE; // string filePath = GetFilePath(item); if (!IsValid(filePath)) { return result; } // result = FileOpen( filePath, FILE_READ | FILE_WRITE | FILE_TXT // ); // return result; } // int GetSignalFileHandlerForRead(X121TradeData &item) { // int result = INVALID_HANDLE; // string filePath = GetSignalFilePath(item); if (!IsValid(filePath)) { return result; } // result = FileOpen( filePath, FILE_READ | FILE_TXT // ); // return result; } int GetSignalFileHandlerForWrite(X121TradeData &item) { // int result = INVALID_HANDLE; // string filePath = GetSignalFilePath(item); if (!IsValid(filePath)) { return result; } // result = FileOpen( filePath, FILE_READ | FILE_WRITE | FILE_TXT // ); // return result; } // int GetConditionsFileHandlerForRead(X121TradeData &item) { // int result = INVALID_HANDLE; // string filePath = GetConditionsFilePath(item); if (!IsValid(filePath)) { return result; } // result = FileOpen( filePath, FILE_READ | FILE_TXT // ); // return result; } int GetConditionsFileHandlerForWrite(X121TradeData &item) { // int result = INVALID_HANDLE; // string filePath = GetConditionsFilePath(item); if (!IsValid(filePath)) { return result; } // result = FileOpen( filePath, FILE_READ | FILE_WRITE | FILE_TXT // ); // return result; } }; // // Trade Handler Class ... class X121SCTradeHandler : public XSCBaseAlert { // // Public ... public: // // // Constructor(s) ... void X121SCTradeHandler(XSCTrade *trader) { // mTrader = trader; lastSignalOn = NULL; mAdditionalVolume = 0; mCollector = new X121TradeCollector(); } // // Deconstructor ... void ~X121SCTradeHandler() { // delete mTrader; delete mCollector; } // // Getter(s) / Setter(s) ... // bool SaveSignals() { return mSaveSignals; } // void SaveSignals(bool value) { mSaveSignals = value; } // bool SaveTrades() { return mSaveTrades; } // void SaveTrades(bool value) { mSaveTrades = value; } // bool SaveConditions() { return mSaveConditions; } // void SaveConditions(bool value) { mSaveConditions = value; } // bool AllowLong() { return mAllowLong; } // void AllowLong(bool value) { mAllowLong = value; } // bool AllowShort() { return mAllowShort; } // void AllowShort(bool value) { mAllowShort = value; } // int MaxAllowedLongs() { return mMaxAllowedLongs; } // void MaxAllowedLongs(int value) { // if (value < 0) { value = 0; } // mMaxAllowedLongs = value; } // int MaxAllowedShorts() { return mMaxAllowedShorts; } // void MaxAllowedShorts(int value) { // if (value < 0) { value = 0; } // mMaxAllowedShorts = value; } // bool UseMaxAllowedTradesPerSymbol() { return mUseMaxAllowedTradesPerSymbol; } // void UseMaxAllowedTradesPerSymbol(bool value) { mUseMaxAllowedTradesPerSymbol = value; } // double MaxDrawdownPercentForOpenTrades() { return mMaxDrawdownPercentForOpenTrades; } // void MaxDrawdownPercentForOpenTrades(double value) { // if (value < 0) { value = 0; } // mMaxDrawdownPercentForOpenTrades = value; } // int NumberOfSLForPauseSignalling() { return mNumberOfSLForPauseSignalling; } // void NumberOfSLForPauseSignalling(int value) { // if (value < 0) { value = 0; } // mNumberOfSLForPauseSignalling = value; } // int SignallingPauseDelayInMinute() { return mSignallingPauseDelayInMinute; } // void SignallingPauseDelayInMinute(int value) { // if (value < 0) { value = 0; } // mSignallingPauseDelayInMinute = value; } // // Protector Start ... // bool UseForceMomentumsInProtection() { return mUseForceMomentumsInProtection; } // void UseForceMomentumsInProtection(bool value) { mUseForceMomentumsInProtection = value; } // int DelayBarBetweenTwoSignal() { return mDelayBarBetweenTwoSignal; } // void DelayBarBetweenTwoSignal(int value) { // if (value < 0) { value = 0; } // mDelayBarBetweenTwoSignal = value; } // double AcceptNextSameTypeSignalWhenLastInProfit() { return mAcceptNextSameTypeSignalWhenLastInProfit; } // void AcceptNextSameTypeSignalWhenLastInProfit(double value) { // if (value < 0) { value = 0; } // mAcceptNextSameTypeSignalWhenLastInProfit = value; } // // In Profit Position Protecting ... // // Trail ... // bool AllowTrail() { return mAllowTrail; } // void AllowTrail(bool value) { mAllowTrail = value; } // double TrailStartDistance() { return mTrailStartDistance; } // void TrailStartDistance(double value) { // if (value < 0) { value = 0; } // mTrailStartDistance = value; } // double TrailStep() { return mTrailStep; } // void TrailStep(double value) { // if (value < 0) { value = 0; } // mTrailStep = value; } // int RemoveTPAfterTrailedLevel() { return mRemoveTPAfterTrailedLevel; } // void RemoveTPAfterTrailedLevel(int value) { // if (value < 0) { value = 0; } // mRemoveTPAfterTrailedLevel = value; } // bool OnlyTrailUnprotected() { return mOnlyTrailUnprotected; } // void OnlyTrailUnprotected(bool value) { mOnlyTrailUnprotected = value; } // // Partial Close (In Profit) ... // double PartialCloseInProfitDistance() { return mPartialCloseInProfitDistance; } // void PartialCloseInProfitDistance(double value) { // if (value < 0) { value = 0; } // mPartialCloseInProfitDistance = value; } // double PartialCloseInProfitVolume() { return mPartialCloseInProfitVolume; } // void PartialCloseInProfitVolume(double value) { // if (value < 0) { value = 0; } // mPartialCloseInProfitVolume = value; } // // In Drawdown Positions Protecting ... // // Protect ... // bool AllowProtect() { return mAllowProtect; } // void AllowProtect(bool value) { mAllowProtect = value; } // double ProtectionStartDistance() { return mProtectionStartDistance; } // void ProtectionStartDistance(double value) { // if (value < 0) { value = 0; } // mProtectionStartDistance = value; } // int ProtectionDelay() { return mProtectionDelay; } // void ProtectionDelay(int value) { // if (value < 0) { value = 0; } // mProtectionDelay = value; } // double ProtectionVolumeMultiplier() { return mProtectionVolumeMultiplier; } // void ProtectionVolumeMultiplier(double value) { // if (value < 1) { value = 1; } // mProtectionVolumeMultiplier = value; } // int MaxAllowedProtection() { return mMaxAllowedProtection; } // void MaxAllowedProtection(int value) { // if (value < 0) { value = 0; } // mMaxAllowedProtection = value; } // bool UseEntryAsProtectionSL() { return mUseEntryAsProtectionSL; } // void UseEntryAsProtectionSL(bool value) { mUseEntryAsProtectionSL = value; } // bool ProtectOnConditions() { return mProtectOnConditions; } // void ProtectOnConditions(bool value) { mProtectOnConditions = value; } // bool AllowDirectionProtct() { return mAllowDirectionProtct; } // void AllowDirectionProtct(bool value) { mAllowDirectionProtct = value; } // // Partial Close (In Drawdown) ... // double PartialCloseInDrawdownDistance() { return mPartialCloseInDrawdownDistance; } // void PartialCloseInDrawdownDistance(double value) { // if (value < 0) { value = 0; } // mPartialCloseInDrawdownDistance = value; } // double PartialCloseInDrawdownVolume() { return mPartialCloseInDrawdownVolume; } // void PartialCloseInDrawdownVolume(double value) { // if (value < 0) { value = 0; } // mPartialCloseInDrawdownVolume = value; } // // Hedge Props ... // bool AllowHedge() { return mAllowHedge; } // void AllowHedge(bool value) { mAllowHedge = value; } // double HedgeMinVolumeStep() { return mHedgeMinVolumeStep; } // // Min: 0.01 // Max 0.1 void HedgeMinVolumeStep(double value) { // if (value < 0.01) { value = 0.01; } // if (value > 0.1) { value = 0.1; } // mHedgeMinVolumeStep = value; } // int MinimumOpenPositionsForHEHedge() { return mMinimumOpenPositionsForHEHedge; } // void MinimumOpenPositionsForHEHedge(int value) { // if (value < 0) { value = 0; } // mMinimumOpenPositionsForHEHedge = value; } // double HedgeHEMinProfitPerVolumeStep() { return mHedgeHEMinProfitPerVolumeStep; } // // Min: 0.01 void HedgeHEMinProfitPerVolumeStep(double value) { // if (value < 0.01) { value = 0.01; } // mHedgeHEMinProfitPerVolumeStep = value; } // double HedgeBEMinProfitPerVolumeStep() { return mHedgeBEMinProfitPerVolumeStep; } // // Min: 0.01 void HedgeBEMinProfitPerVolumeStep(double value) { // if (value < 0.01) { value = 0.01; } // mHedgeBEMinProfitPerVolumeStep = value; } // // Read Only Props ... // int MaxSameTimeTrades() { return maxSameTimeTrades; } // // Calculate Max Drawdown and it's Percent ... double GetMaxDrawdown() { // XPosition positions[]; int positionsCount = mTrader.GetPositions(positions); if (IsValidSize(positionsCount)) { double mEquity = mTrader.mAccount.GetEquity(); if (mEquity > maxDrawdown) { maxDrawdown = mEquity; } // drawdownPercent = (maxDrawdown - mEquity) / (staticBalanceForCalculateDrawdown > 0 ? staticBalanceForCalculateDrawdown : maxDrawdown) * 100; drawdownPercent = NormalizeDouble(drawdownPercent, 3); } else { // maxDrawdown = 0.0; drawdownPercent = 0.0; } // return drawdownPercent; } // double AdditionalVolume() { return mAdditionalVolume; } // // Position Retrievers ... /** * Retrieve Positions as XProtetedPosition structure * @param positions: Argument 1 * @return ( int ) */ int GetPositions( XProtectedPosition &positions[] // ) { // int result = 0; // Clean(positions); // // Retrieve Positions from Trader Class ... XPosition allPositions[]; int allPositionsCount = mTrader.GetPositions( allPositions, NULL, // All Symbols ... NULL, // All Providers ... NULL, // All Periods ... X_POSITION_TYPE_ALL, // Long and Short ... false, // Filter By Magic ... true // Force Clean ... ); if (!IsValidSize(allPositionsCount)) { return result; } // // Filter Support Positions ... XPosition mainPositions[]; XPosition supportPositions[]; for (int i = 0; i < allPositionsCount; i++) { // XPosition iPosition = allPositions[i]; // // Check Validation ... if (!iPosition.IsValid()) { continue; } // // Check Position Support or not ... bool isSupport = IsSupport(iPosition.comment); if (isSupport) { // AddRef( iPosition, supportPositions // ); continue; } // AddRef( iPosition, mainPositions // ); } // // Check Main Positions Count ... int mainPositionsCount = ArraySize(mainPositions); if (!IsValidSize(mainPositionsCount)) { return result; } // int supportPositionsCount = ArraySize(supportPositions); // for (int i = 0; i < mainPositionsCount; i++) { // XPosition iPosition = mainPositions[i]; // XProtectedPosition iProtected; iProtected.main = iPosition; Clean(iProtected.supports); // // Loop Through Support Positions To Find iPositions Support ... if (IsValidSize(supportPositionsCount)) { // for (int j = 0; j < supportPositionsCount; j++) { // XPosition jSupport = supportPositions[j]; // ulong supportParentTicket = ExtractSupportedTicket(jSupport.comment); bool isSupport = supportParentTicket > 0; if (isSupport && supportParentTicket == iPosition.ticket) { // AddRef( jSupport, iProtected.supports // ); } // ulong eqmSupportParentTicket = ExtractEQMSupportedTicket(jSupport.comment); bool isEQMSupport = eqmSupportParentTicket > 0; if (isEQMSupport && eqmSupportParentTicket == iPosition.ticket) { // AddRef( jSupport, iProtected.supports // ); } } } // // Findout X121TradeData ... int iIDX = -1; bool hasItem = HasItem( iPosition.ticket, iIDX // ); if (hasItem && IsValidIndex(iIDX)) { iProtected.data = mData[iIDX]; } // AddRef( iProtected, positions // ); } // Clean(allPositions); Clean(mainPositions); Clean(supportPositions); // result = ArraySize(positions); // return result; } // // Trade Handling Functions ... // // First Step of Trade Handling ... // Since Must Call when a Signal Executed ... void AddData( XSignal &signal, // Executed Signal double commission = 0 // Commission ) { // // Check Signal Valid ... if (!signal.IsValid()) { return; } // // Check Signal Support or Recovery ... bool isSupport = IsSupport(signal.comment); bool isRecovery = ExtractRecoveredTicket(signal.comment) > 0; // X121TradeData item; bool isFilled = item.Fill(signal); if (!isFilled) { return; } // item.commission = commission; // Add(item); // SaveSignal(item); } // void Finish(const XDeal &deal) { // int idx = -1; bool hasItem = HasItem( deal.positionId, idx // ); if (!hasItem) { return; } // // Update Item Info ... mData[idx].swap = deal.swap; mData[idx].endTime = deal.time; mData[idx].profit = deal.profit; // mData[idx].message = deal.reason == DEAL_REASON_TP ? "TP" : "SL"; // Save(idx); } // void Finish( const ulong ticket, const XPosition &position, const string comment // ) { // int idx = -1; bool hasItem = HasItem( ticket, idx // ); if (!hasItem) { return; } // // Update Item Info ... mData[idx].swap = position.swap; mData[idx].endTime = TimeCurrent(); mData[idx].profit = position.profit; // mData[idx].message = comment; // Save(idx); } // // this Method call's by a Timer, // or in OnTick for Update Positions, // Data ... void UpdateData() { // XPosition positions[]; int count = mTrader.GetPositions(positions); if (!IsValidSize(count)) { return; } // for (int i = 0; i < count; i++) { // XPosition iPosition = positions[i]; // int idx = -1; bool isExists = HasItem( iPosition.ticket, idx // ); if (!isExists) { // // Add New Data ... // // Find Executed Signal Deal History ... XDeal deals[]; double commission = 0; int dealsCount = mTrader.GetDeals( deals, iPosition.symbol, iPosition.provider, iPosition.period, NULL, DEAL_ENTRY_IN // ); if (IsValidSize(dealsCount)) { // for (int i = 0; i < dealsCount; i++) { // XDeal iDeal = deals[i]; if (iDeal.positionId == iPosition.ticket) { // commission = iDeal.commission; break; } } } // X121TradeData iData; iData.Fill( iPosition // ); // iData.ticket = iPosition.ticket; // Add(iData); } else { // // Update Exists ... mData[idx].Update(iPosition); } } // count = Count(); if (count > maxSameTimeTrades) { maxSameTimeTrades = count; } // GetMaxDrawdown(); } // void UpdateSignal(XSignal &signal) { // if (!signal.IsValid()) { return; } // int count = Count(); if (!IsValidSize(count)) { return; } // for (int i = 0; i < count; i++) { // bool isOwn = mData[i].IsOwn( signal.symbol, signal.provider, signal.period, ToPositionType(signal.type) // ); if (isOwn) { mData[i].Fill(signal); } } } // void RemoveSignal(XSignal &signal) { // if (!signal.IsValid()) { return; } // int signalIDX = -1; ENUM_X_POSITION_TYPES xType = ToPositionType(signal.type); bool hasSignal = HasItem( signal.symbol, signal.provider, signal.period, xType, signalIDX // ); if (!hasSignal || !IsValidIndex(signalIDX)) { return; } // // Remove Item From List ... ArrayRemove( mData, signalIDX, 1 // ); } // // Position Execute and Sync Functions ... /** * Validate Signal For Execution ... */ bool CanExecute(XSignal &signal) { // bool result = false; // // Validate Signal ... result = signal.IsValid(); if (!result) { return result; } // bool isLong = IsLong(signal.type); // // Chekc Signalling Enable or not ... result = isLong ? mAllowLong : mAllowShort; if (!result) { return result; } // // Check Signal is Support or not ... bool isSupport = IsSupport(signal.comment); result = !isSupport; if (!result) { return result; } // ENUM_X_POSITION_TYPES pType = ToPositionType(signal.type); double requiredProfitForAcceptNext = AcceptNextSameTypeSignalWhenLastInProfit(); // // Implement Same Signal Conditions ... XPosition smaeSymbolPositions[]; int sameSymbolPositionsCount = mTrader.GetPositions( smaeSymbolPositions, signal.symbol, signal.provider, signal.period, pType, true, // Filter By Magic ... true // Force Clean ... ); XPosition youngestSame; int youngestSameAge = GetYoungest( youngestSame, smaeSymbolPositions // ); // double youngestSameProfitInPoint = youngestSame.GetProfitInPoint(); // result = sameSymbolPositionsCount == 0 || (sameSymbolPositionsCount <= 0 ? true : requiredProfitForAcceptNext <= 0 ? true : youngestSameAge >= 0 && youngestSameProfitInPoint >= requiredProfitForAcceptNext); if (!result) { return result; } // int symbolIDX = -1; bool hasSymbol = HasSymbol( signal.symbol, symbolIDX // ); if (hasSymbol) { // result = isLong ? mSymbolData[symbolIDX].CanLong() : mSymbolData[symbolIDX].CanShort(); } // return result; } /** * Execute Specific Signal using Trade Handler ... */ bool ExecuteSignal( XSignal &signal, // Signal for Execution ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Execution State X121StrategyConditions &conditions, // Signal Conditions bool ignorePolicies = false // Ignore Execution Policies ) { // state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS; bool result = false; // // Check Signal Validation ... result = signal.IsValid(); if (!result) { return result; } // // Check Policies ... if (!ignorePolicies) { // // Filter Signals if Necessary ... result = CanExecute(signal); if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS; return result; } // bool isLong = IsLong(signal.type); // // Check Allow Trade Type ... result = isLong ? mAllowLong : mAllowShort; if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED; return result; } // // Check Trades Count ... if (mMaxAllowedLongs > 0 || mMaxAllowedShorts > 0) { // XPosition longs[]; XPosition shorts[]; // // Counting Positions ... if (mUseMaxAllowedTradesPerSymbol) { // mTrader.GetPositions( longs, shorts, signal.symbol // ); } else { // mTrader.GetPositions( longs, shorts, NULL // All Symbols ... ); } // int longsCount = ArraySize(longs); int shortsCount = ArraySize(shorts); // result = // // Long ... isLong ? mMaxAllowedLongs <= 0 ? true : longsCount < mMaxAllowedLongs // // Short ... : mMaxAllowedShorts <= 0 ? true : shortsCount < mMaxAllowedShorts // ; if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED; return result; } // // Check Position Delays ... if (result && mDelayBarBetweenTwoSignal > 0) { // int youngestAge = 0; XPosition youngestPosition; // // Long Positions when there are Longs ... if (isLong && longsCount > 0) { // youngestAge = GetYoungest( youngestPosition, longs // ); } // // Short Positions when there are Shorts ... else if (!isLong && shortsCount > 0) { // youngestAge = GetYoungest( youngestPosition, shorts // ); } // // Only Check when there is must to check and conditions happens ... if (youngestAge > 0 && youngestPosition.IsValid()) { // result = youngestAge >= mDelayBarBetweenTwoSignal; if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED; return result; } } } } // // Check Drawdown ... if (mMaxDrawdownPercentForOpenTrades > 0) { // drawdownPercent = GetMaxDrawdown(); // result = drawdownPercent <= 0 ? true : drawdownPercent < mMaxDrawdownPercentForOpenTrades; if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_NO_EQUITY; return result; } } } // // Add Additional Volume to Signal ... signal.volume += mAdditionalVolume; // bool isFiltered = // conditions.IsValid() && x121Parser.IsFiltered( signal, conditions // ); if (isFiltered) { // RemoveSignal(signal); result = false; // return result; } // // Attach Conditions Summary to Signal ... string conditionsSummary = conditions.GenerateSummary( false, false, true, false // ); // signal.conditions = x121Parser.GenerateSignalConditions( signal, conditions // ); // // Check Signal Delay ... datetime currentTime = TimeCurrent(); int delay = DelayBarBetweenTwoSignal(); bool isDelayPassed = delay <= 0 ? true : !IsValid(lastSignalOn) ? true : MathAbs(TimeToSeconds(currentTime)) - MathAbs(TimeToSeconds(lastSignalOn)) >= ulong(delay * PeriodSeconds(_Period)); if (!isDelayPassed) { // result = false; return result; } // // Execute Signal ... result = mTrader.ExecuteSignal( signal, state // ); if (result) { // double commission = mTrader.GetPositionCommission(signal.positionId); // // Add Signal to Trade Handler ... AddData( signal, commission // ); // lastSignalOn = currentTime; // string msg = (signal.type == POSITION_TYPE_BUY ? "Long" : "Short") + " Signal Provided by: " + signal.provider + (signal.pushers > 1 ? " Pushers: " + ToString(signal.pushers) : "") + " on: " + signal.symbol + " in: " + ToString(signal.period) + " Executed Successfully ..."; Alert(msg); } // return result; } // // Positions Management ... // // Reset Position Management ... void ResetSymbolData() { // Clean(mSymbolData); } // // Handle SL ... void HandleSL(ulong positionId) { // int idx = -1; bool hasItem = HasItem( positionId, idx // ); if (!hasItem) { return; } // string symbol = mData[idx].symbol; bool isLong = IsLong(mData[idx].type); // int symbolIDX = -1; bool hasSymbol = HasSymbol( symbol, symbolIDX // ); if (!hasSymbol) { // // Add New One ... // XSymbolData sData; sData.symbol = symbol; // if (isLong) { sData.longSL = 1; } else { sData.shortSL = 1; } // AddRef( sData, mSymbolData // ); } else { // // Update Eists ... // datetime cTime = TimeCurrent(); int maxAllowedSL = NumberOfSLForPauseSignalling(); int pauseMinute = SignallingPauseDelayInMinute(); // if (isLong) { // mSymbolData[symbolIDX].longSL++; // if (pauseMinute > 0 && maxAllowedSL > 0 && !IsValid(mSymbolData[symbolIDX].disableLong) && mSymbolData[symbolIDX].longSL == maxAllowedSL) { // mSymbolData[symbolIDX].longSL = 0; mSymbolData[symbolIDX].disableLong = (datetime)((long)cTime + (pauseMinute * 60)); } } else { // mSymbolData[symbolIDX].shortSL++; // if (pauseMinute > 0 && maxAllowedSL > 0 && !IsValid(mSymbolData[symbolIDX].disableShort) && mSymbolData[symbolIDX].shortSL == maxAllowedSL) { // mSymbolData[symbolIDX].shortSL = 0; mSymbolData[symbolIDX].disableShort = (datetime)((long)cTime + (pauseMinute * 60)); } } } } // // Handle TP ... void HandleTP(ulong positionId) { // int idx = -1; bool hasItem = HasItem( positionId, idx // ); if (!hasItem) { return; } // string symbol = mData[idx].symbol; bool isLong = IsLong(mData[idx].type); // int symbolIDX = -1; bool hasSymbol = HasSymbol( symbol, symbolIDX // ); if (hasSymbol) { // // Update Eists ... // if (isLong) { // if (mSymbolData[symbolIDX].longSL > 0) { mSymbolData[symbolIDX].longSL--; } } else { // if (mSymbolData[symbolIDX].shortSL > 0) { mSymbolData[symbolIDX].shortSL--; } } } } // // Protection Functions ... /** * Handle Positiona Protections */ void HandleProtection() { // // Retrieve Positions ... XProtectedPosition pPositions[]; int pPositionsCount = GetPositions( pPositions // ); // // Validate Count ... if (!IsValidSize(pPositionsCount)) { return; } // bool isHedged = HandleHedge(pPositions); if (isHedged) { // // Renew Data ... Clean(pPositions); int pPositionsCount = GetPositions( pPositions // ); // // Validate Count ... if (!IsValidSize(pPositionsCount)) { return; } // return; } // int protectedPositions = 0; for (int i = 0; i < pPositionsCount; i++) { // // Check Position is Protectable or not ... XProtectedPosition iProtected = pPositions[i]; XPosition iPosition = iProtected.main; // bool isProtected = HandlePositionProtecting( iPosition, iProtected.supports, pPositions // ); if (isProtected) { protectedPositions++; } } // if (protectedPositions > 0) { // // Renew Data ... Clean(pPositions); int pPositionsCount = GetPositions( pPositions // ); // // Validate Count ... if (!IsValidSize(pPositionsCount)) { return; } } } // // Protected ... protected: // XSCTrade *mTrader; // Instance of Trader Class X121TradeCollector *mCollector; // Instance of Trade Collector Class // X121TradeData mData[]; // Hold Trade Data XSymbolData mSymbolData[]; // Hold Symbols SL TP Data // // Hedge Related Functions ... /** * Handle Hedging On Positions ... */ bool HandleHedge(XProtectedPosition &positions[]) { // bool result = false; // // Check Hedging is Enabled Or Not ... result = AllowHedge(); if (!result) { return result; } // // Check Minimum Volume Step is Provided or not ... double minVolumeStep = HedgeMinVolumeStep(); result = minVolumeStep > 0; if (!result) { return result; } // // Check Positions ... int positionsCount = ArraySize(positions); result = IsValidSize(positionsCount); if (!result) { return result; } // // Calculate Required Info ... double swaps = 0; // Summary of Positions Swaps ... double profits = 0; // Summary of Positions and Supports Profits ... double volumes = 0; // Summary of Positions and Supports Volumes ... int supportsCount = 0; // Number of Protecting Positions ... double commissions = 0; // Summary of Positions and Supports Commissions ... XPosition flatPositions[]; // Flat Positions ... for (int i = 0; i < positionsCount; i++) { // XProtectedPosition iProtected = positions[i]; // XPosition iPositions[]; int iPositionsCount = iProtected.ExtractPositions(iPositions); if (IsValidSize(iPositionsCount)) { // Copy( iPositions, flatPositions, false // ); } // // Collect Main Positions Data ... swaps += iProtected.main.swap; profits += iProtected.main.profit; volumes += iProtected.main.volume; commissions += mTrader.GetPositionCommission(iProtected.main.ticket); // int iSupportsCount = iProtected.CountSupports(); supportsCount += iSupportsCount; // if (IsValidSize(iSupportsCount)) { // // Collectiong Supports Positions Data ... for (int j = 0; j < iSupportsCount; j++) { // XPosition jSupport = iProtected.supports[j]; // swaps += jSupport.swap; profits += jSupport.profit; volumes += jSupport.volume; // commissions += mTrader.GetPositionCommission(jSupport.ticket); } } } // // First Step is Handle HE Hedge ... // int minOpenPositions = MinimumOpenPositionsForHEHedge(); double heMinProfitPerVolumeStep = HedgeHEMinProfitPerVolumeStep(); double beMinProfitPerVolumeStep = HedgeBEMinProfitPerVolumeStep(); // // Check HE Hedge Conditions ... bool allowHEHedge = minOpenPositions > 0 && heMinProfitPerVolumeStep > 0; if (allowHEHedge) { // // Implement HE Hedge ... // // Check Main Positions Count and also not Support Positions ... result = supportsCount == 0 && positionsCount >= minOpenPositions; if (result) { // // Check Profits ... result = profits > 0; if (result) { // // Calculate Required Profit ... double volumeSteps = volumes / minVolumeStep; double minRequiredProfit = (volumeSteps * heMinProfitPerVolumeStep) + commissions + (-1 * swaps); // // Check Profits Satisfied Required Profit's For Hedge or not ... result = profits >= minRequiredProfit; if (result) { // int flatPositionsCount = ArraySize(flatPositions); result = IsValidSize(flatPositionsCount); if (result) { // string comment = "EQM HE Hedge ..."; int closed = mTrader.Close( flatPositions, comment // ); // result = closed > 0; if (result) { // string message = "EQM HE Hedge Close (" + ToString(flatPositionsCount) + ") Positions by: " + ToString(profits); Alert(message); // return result; } } } } } } // // Check BE Hedge Conditions ... bool allowBEHedge = positionsCount >= 1 && supportsCount >= 1 && beMinProfitPerVolumeStep > 0; if (allowBEHedge) { // // Implement BE Hedge ... // // Check Profits ... result = profits > 0; if (result) { // // Calculate Required Profit ... double volumeSteps = volumes / minVolumeStep; double minRequiredProfit = (volumeSteps * beMinProfitPerVolumeStep) + commissions + (-1 * swaps); // // Check Profits Satisfied Required Profit's For Hedge or not ... result = profits >= minRequiredProfit; if (result) { // int flatPositionsCount = ArraySize(flatPositions); result = IsValidSize(flatPositionsCount); if (result) { // string comment = "EQM BE Hedge ..."; int closed = mTrader.Close( flatPositions, comment // ); // result = closed > 0; if (result) { // string message = "EQM BE Hedge Close (" + ToString(flatPositionsCount) + ") Positions by: " + ToString(profits); Alert(message); // return result; } } } } // return result; } // return result; } /** * Handle Protecting Position ... */ bool HandlePositionProtecting( XPosition &position, // Main Position XPosition &supports[], // Supports XProtectedPosition &positions[] // All Positions ) { // bool result = false; // // Find Position's Item Data ... int iDX = -1; result = HasItem( position.ticket, iDX // ); if (!result) { return result; } // int supportsCount = ArraySize(supports); // // Handle Protection Of Protection Signals ... if (supportsCount > 0) { HandleProtectionOfProtectors(supports); } // // Here we Make Sure this Position has reached Proper distance ... // bool isLong = IsLong(position.type); bool isInProfit = position.profit > 0; datetime currentTime = TimeCurrent(); // double profitInPoint = position.GetProfitInPoint(); double pointValue = position.GetPointsValue(); // // Determines there is a Freezed Position or not ... bool hasFreezed = false; int positionsCount = ArraySize(positions); if (IsValidSize(positionsCount)) { // for (int i = 0; i < positionsCount; i++) { // int iSupportsCount = ArraySize(positions[i].supports); // hasFreezed = iSupportsCount == 1 && positions[i].main.tp == 0 && positions[i].main.sl == 0 && positions[i].supports[0].tp == 0 && positions[i].supports[0].sl == 0 && positions[i].main.volume == positions[i].supports[0].volume; if (hasFreezed) { break; } } } // // Reading Requirements for Trailling Stops ... bool allowTrail = AllowTrail(); double trailStep = TrailStep(); double trailStartDistance = TrailStartDistance(); bool allowOnlyUnprotecteds = OnlyTrailUnprotected(); int removeTPAfterTrailedLevel = RemoveTPAfterTrailedLevel(); bool disableTrailWhenFreezedPosition = false; // DisableTrailWhenFreezedPosition(); bool canTrail = isInProfit && allowTrail && trailStep > 0 && profitInPoint > 0 && trailStartDistance > 0 && (!allowOnlyUnprotecteds ? true : supportsCount <= 0) && profitInPoint >= trailStartDistance && (!disableTrailWhenFreezedPosition ? true : !hasFreezed); // // Reading Requirements for Partial Close ... // In Profit ... double partialCloseInProfitDistance = PartialCloseInProfitDistance(); double partialCloseInProfitVolume = PartialCloseInProfitVolume(); bool canPartialCloseInProfit = isInProfit && profitInPoint > 0 && !mData[iDX].partiallyClosed && partialCloseInProfitVolume > 0 && profitInPoint >= partialCloseInProfitDistance; // // In Drawdown ... double partialCloseInDrawdownDistance = PartialCloseInProfitDistance(); double partialCloseInDrawdownVolume = PartialCloseInProfitVolume(); bool canPartialCloseInDrawdown = !isInProfit && profitInPoint < 0 && !mData[iDX].partiallyClosed && partialCloseInDrawdownVolume > 0 && MathAbs(profitInPoint) >= partialCloseInDrawdownDistance; // double partialCloseVolume = canPartialCloseInProfit ? partialCloseInProfitVolume : canPartialCloseInDrawdown ? partialCloseInDrawdownVolume : 0; // bool canPartialClose = partialCloseVolume > 0 && (canPartialCloseInProfit || canPartialCloseInDrawdown); // // Reading Requirement for Freezing Positions ... // // Protect ... bool allowProtect = AllowProtect(); int protectionDelay = ProtectionDelay(); bool protectOnConditions = ProtectOnConditions(); int maxAllowedProtection = MaxAllowedProtection(); bool useEntryAsProtectionSL = UseEntryAsProtectionSL(); double protectDistance = ProtectionStartDistance(); bool allowDirectionProtect = AllowDirectionProtct(); double protectVolumeMultiplier = ProtectionVolumeMultiplier(); bool canProtect = !isInProfit && allowProtect && protectDistance > 0 && protectionDelay >= 0 && protectVolumeMultiplier >= 1 && (maxAllowedProtection <= 0 ? true : supportsCount < maxAllowedProtection) && MathAbs(profitInPoint) >= MathAbs(protectDistance); // result = canTrail || canProtect || canPartialClose; if (!result) { return result; } // int zIndex = 0; int cIndex = zIndex + 1; int pIndex = cIndex + 1; int ppIndex = pIndex + 1; // // Last Bar ... XOHCL cBar; result = cBar.Init( position.symbol, position.period, cIndex // ); if (!result) { return result; } // // Previous Bar of Last Bar ... XOHCL pBar; result = cBar.GetPreviousBar(pBar); if (!result) { return result; } // // Last Swing Low Bar ... XOHCL lastSwingLow; result = cBar.FindLastSwingLow(lastSwingLow); if (!result) { return result; } // // Last Swing High Bar ... XOHCL lastSwingHigh; result = cBar.FindLastSwingHigh(lastSwingHigh); if (!result) { return result; } // // Common Conditions For Bullish and Bearish Powers ... // // For Trend ... XOHCL tmpHSW[]; XOHCL tmpLSW[]; // // Detect Bullish/Bearish Patterns and Trends ... // // Bullish ... bool hasBullishPower = cBar.HasBullishPower(); bool hasBullishPattern = HasBullishPattern(cBar); bool hasBullishPressure = cBar.HasBullishPressure(); bool isBullishTrend = cBar.HasBullishTrend( tmpHSW, tmpLSW, true // ); bool isBullishTrend1 = cBar.HasBullishTrend( tmpHSW, tmpLSW, false // ); bool hasBullishTrend = // isBullishTrend // || // isBullishTrend1 // ; // // Bearish ... bool hasBearishPower = cBar.HasBearishPower(); bool hasBearishPattern = HasBearishPattern(cBar); bool hasBearishPressure = cBar.HasBearishPressure(); bool isBearishTrend = cBar.HasBearishTrend( tmpHSW, tmpLSW, true // ); bool isBearishTrend1 = cBar.HasBearishTrend( tmpHSW, tmpLSW, false // ); bool hasBearishTrend = // isBearishTrend // || // isBearishTrend1 // ; // // Define Conditions ... MqlTick ticks[]; int ticksCount = CopyTicks( position.symbol, ticks, COPY_TICKS_ALL, 0, 5 // ); // bool isTicksBullishForLong = false; bool isTicksBearishForLong = false; bool isTicksBullishForShort = false; bool isTicksBearishForShort = false; // if (ticksCount == 5) { // isTicksBullishForLong = // GetTickEntry(ticks[0], POSITION_TYPE_BUY, position.symbol) > GetTickEntry(ticks[1], POSITION_TYPE_BUY, position.symbol) && GetTickEntry(ticks[1], POSITION_TYPE_BUY, position.symbol) > GetTickEntry(ticks[2], POSITION_TYPE_BUY, position.symbol) && GetTickEntry(ticks[2], POSITION_TYPE_BUY, position.symbol) > GetTickEntry(ticks[3], POSITION_TYPE_BUY, position.symbol) // ; // isTicksBearishForLong = // GetTickEntry(ticks[0], POSITION_TYPE_BUY, position.symbol) < GetTickEntry(ticks[1], POSITION_TYPE_BUY, position.symbol) && GetTickEntry(ticks[1], POSITION_TYPE_BUY, position.symbol) < GetTickEntry(ticks[2], POSITION_TYPE_BUY, position.symbol) && GetTickEntry(ticks[2], POSITION_TYPE_BUY, position.symbol) < GetTickEntry(ticks[3], POSITION_TYPE_BUY, position.symbol) // ; // isTicksBullishForShort = // GetTickEntry(ticks[0], POSITION_TYPE_SELL, position.symbol) > GetTickEntry(ticks[1], POSITION_TYPE_SELL, position.symbol) && GetTickEntry(ticks[1], POSITION_TYPE_SELL, position.symbol) > GetTickEntry(ticks[2], POSITION_TYPE_SELL, position.symbol) && GetTickEntry(ticks[2], POSITION_TYPE_SELL, position.symbol) > GetTickEntry(ticks[3], POSITION_TYPE_SELL, position.symbol) // ; // isTicksBearishForShort = // GetTickEntry(ticks[0], POSITION_TYPE_SELL, position.symbol) < GetTickEntry(ticks[1], POSITION_TYPE_SELL, position.symbol) && GetTickEntry(ticks[1], POSITION_TYPE_SELL, position.symbol) < GetTickEntry(ticks[2], POSITION_TYPE_SELL, position.symbol) && GetTickEntry(ticks[2], POSITION_TYPE_SELL, position.symbol) < GetTickEntry(ticks[3], POSITION_TYPE_SELL, position.symbol) // ; } // // News Momentum Change ... // double hh5 = cBar.FindHighest( 5, MODE_HIGH // ); // double ll5 = cBar.FindLowest( 5, MODE_LOW // ); // bool isForecBullishMomentum = false; bool isForceBearishMomentum = false; bool useForceMomentum = UseForceMomentumsInProtection(); if (ticksCount == 5 && useForceMomentum) { // isForecBullishMomentum = // GetTickEntry(ticks[0], POSITION_TYPE_BUY, position.symbol) >= hh5 // && // ( // GetTickEntry(ticks[0], POSITION_TYPE_BUY, position.symbol) > GetTickEntry(ticks[1], POSITION_TYPE_BUY, position.symbol) && GetTickEntry(ticks[1], POSITION_TYPE_BUY, position.symbol) > GetTickEntry(ticks[2], POSITION_TYPE_BUY, position.symbol) && GetTickEntry(ticks[2], POSITION_TYPE_BUY, position.symbol) > GetTickEntry(ticks[3], POSITION_TYPE_BUY, position.symbol) && GetTickEntry(ticks[3], POSITION_TYPE_BUY, position.symbol) > GetTickEntry(ticks[4], POSITION_TYPE_BUY, position.symbol) // ) // ; // isForceBearishMomentum = // GetTickEntry(ticks[0], POSITION_TYPE_SELL, position.symbol) <= ll5 // && // ( // GetTickEntry(ticks[0], POSITION_TYPE_SELL, position.symbol) < GetTickEntry(ticks[1], POSITION_TYPE_SELL, position.symbol) && GetTickEntry(ticks[1], POSITION_TYPE_SELL, position.symbol) < GetTickEntry(ticks[2], POSITION_TYPE_SELL, position.symbol) && GetTickEntry(ticks[2], POSITION_TYPE_SELL, position.symbol) < GetTickEntry(ticks[3], POSITION_TYPE_SELL, position.symbol) && GetTickEntry(ticks[3], POSITION_TYPE_SELL, position.symbol) < GetTickEntry(ticks[4], POSITION_TYPE_SELL, position.symbol) // ) // ; } // bool hasBullishDecision = // cBar.IsBullishDecision() // ; // bool hasBearishDecision = // cBar.IsBearishDecision() // ; // bool hasBullishConditions = // ( // hasBullishTrend && hasBullishDecision && (hasBullishPower || hasBullishPattern || hasBullishPressure) // ) // ; // bool hasBearishConditions = // ( // hasBearishTrend && hasBearishDecision && (hasBearishPower || hasBearishPattern || hasBearishPressure) // ) // ; // // Do Trail ... bool isTrailed = false; if (canTrail) { // bool hasTrailConditions = isLong ? (isForecBullishMomentum || (isTicksBullishForLong && hasBullishConditions)) : (isForceBearishMomentum || (isTicksBearishForShort && hasBearishConditions)); if (hasTrailConditions) { // double entry = position.entry; int lastTrailedStep = mData[iDX].trailStep; // double requiredProfit = lastTrailedStep == 0 ? trailStartDistance : trailStartDistance + (lastTrailedStep * trailStep); // bool isProfitsPassed = profitInPoint > requiredProfit; if (isProfitsPassed) { // double delta = (requiredProfit * pointValue); // double sl = isLong ? entry + delta : entry - delta; // string comment = "EQM Trail Stop ..."; // bool canRemoveTP = position.tp != 0 && removeTPAfterTrailedLevel > 0 && mData[iDX].trailStep == removeTPAfterTrailedLevel; double tp = canRemoveTP ? 0 : position.tp; // // Try to Modify Position ... isTrailed = mTrader.Modify( position.ticket, sl, tp, comment // ); if (isTrailed) { // mData[iDX].trailStep++; // string message = "EQM Trail (" + ToString(position.ticket) + ") Stop in Level: " + ToString(mData[iDX].trailStep) + " ..."; Alert(message); } } } // // Force Trail When passed half way ... else { // // Handle Force Trail ... double requiredProfit = position.GetRewardInPoint() / 2; if (position.sl > 0 && position.sl < position.entry && profitInPoint >= requiredProfit) { // double delta = requiredProfit - (requiredProfit / 3); double sl = isLong ? position.entry + (delta * pointValue) : position.entry - (delta * pointValue); // string comment = "EQM Force Trail Stop ..."; // // Try to Modify Position ... isTrailed = mTrader.Modify( position.ticket, sl, position.tp, comment // ); if (isTrailed) { // mData[iDX].trailStep++; // string message = "EQM Force Trail (" + ToString(position.ticket) + ") Stop ..."; Alert(message); } } } } // // Do Partial Close ... bool isPartialClosed = false; if (canPartialClose) { // string comment = "EQM Partial Close ..."; // // Do Partial Closing ... isPartialClosed = mTrader.ClosePartial( position.ticket, partialCloseVolume, comment // ); if (isPartialClosed) { // mData[iDX].partiallyClosed = true; // string message = "EQM Partially Closed " + ToString(partialCloseVolume) + " of (" + ToString(position.ticket) + ") ..."; Alert(message); } } // // Protect ... bool isProtected = false; if (canProtect) { // // Protection Conditions ... bool hasLongProtectConditions = isForecBullishMomentum || (isTicksBullishForLong && hasBullishConditions); bool hasShortProtectConditions = isForceBearishMomentum || (isTicksBearishForShort && hasBearishConditions); // // Check Protection Delay ... datetime currentTime = TimeCurrent(); datetime lastProtectedOn = mData[iDX].lastProtectedOn; bool isProtectionDelayPassed = protectionDelay <= 0 ? true : !IsValid(lastProtectedOn) ? true : (TimeToSeconds(currentTime) - TimeToSeconds(lastProtectedOn)) > (ulong)protectionDelay; // // Checking Protection Conditions ... bool hasProtectConditions = isProtectionDelayPassed && (!protectOnConditions ? true : allowDirectionProtect ? (hasLongProtectConditions || hasShortProtectConditions) : isLong ? hasShortProtectConditions : hasLongProtectConditions); // // Check Protection Conditions Happens ... if (hasProtectConditions) { // bool isInDirectProtection = !protectOnConditions ? true : isLong ? hasShortProtectConditions : hasLongProtectConditions; // double sl = !isInDirectProtection ? position.sl : useEntryAsProtectionSL ? position.entry : position.tp; double tp = !isInDirectProtection ? position.tp : position.sl; double volume = protectVolumeMultiplier * position.volume; ENUM_POSITION_TYPE type = !isInDirectProtection ? position.type : GetOpposit(position.type); double entry = GetEntry( position.symbol, type // ); ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET; // // Prepare Signal ... XSignal signal; bool isPrepared = signal.Prepare( position.symbol, position.provider, position.period, type, mode, entry, volume, sl, tp // ); // if (isPrepared) { // // Generate Comment for Recover and Support ... string comment = GenerateSupportTag(position.ticket); // signal.comment = comment; // X121StrategyConditions conditions; ENUM_X_SIGNAL_EXECUTION_RESULT state; isProtected = ExecuteSignal( signal, state, conditions, true // Support Signal need to Ignore Policies ... ); if (isProtected) { // // Update Last Protected On Data Handler ... mData[iDX].lastProtectedOn = currentTime; // // Alert ... string message = "EQM Open " + (IsLong(type) ? "Long" : "Short") + " Protect Position for (" + ToString(position.ticket) + ") ..."; Alert(message); } } } } // result = isTrailed || isProtected || isPartialClosed; // return result; } /** * Handle Protection of Support(s) ... * * @param supports: Supports Array ... */ void HandleProtectionOfProtectors(XPosition &supports[]) { // int supportsCount = ArraySize(supports); // if (!IsValidSize(supportsCount)) { return; } // // TODO: Implement Supports Protection ... // // Trailling ... } // // Private ... private: // // Props ... double mAdditionalVolume; // Volume Additional // // Read Only ... int maxSameTimeTrades; // Max Same Time Trades double maxDrawdown; // Max Drawdown double drawdownPercent; // Drawdown Percent double staticBalanceForCalculateDrawdown; // Static Balance for Max Drawdown Calculation // bool mSaveSignals; // Save Signals bool mSaveTrades; // Save Trades bool mSaveConditions; // Save SL Conditions // bool mAllowLong; // Allow Long/Buy Trade Type bool mAllowShort; // Allow Short/Sell Trade Type int mMaxAllowedLongs; // Max Allowe Long/Buy Trades int mMaxAllowedShorts; // Max Allowe Short/Sell Trades bool mUseMaxAllowedTradesPerSymbol; // Use Max Allowed Trades Per Symbol int mNumberOfSLForPauseSignalling; // Number of SL For Pause Signalling Per Symbol/Type int mSignallingPauseDelayInMinute; // Signalling Pause Delay In Minute double mMaxDrawdownPercentForOpenTrades; // Max Drawdown Percent for Open Trades // // Protector ... // bool mUseForceMomentumsInProtection; // Use Force Momentums In Protection; int mDelayBarBetweenTwoSignal; // Delay Bars Between Two Signal double mAcceptNextSameTypeSignalWhenLastInProfit; // Accept Next Same Type Signal When Last in Profit in Point // datetime lastSignalOn; // // Since Signal Filtering done based on // Strategy and it's not related to Public // TradeHandler for Seperation of Concern issue, // we do this here ... X121StartegyConditionsParser x121Parser; // // In Profit Positions Protecting ... // // Trail ... bool mAllowTrail; // Allow Trail Stop for Positions double mTrailStartDistance; // Specify Trail Start in Point double mTrailStep; // Trail Step in Point int mRemoveTPAfterTrailedLevel; // Remove Trailed Position TP after Level bool mOnlyTrailUnprotected; // Only Trail Unprotected Positionss // // Partial Close (In Profit) ... double mPartialCloseInProfitDistance; // Specify Partial Close Profit in Point double mPartialCloseInProfitVolume; // Specify Partial Close in Profit Volume // // In Drawdown Positions Protecting ... // // Protect ... bool mAllowProtect; // Allow Proptecting double mProtectionStartDistance; // Protection Start Drawdown in Profit double mProtectionVolumeMultiplier; // Protection Volume Multiplier int mMaxAllowedProtection; // Max Allowed Protection bool mUseEntryAsProtectionSL; // Use Position Entry For SL of Protect bool mAllowDirectionProtct; // Allow also Directional Protect bool mProtectOnConditions; // Do Protection only when Conditions happens int mProtectionDelay; // Delay Between two Protection in Secconds // // Partial Close (In Drawdown) ... double mPartialCloseInDrawdownDistance; // Specify Partial Close Drawdown in Point double mPartialCloseInDrawdownVolume; // Specify Partial Close in Drawdown Volume // // Hedging Properties ... bool mAllowHedge; // Allow Protector to Hedge Positions double mHedgeMinVolumeStep; // Minimum Volume Step For Hedge int mMinimumOpenPositionsForHEHedge; // Minimum Open Positions For HE Hedge double mHedgeHEMinProfitPerVolumeStep; // Minimum Required Profit For HE Hedge Per Volume Step double mHedgeBEMinProfitPerVolumeStep; // Minimum Required Profit For BE Hedge Per Volume Step // // Common Functions ... // // Count Data ... int Count() { return ArraySize(mData); } // // Add Item ... bool Add(X121TradeData &item) { // bool result = false; // result = item.IsValid(); if (!result) { return result; } // int index = -1; if (item.ticket > 0) { // result = !HasItem( item.ticket, index // ); } else { // result = !HasItem( item.symbol, item.provider, item.period, item.type, index // ); } if (!result || IsValidIndex(index)) { // result = false; return result; } // AddRef( item, mData // ); // return result; } // // Find Item Index ... bool HasItem( ulong ticket, int &index // ) { // bool result = false; // index = -1; // int count = Count(); result = IsValidSize(count); if (!result) { return result; } // for (int i = 0; i < count; i++) { // result = mData[i].IsOwn(ticket); if (result) { // index = i; break; } } // return result; } // // Find Item Index ... bool HasItem( string symbol, string provider, ENUM_TIMEFRAMES period, ENUM_X_POSITION_TYPES type, int &index // ) { // bool result = false; // 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); if (!result) { return result; } // for (int i = 0; i < count; i++) { // result = mData[i].IsOwn( symbol, provider, period, type // ); if (result) { // index = i; break; } } // return result; } // void Save(int index) { // int count = Count(); if (!IsValidIndex(index) || index > count - 1) { return; } // // Save Trade ... if (mSaveTrades) { mCollector.Save(mData[index]); } // if (mSaveConditions) { mCollector.SaveConditions(mData[index]); } // // Remove Item From List ... ArrayRemove( mData, index, 1 // ); } // void SaveSignal(X121TradeData &item) { // if (!mSaveSignals) { return; } // // Save Signal ... mCollector.SaveSignal(item); } // // Symbol Data Parsing ... // bool HasSymbol( string symbol, int &index // ) { // index = -1; bool result = false; // result = IsValid(symbol); if (!result) { return result; } // int count = ArraySize(mSymbolData); result = IsValidSize(count); if (!result) { return result; } // // Loop through Symbol Data ... for (int i = 0; i < count; i++) { // XSymbolData iData = mSymbolData[i]; // if (iData.symbol == symbol) { // index = i; result = true; break; } } // return result; } // }; //