/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class Library // -------------------------------------- // Name: XCX121SMCTradeHandler // Description: provides all based classes for use ... // // // 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.x-alert.class.mq5" #include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" #include "../../Classes/x-saherelm.x-trade.class.mq5" // // Definitions ... // // Model a Trade Data ... struct X121SMCTradeData { // double ask; // Ask Price on Start Time double bid; // bid Price on Start Time ulong ticket; // Position Ticket double swap; // Swap double profit; // Profit on Close XSignal signal; // Signal Object string message; // Message datetime endTime; // End Time datetime startTime; // Start Time double commission; // Commission string conditions; // Signal Conditions double maxDrawdown; // Max Position Drawdown // // Constructor ... X121SMCTradeData() { Clean(); } /** * Initialize Item ... * * @param _signal: XSignal instance Reference, Provides Source For Initializaion ... * * @return ( bool ) */ bool Init(XSignal &_signal) { // bool result = false; // Clean(); // result = _signal.IsValid(); if (!result) { return result; } // signal = _signal; // result = IsValid(); // return result; } // // Tools ... /** * Cleaning Up Model ... */ void Clean() { // ask = 0; bid = 0; swap = 0; profit = 0; ticket = 0; commission = 0; maxDrawdown = 0; // endTime = NULL; message = NULL; startTime = NULL; conditions = NULL; // signal.Clean(); } /** * Validate Model ... * * @return ( bool ) */ bool IsValid() { // bool result = false; // result = // signal.IsValid() // ; // return result; } /** * Calculate Model Age ... * * @return ( int ) */ int GetAge() { // int result = -1; // if (!IsValid()) { return result; } // int startIndex = iBarShift( GetSymbol(), GetPeriod(), startTime, false // ); // datetime mEndTime = IsValid(endTime) ? endTime : TimeCurrent(); int endIndex = iBarShift( GetSymbol(), GetPeriod(), mEndTime, false // ); // result = MathAbs(startIndex - endIndex); // return result; } // // Owner Functions ... /** * Check a Ticket is Own to Model or not ... * * @param _ticket: ULONG, Position Ticket ... * * @return ( bool ) */ bool IsOwn( ulong _ticket // ) { // bool result = false; // result = IsValid() && _ticket == ticket; // return result; } /** * Check Specified Conditions is Own to Model or not ... * * @param _symbol: String, Specified Symbol ... * @param _provider: String, Specified Provider ... * @param _period: ENUM_TIMEFRAMES member, Specified Signal Period ... * @param _type: ENUM_X_POSITION_TYPES member, Specified Signal Type ... * * @return ( bool ) */ bool IsOwnSignalTime( string _symbol, string _provider, ENUM_TIMEFRAMES _period, ENUM_X_POSITION_TYPES _type, datetime _time // ) { // bool result = false; // result = // IsValid(_time) && Time() == _time && IsValid(_symbol) && IsValid(_period) && XType() == _type && IsValid(_provider) && GetPeriod() == _period && GetSymbol() == _symbol && Provider() == _provider && XType() != X_POSITION_TYPE_ALL && XType() != X_POSITION_TYPE_NONE // ; // return result; } /** * Check Specified Conditions is Own to Model or not ... * * @param _symbol: String, Specified Symbol ... * @param _provider: String, Specified Provider ... * @param _period: ENUM_TIMEFRAMES member, Specified Signal Period ... * @param _type: ENUM_X_POSITION_TYPES member, Specified Signal Type ... * * @return ( bool ) */ bool IsOwnStartTime( string _symbol, string _provider, ENUM_TIMEFRAMES _period, ENUM_X_POSITION_TYPES _type, datetime _time // ) { // bool result = false; // result = // IsValid(_time) && IsValid(_symbol) && IsValid(_period) && XType() == _type && IsValid(startTime) && startTime == _time && IsValid(_provider) && GetPeriod() == _period && GetSymbol() == _symbol && Provider() == _provider && XType() != X_POSITION_TYPE_ALL && XType() != X_POSITION_TYPE_NONE // ; // return result; } /** * Check Specified Signal is Own to Model or not ... * * @param _signal: XSignal instance Reference ... * * @return ( bool ) */ bool IsOwn(XSignal &_signal) { // bool result = false; // result = // IsValid() && _signal.IsValid() && IsOwnSignalTime( _signal.symbol, _signal.provider, _signal.period, ToPositionType(_signal.type), _signal.time) // ; // return result; } /** * Check Specified Position is Own to Model or not ... * * @param _position: XPosition instance Reference ... * * @return ( bool ) */ bool IsOwn(XPosition &_position) { // bool result = false; // result = // IsValid() && _position.IsValid() && IsOwnStartTime( _position.symbol, _position.provider, _position.period, ToPositionType(_position.type), _position.openAt) // ; // return result; } /** * Check Specified Position is Own to Model or not ... * * @param _position: XPosition instance Reference ... * * @return ( bool ) */ bool IsOwnPosition(XPosition &_position) { // bool result = false; // double tp = TP(); double sl = SL(); double entry = Entry(); double volume = Volume(); string symbol = GetSymbol(); string provider = Provider(); ENUM_POSITION_TYPE type = Type(); ENUM_TIMEFRAMES period = GetPeriod(); // double pVolume = _position.volume; double pSL = NormalizePrice(_position.sl, _position.symbol); double pTP = NormalizePrice(_position.tp, _position.symbol); double pEntry = NormalizePrice(_position.entry, _position.symbol); // result = // IsValid() && (sl == pSL || tp == pTP) && entry == pEntry && pVolume == volume && _position.IsValid() && type == _position.type && symbol == _position.symbol && period == _position.period && provider == _position.provider // ; // if (!result) { // result = // IsValid() && _position.IsValid() && _position.ticket == signal.positionId; } // return result; } /** * Update Model Data by Providing Specified Signal ... * * @param _signal: XSignal instance Reference ... * * @return ( bool ) */ bool Update(XSignal &_signal) { // bool result = false; // result = // IsValid() && _signal.IsValid() && IsOwn(_signal) // ; if (!result) { return result; } // signal = _signal; // return result; } /** * Update Model Data by Providing Specified Position ... * * @param _position: XPosition instance Reference ... * * @return ( bool ) */ bool Update(XPosition &_position) { // bool result = false; // result = // IsValid() && _position.IsValid() && IsOwn(_position) // ; if (!result) { return result; } // swap = _position.swap; ticket = _position.ticket; profit = _position.profit; message = _position.comment; startTime = _position.openAt; // // Set Once ... if (commission == 0 && _position.commission != 0) { commission = _position.commission; } // // Set Once ... if (ask == 0) { ask = GetAsk(_position.symbol); } // // Set Once ... if (bid == 0) { bid = GetBid(_position.symbol); } // if (profit < 0 && profit < maxDrawdown) { maxDrawdown = profit; } // return result; } /** * Update Model Data by Providing Specified Position ... * * @param _position: XPosition instance Reference ... * * @return ( bool ) */ bool UpdatePosition(XPosition &_position) { // bool result = false; // result = // IsValid() && _position.IsValid() && IsOwnPosition(_position) // ; if (!result) { return result; } // swap = _position.swap; ticket = _position.ticket; profit = _position.profit; message = _position.comment; startTime = _position.openAt; // // Set Once ... if (commission == 0 && _position.commission != 0) { commission = _position.commission; } // // Set Once ... if (ask == 0) { ask = GetAsk(_position.symbol); } // // Set Once ... if (bid == 0) { bid = GetBid(_position.symbol); } // if (profit < 0 && profit < maxDrawdown) { maxDrawdown = profit; } // return result; } // // Tools Extensions ... /** * Get Model Symbol ... * * @return ( string ) */ string GetSymbol() { return signal.symbol; } /** * Get Model Period ... * * @return ( ENUM_TIMEFRAMES ) */ ENUM_TIMEFRAMES GetPeriod() { return signal.period; } /** * Get Model Provider ... * * @return ( string ) */ string Provider() { return signal.provider; } /** * Get Model Entry ... * * @return ( double ) */ double Entry() { return signal.entry; } /** * Get Model Stop Loss ... * * @return ( double ) */ double SL() { return signal.sl; } /** * Get Model Take Profit ... * * @return ( double ) */ double TP() { return signal.tp; } /** * Get Position Spread on Open Time ... * * @return ( double ) */ double Spread() { return MathAbs(ask - bid); } /** * Get Model Volume ... * * @return ( double ) */ double Volume() { return signal.volume; } /** * Get Model Point Value ... * * @return ( double ) */ double Points() { return GetPoints(GetSymbol()); } /** * Get Model Type ... * * @return ( ENUM_POSITION_TYPE ) */ ENUM_POSITION_TYPE Type() { return signal.type; } /** * Get Model Type ... * * @return ( ENUM_X_POSITION_TYPES ) */ ENUM_X_POSITION_TYPES XType() { // ENUM_X_POSITION_TYPES result = X_POSITION_TYPE_NONE; // if (!IsValid()) { return result; } // result = IsLong(Type()) ? X_POSITION_TYPE_LONG : X_POSITION_TYPE_SHORT; // return result; } /** * Get Model Signal Mode ... * * @return ( ENUM_X_ORDER_MODES ) */ ENUM_X_ORDER_MODES Mode() { return signal.mode; } /** * Get Model Signal Time ... * * @return ( datetime ) */ datetime Time() { return signal.time; } // // Additional Helpers Extensions ... /** * Get Signal Full TP Level ... * * @return ( double ) */ double FullTPLevel() { return signal.fullTPLevel; } /** * Check Can Partial Close Position or not ... * * @return ( bool ) */ bool CanPartialClose() { return signal.CanPartialClose(); } /** * Retrieve Partial Close Volume Multiplier ... * * @return ( double ) */ double PartialCloseMultiplier() { return signal.partialCloseMultiplier; } /** * Get Partial Close On TP Level ... * * @return ( double ) */ double PartialCloseOnTPLevel() { return signal.partialCloseOnTPLevel; } /** * Check Can Risk Free Position on Break Even Point or not ... * * @return ( bool ) */ bool CanRiskFreeOnBreakEvenPoint() { return signal.CanRiskFreeOnBreakEvenPoint(); } /** * Get Minimum Required Profit after Break Even Point for Risk Free ... * * @return ( double ) */ double TPLevelForBreakEven() { return signal.tpLevelForBreakEven; } /** * Calculate Break Even Point ... * * @return ( double ) */ double CalculateBreakEvenPoint() { // double result = 0; // bool isValid = // ask > 0 && bid > 0 && IsValid() && ticket > 0 && signal.IsValid() // ; if (!isValid) { return result; } // // Calculate Spread ... double spread = Spread(); if (spread <= 0) { return result; } // // Calculate BEP ... result = // spread + (-1 * swap) + MathAbs(commission) // ; // return result; } /** * Check Can Trail Position Stop Loss or not ... * * @return ( bool ) */ bool CanTrailSL() { return signal.CanTrailSL(); } /** * Get Start Position SL Trailling on TP Level ... * * @return ( double ) */ double TrailSLStartOnReachTPLevel() { return signal.trailSLStartOnReachTPLevel; } // // Data Collector Extensions ... /** * Get Data Collection File Name ... * * @return ( string ) */ string GetFileName() { // string result = NULL; // if (!IsValid()) { return result; } // result = // GetSymbol() + "\\" + ToString(XType()) + "\\" + (profit >= 0 ? "Profit" : "Loss") + "\\" + ToString(ticket) + "_" + ToString(GetPeriod()) + "_" + ToFormatString(startTime) // ; // return result; } /** * Get Signal Collectiong File Name ... * * @return ( string ) */ string GetSignalFileName() { // string result = NULL; // result = // GetSymbol() + "\\" + ToString(XType()) + "\\" + Provider() + "_" + ToFormatString(startTime) // ; // return result; } /** * Converts Model to String Representation ... * * @param onlySignals: Boolean, Specified Represent Only Signal or not ... * * @return ( string ) */ string ToString( bool onlySignals = false // ) { // string result = NULL; // int age = GetAge(); // result = // (onlySignals ? "" : ToString("Ticket", ticket)) + ToString("Symbol", GetSymbol()) + ToString("Period", GetPeriod()) + ToString("Entry", Entry()) + ToString("Provider", Provider()) + ToString("Type", ToString(XType())) + ToString("Time", startTime) + // // 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", signal.pushers) + "Conditions:" + "\n" + "-------------" + "\n" + conditions + "" // ) + // "" // ; // return result; } // // End Of X121SMCTradeData Model ... }; // // Model Specified Symbol's Positions States ... struct X121SMCSymbolPositionInfo { // string symbol; // datetime enableAt; // int longSLs; int longTPs; // int shortSLs; int shortTPs; // int countedSLs; // // Constructor ... X121SMCSymbolPositionInfo() { Clean(); } // // Tools ... /** * Cleanup ... */ void Clean() { // longSLs = 0; longTPs = 0; // shortSLs = 0; shortTPs = 0; // countedSLs = 0; // enableAt = NULL; } /** * Check is own Symbol Info ... * * @param _symbol: String ... * * @return ( bool ) */ bool IsOwn(string _symbol) { // bool result = false; // result = // IsValid(symbol) && _symbol == symbol // ; // return result; } /** * Check Symbol Trading is Enable or not ... * * @param time: DateTime ... * * @return ( bool ) */ bool IsEnable(datetime time = NULL) { // bool result = false; // time = NormalizeTime(time); // bool isEnableAtValid = IsValid(enableAt); // result = !isEnableAtValid ? true : time > enableAt; if (result && isEnableAtValid) { Reset(); } // return result; } /** * Pause Symbol Trading ... * * @param seconds: Integer ... */ void Pause(int seconds) { // if (seconds <= 0) { return; } // datetime _enableAt = ((datetime)((int)TimeCurrent() + seconds)); enableAt = _enableAt; } /** * Handle Stop Loss ... * * @param _type: ENUM_POSITION_TYPE member ... */ void HandleSL(ENUM_POSITION_TYPE _type) { // bool isLong = IsLong(_type); if (isLong) { longSLs++; } else { shortSLs++; } // countedSLs++; } /** * Handle Take Profit ... * * @param _type: ENUM_POSITION_TYPE member ... */ void HandleTP(ENUM_POSITION_TYPE _type) { // bool isLong = IsLong(_type); if (isLong) { longTPs++; } else { shortTPs++; } // countedSLs--; if (countedSLs < 0) { countedSLs = 0; } } /** * Reset Counter ... */ void Reset() { // countedSLs = 0; enableAt = NULL; } // // End of X121SMCSymbolPositionInfo Model ... }; // // Implementations ... // // a Class For Read and Write Trade Info Data in Files ... class X121SMCTradeCollector { // // Public ... public: // // Props ... // // Constructor(s) ... X121SMCTradeCollector( string _path = NULL // Base Path ) { // mAccount = new XCAccount(); // if (IsValid(_path)) { mPath = _path; } else { mPath = "X121SMCTradeData" + "\\" + mAccount.GetCompany(); } } // // Deconstructor ... ~X121SMCTradeCollector() { } /** * Check Specified Model is Exists or not ... * * @param item: X121SMCTradeData instance Reference, Provides Source Model ... * * @return ( bool ) */ bool IsExists(X121SMCTradeData &item) { // bool result = false; // int mHandler = GetFileHandlerForRead(item); result = mHandler != INVALID_HANDLE; FileClose(mHandler); // return result; } /** * Save Specified Model as Data ... * * @param item: X121SMCTradeData instance Reference, Provides Source Model ... * * @return ( bool ) */ bool Save(X121SMCTradeData &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; } /** * Save Specified Model as Signal ... * * @param item: X121SMCTradeData instance Reference, Provides Source Model ... * * @return ( bool ) */ bool SaveSignal(X121SMCTradeData &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; } /** * Save Specified Model Conditions ... * Conditions only save for Loss Signals ... * this means the profit must be Lower than Zero ... * ans also message Contains SL ... * * @param item: X121SMCTradeData instance Reference, Provides Source Model ... * * @return ( bool ) */ bool SaveConditions(X121SMCTradeData &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 ... // XCAccount *mAccount; // string GetFilePath(X121SMCTradeData &item) { // string fileName = item.GetFileName(); // return GetFilePath(fileName); } string GetFilePath(string fileName) { // string result = ""; // result = // mPath + "\\" + "Trades" + "\\" + fileName + ".x121.log" // ; // return result; } // string GetSignalFilePath(X121SMCTradeData &item) { // string fileName = item.GetSignalFileName(); // return GetSignalFilePath(fileName); } string GetSignalFilePath(string fileName) { // string result = ""; // result = // mPath + "\\" + "Signals" + "\\" + fileName + ".x121.log" // ; // return result; } // string GetConditionsFilePath(X121SMCTradeData &item) { // bool isLong = IsLong(item.Type()); // string fileName = item.GetSymbol() + "\\" + (isLong ? "Longs" : "Shorts"); // return GetConditionsFilePath(fileName); } string GetConditionsFilePath(string fileName) { // string result = ""; // result = // mPath + "\\" + "Conditions" + "\\" + fileName + ".x121.log" // ; // return result; } // int GetFileHandlerForRead(X121SMCTradeData &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(X121SMCTradeData &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(X121SMCTradeData &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(X121SMCTradeData &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(X121SMCTradeData &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(X121SMCTradeData &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; } // // End of X121SMCTradeCollector Class ... }; // // Trade Handler Class ... // a Class For Handling All Trade Requirements ... class XC121SMCTradeHandler : public XCBaseAlert { // // Public ... public: // // // Constructor(s) ... XC121SMCTradeHandler(XCTrade *trader) { // mTrader = trader; mAdditionalVolume = 0; mCollector = new X121SMCTradeCollector(); } // // Deconstructor ... ~XC121SMCTradeHandler() { // delete mTrader; delete mCollector; } // // ReadOnly Props ... /** * Get Max Same Time Trades ... * * @return ( double ) */ double GetMaxSameTimeTrades() { return maxSameTimeTrades; } /** * Get Max Drawdown Happens ... * * @return ( double ) */ double GetMaxDrawdown() { return maxDrawdown; } /** * Get Currently Drawdown of Account ... * * @return ( double ) */ double GetCurrentDrawdown() { return currentDrawdown; } /** * Get Account Current Drawdown Percent ... * * @return ( double ) */ double GetDrawdownPercent() { return drawdownPercent; } // // Properties Getter(s) / Setter(s) ... // // Saving Properties ... /** * Get Save Signals State ... * * @return ( bool ) */ bool SaveSignals() { return mSaveSignals; } /** * Set Save Signals State ... * * @param value: Boolean ... */ void SaveSignals(bool value) { mSaveSignals = value; } /** * Get Save Trades State ... * * @return ( bool ) */ bool SaveTrades() { return mSaveTrades; } /** * Set Save Trades State ... * * @param value: Boolean ... */ void SaveTrades(bool value) { mSaveTrades = value; } /** * Get Save Conditions State ... * * @return ( bool ) */ bool SaveConditions() { return mSaveConditions; } /** * Set Save Conditions State ... * * @param value: Boolean ... */ void SaveConditions(bool value) { mSaveConditions = value; } // // Signalling Props ... /** * Get Allow Long Signals State ... * * @return ( bool ) */ bool AllowLong() { return mAllowLong; } /** * Set Allow Long Signals State ... * * @param value: Boolean ... */ void AllowLong(bool value) { mAllowLong = value; } /** * Get Allow Short Signals State ... * * @return ( bool ) */ bool AllowShort() { return mAllowShort; } /** * Set Allow Short Signals State ... * * @param value: Boolean ... */ void AllowShort(bool value) { mAllowShort = value; } /** * Get Max Allowed Long Signals ... * 0 => Unlimited ... * * @return ( int ) */ int MaxAllowedLongs() { return mMaxAllowedLongs; } /** * Set Max Allowed Long Signals ... * * @param value: Integer ... * 0 => Unlimited ... */ void MaxAllowedLongs(int value) { // if (value < 0) { value = 0; } // mMaxAllowedLongs = value; } /** * Get Max Allowed Short Signals ... * 0 => Unlimited ... * * @return ( int ) */ int MaxAllowedShorts() { return mMaxAllowedShorts; } /** * Set Max Allowed Short Signals ... * * @param value: Integer ... * 0 => Unlimited ... */ void MaxAllowedShorts(int value) { // if (value < 0) { value = 0; } // mMaxAllowedShorts = value; } /** * Get Use Max Allowed Signal Types Per Symbol State ... * * @return ( bool ) */ bool UseMaxAllowedSignalsPerSymbol() { return mUseMaxAllowedSignalsPerSymbol; } /** * Set Use Max Allowed Signal Types Per Symbol State ... * * @param value: Boolean ... */ void UseMaxAllowedSignalsPerSymbol(bool value) { mUseMaxAllowedSignalsPerSymbol = false; } /** * Get Last Position Profit In Points for Accept new Signal ... * 0 => Accept All ... * * @return ( double ) */ double LastPositionProfitForAcceptNextInPoint() { return mLastPositionProfitForAcceptNextInPoint; } /** * Set Last Position Profit In Points for Accept new Signal ... * * @param value: Double ... * 0 => Accept All ... */ void LastPositionProfitForAcceptNextInPoint(double value) { // if (value < 0) { value = 0; } // mLastPositionProfitForAcceptNextInPoint = value; } /** * Get Delay between two Signals in Bars ... * 0 => Accept All ... * * @return ( int ) */ int DelaysBetweenTwoSignalsInBar() { return mDelaysBetweenTwoSignalsInBar; } /** * Set Delay between two Signals in Bars ... * * @param value: Integer ... * 0 => Accept All ... */ void DelaysBetweenTwoSignalsInBar(int value) { // if (value < 0) { value = 0; } // mDelaysBetweenTwoSignalsInBar = value; } /** * Get Max Allowed Spread for Signalling ... * 0 => Accept All ... * * @return ( double ) */ double MaxAllowedSpread() { return mMaxAllowedSpread; } /** * Set Max Allowed Spread for Signalling ... * * @param value: Double ... * 0 => Accept All ... */ void MaxAllowedSpread(double value) { // if (value < 0) { value = 0; } // mMaxAllowedSpread = value; } /** * Get Additional Signal Volume ... * * @return ( double ) */ double AdditionalVolume() { return mAdditionalVolume; } /** * Set Additional Signal Volume ... * * @param value: Double ... * min = 0.01 */ void AdditionalVolume(double value) { // if (value < 0) { value = 0; } // if (value > 0 && value < 0.01) { value = 0.01; } // mAdditionalVolume = value; } // // Risk Management Props ... /** * Get Max Allowed Drawdown Percent for Open Trades ... * 0 => Ignore ... * min => 0 ... * max => 100 ... * * @return ( double ) */ double MaxAllowedDrawdownToOpenTrades() { return mMaxAllowedDrawdownToOpenTrades; } /** * Set Max Allowed Drawdown Percent for Open Trades ... * * @param value: Double ... * 0 => Ignore ... * min => 0 ... * max => 100 ... */ void MaxAllowedDrawdownToOpenTrades(double value) { // if (value < 0) { value = 0; } // if (value > 50) { value = 50; } // mMaxAllowedDrawdownToOpenTrades = value; } /** * Get Max Allowed SL for Pause Signalling Per Symbol ... * 0 => Unlimited ... * * @return ( int ) */ int MaxAllowedSLToPauseSignallingPerSymbol() { return mMaxAllowedSLToPauseSignallingPerSymbol; } /** * Set Max Allowed SL for Pause Signalling Per Symbol ... * * @param value: Integer ... * 0 => Unlimited ... */ void MaxAllowedSLToPauseSignallingPerSymbol(int value) { // if (value < 0) { value = 0; } // mMaxAllowedSLToPauseSignallingPerSymbol = value; } /** * Get Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds ... * 0 => Ignore ... * * @return ( int ) */ int PauseSignallingAfterReachesMaxAllowedSLInSecconds() { return mPauseSignallingAfterReachesMaxAllowedSLInSecconds; } /** * Set Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds ... * * @param value: Integer ... * 0 => Ignore ... */ void PauseSignallingAfterReachesMaxAllowedSLInSecconds(int value) { // if (value < 0) { value = 0; } // mPauseSignallingAfterReachesMaxAllowedSLInSecconds = value; } // // Protection Props ... /** * Get Allow Hedge Positions State ... * * @return ( bool ) */ bool AllowHedging() { return mAllowHedging; } /** * Set Allow Hedge Positions State ... * * @param value: Boolean ... */ void AllowHedging(bool value) { mAllowHedging = value; } /** * Get Minimum Open Positions for Hedging ... * 0 => Ignore ... * * @return ( int ) */ int MinOpenTradesFroHedging() { return mMinOpenTradesFroHedging; } /** * Set Minimum Open Positions for Hedging ... * * @param value: Integer ... * 0 => Ignore ... */ void MinOpenTradesFroHedging(int value) { // if (value < 0) { value = 0; } // mMinOpenTradesFroHedging = value; } /** * Get Minimum Volume Step for Hedging ... * 0 => Ignore ... * * @return ( double ) */ double HedgingMinVolumeStep() { return mHedgingMinVolumeStep; } /** * Set Minimum Volume Step for Hedging ... * * @param value: Double ... * 0 => Ignore ... */ void HedgingMinVolumeStep(double value) { // if (value < 0) { value = 0; } // if (value > 0 && value < 0.01) { value = 0.01; } // if (value > 0 && value > 0.1) { value = 0.1; } // mHedgingMinVolumeStep = value; } /** * Get Minimum Required Profit Per Volume Step for Hedging ... * 0 => Ignore ... * * @return ( double ) */ double HedgeingMinRequiredProfitPerVolumeStep() { return mHedgeingMinRequiredProfitPerVolumeStep; } /** * Set Minimum Required Profit Per Volume Step for Hedging ... * * @param value: Double ... * 0 => Ignore ... */ void HedgeingMinRequiredProfitPerVolumeStep(double value) { // if (value < 0) { value = 0; } // mHedgeingMinRequiredProfitPerVolumeStep = value; } // // Actions ... // // Data Collection Actions ... /** * Add Executed Signal Data Model to Trade Datas ... * * @param signal: XSignal instance Reference, Issued Signal ... */ void Add(XSignal &signal) { // // Check Signal is Valid and also not Exists // in Datas ... int idx = -1; bool hasItem = HasItem( signal, idx // ); if (hasItem) { return; } // // Initialize Data Item and Add it to Collection of Datas // if Everythings OK ... X121SMCTradeData data; bool isInited = data.Init(signal); if (isInited) { // Add(data); SaveSignal(data); } } /** * Update a Registered Data Model by Providing Specified Signal ... * usually used When a signal Modified after Executed for Conditionally Signals ... * * @param signal: XSignal instance Reference, Issued Signal ... */ void Update(XSignal &signal) { // // Validate Signal ... if (!signal.IsValid()) { return; } // // Check Signal Registered Before ... int idx = -1; bool hasItem = HasItem( signal, idx // ); bool isUpdated = false; if (!hasItem) { // // Add New Item if not Exists ... Add(signal); isUpdated = true; } else { // // Update Data Model in Datas Collection ... isUpdated = mData[idx].Update(signal); } // if (isUpdated) { SaveSignal(mData[idx]); } } /** * Update a Registered Data Model by Providing Specified Position ... * used for Updating Positions Data or When a Conditional Order Executed as Position ... * * @param position: XPosition instance Referece ... */ void Update(XPosition &position) { // // Validate Position ... if (!position.IsValid()) { return; } // // Check Position Registered Before ... int idx = -1; bool hasItem = HasItem( position, idx // ); if (!hasItem) { return; } // // Update Data Model in Datas Collection ... mData[idx].Update(position); } /** * Remove Specified Registered Signal from Data Collection ... * * @param signal: XSignal instance Reference ... */ void Remove(XSignal &signal) { // // Validate Signal ... if (!signal.IsValid()) { return; } // // Check Signal is Registered or not ... int idx = -1; bool hasItem = HasItem( signal, idx // ); if (!hasItem) { return; } // // Remove Data From Collection ... ArrayRemove( mData, idx, 1 // ); } /** * Handle Position Execution Finished by Providing a Deal ... * usually used when a Position TP/SL Triggered ... * * @param deal: XDeal instance Reference ... */ void Finish(const XDeal &deal) { // // Validate Deal ... // Check Specified Data Registered or not ... int idx = -1; bool hasItem = HasItem( deal.positionId, idx // ); if (!hasItem) { return; } // // Update Data Info ... mData[idx].swap = deal.swap; mData[idx].endTime = deal.time; mData[idx].profit = deal.profit; // // Check Deal Reason ... bool isTP = deal.reason == DEAL_REASON_TP; bool isSL = deal.reason == DEAL_REASON_SL; // // Prepare Specified Message Based on Deal Reason ... mData[idx].message = isTP ? "TP" : isSL ? "SL" : ""; // // Handle Symbol Positions TP or SL Actions ... if (isTP || isSL) { // // Check Symbol Position Info Model Exists ... int symbolIDX = -1; bool hasInfo = HasSymbol( mData[idx].GetSymbol(), symbolIDX // ); // // Try to Update or Add Symbol Position Info ... X121SMCSymbolPositionInfo info; if (!hasInfo) { // // Add New One ... info.symbol = mData[idx].GetSymbol(); } else { // // Update Exists ... info = mSymbolInfos[symbolIDX]; // // Remove Exists ... ArrayRemove( mSymbolInfos, symbolIDX, 1 // ); } // ENUM_POSITION_TYPE xType = IsLong(mData[idx].Type()) ? POSITION_TYPE_BUY : POSITION_TYPE_SELL; // // Call Propper TP / SL Handlers on Symbol Position Info Model ... if (isTP) { info.HandleTP(xType); } else if (isSL) { info.HandleSL(xType); } // // Add Model to Symbol Positions Collection ... AddRef( info, mSymbolInfos // ); // // Try to Check Symbol Positions Info Collection for Pause Specified Symbol ... HandlePauseSymbol(mData[idx].GetSymbol()); } // // Save Collector Calss Data Model ... Save(idx); } /** * Handle Position Execution Finished by Providing some Data ... * usually used when a Position Force Closed Triggered ... * * @param ticket: ULong, Position ticket ... * @param position: XPosition instance Reference ... * @param comment: String, Force Closing Comment ... */ void Finish( const ulong ticket, const XPosition &position, const string comment // ) { // // Validate and Check Data Registered or not ... int idx = -1; bool hasItem = HasItem( ticket, idx // ); if (!hasItem) { return; } // // Update Data Info ... mData[idx].swap = position.swap; mData[idx].endTime = TimeCurrent(); mData[idx].profit = position.profit; // mData[idx].message = comment; // // Handle Force Closes as TP/SL for Updating // Symbol Info Positions ... bool handleForceClose = true; if (handleForceClose) { // // Simulate TP/SL based on Closing Profit ... bool isTP = position.profit > 0; bool isSL = position.profit < 0; // if (isTP || isSL) { // // Check Symbol Position Info Model Exists ... int symbolIDX = -1; bool hasInfo = HasSymbol( mData[idx].GetSymbol(), symbolIDX // ); // // Try to Update or Add Symbol Position Info ... X121SMCSymbolPositionInfo info; if (!hasInfo) { // // Add New One ... info.symbol = mData[idx].GetSymbol(); } else { // // Update Exists ... info = mSymbolInfos[symbolIDX]; // // Remove Exists ... ArrayRemove( mSymbolInfos, symbolIDX, 1 // ); } // ENUM_POSITION_TYPE xType = IsLong(mData[idx].Type()) ? POSITION_TYPE_BUY : POSITION_TYPE_SELL; // // Call Propper TP / SL Handlers on Symbol Position Info Model ... if (isTP) { info.HandleTP(xType); } else if (isSL) { info.HandleSL(xType); } // // Add Model to Symbol Positions Collection ... AddRef( info, mSymbolInfos // ); // // Try to Check Symbol Positions Info Collection for Pause Specified Symbol ... HandlePauseSymbol(mData[idx].GetSymbol()); } // // Save Collector Calss Data Model ... Save(idx); } } /** * Update New Open Positions Data on Collection ... */ void HandleNewPosition() { // // Retrieve Last Open Position ... ulong lastOpenPositionTicket = mTrader.GetLastOpenPositionTicket(); if (lastOpenPositionTicket == 0) { return; } // XPosition position; bool hasPosition = mTrader.GetPosition( lastOpenPositionTicket, position // ); if (!hasPosition) { return; } // // Calculate Position Commission ... double commission = mTrader.GetPositionCommission(position.ticket); position.commission = commission; // // Apply Updates on Data Collection ... int idx = -1; bool hasItem = HasItemByPosition( position, idx // ); if (!hasItem) { return; } // mData[idx].UpdatePosition(position); } // // Symbol Position Info Actions ... /** * Retrieve Specified Symbols Info ... * * @param symbol: String ... * @param info: X121SMCSymbolPositionInfo instance ... * * @return ( bool ) */ bool GetSymbolInfo( string symbol, X121SMCSymbolPositionInfo &info // ) { // bool result = false; // info.Clean(); // int symbolIDX = -1; result = HasSymbol( symbol, symbolIDX // ); if (!result) { return result; } // info = mSymbolInfos[symbolIDX]; // return result; } /** * Pause Specified Symbol Trading ... * * @param symbol: String ... */ void HandlePauseSymbol(string symbol) { // if (!IsValid(symbol)) { return; } // int idx = -1; bool hasItem = HasSymbol( symbol, idx // ); if (!hasItem) { return; } // int maxAllowedSLToPause = MaxAllowedSLToPauseSignallingPerSymbol(); int pauseDelay = PauseSignallingAfterReachesMaxAllowedSLInSecconds(); if (maxAllowedSLToPause <= 0 || pauseDelay <= 0) { return; } // bool canPauseSymbol = mSymbolInfos[idx].IsEnable() && mSymbolInfos[idx].countedSLs >= maxAllowedSLToPause; if (!canPauseSymbol) { return; } // mSymbolInfos[idx].Pause(pauseDelay); // string message = "Pause (" + symbol + ") until: (" + ToString(mSymbolInfos[idx].enableAt) + ") ..."; Alert(message); // } /** * Reset Specified Symbol Info ... * * @param symbol: String ... */ void ResetSymbolInfo(string symbol) { // if (!IsValid(symbol)) { return; } // int symbolIDX = -1; bool hasSymbol = HasSymbol( symbol, symbolIDX // ); if (!hasSymbol) { return; } // mSymbolInfos[symbolIDX].Reset(); // string message = "Reset " + symbol + ", Pause State ..."; Alert(message); } /** * Reset All Paused Symbols ... */ void ResumePausedSymbols() { // int count = ArraySize(mSymbolInfos); if (!IsValidSize(count)) { return; } // for (int i = 0; i < count; i++) { // mSymbolInfos[i].Reset(); } // string message = "Force Resume Paused Symbols ..."; Alert(message); } // // Signal Execution Actions ... /** * Validate Signal For Execution ... * * @param signal: XSignal instance Reference ... * @param state: ENUM_X_SIGNAL_EXECUTION_RESULT Reference for olding Signal Execution Result Reason ... * * @return ( bool ) */ bool CanExecute( XSignal &signal, ENUM_X_SIGNAL_EXECUTION_RESULT &state // Execution State ) { // bool result = false; // state = X_SIGNAL_EXECUTION_UNKNOWN; // // Validate Signal ... result = signal.IsValid(); if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS; return result; } // int symbolIDX = -1; bool hasSymbolInfo = HasSymbol( signal.symbol, symbolIDX // ); // // Check rading Not Paused ... result = !hasSymbolInfo || mSymbolInfos[symbolIDX].IsEnable(); if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED; return result; } // bool isLong = IsLong(signal.type); // // Chekc Signalling Enable or not ... result = isLong ? mAllowLong : mAllowShort; if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED; return result; } // // Check Signal is Support or not ... bool isSupport = IsSupport(signal.comment); result = !isSupport; if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED; return result; } // ENUM_X_POSITION_TYPES pType = ToPositionType(signal.type); double requiredProfitForAcceptNext = LastPositionProfitForAcceptNextInPoint(); // // 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) { // state = X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR; return result; } // // Retrieve Longs and Shorts ... XPosition longs[]; XPosition shorts[]; bool useMaxAllowedPositionsPerSymbol = UseMaxAllowedSignalsPerSymbol(); // // Retrieve Positions ... if (useMaxAllowedPositionsPerSymbol) { // mTrader.GetPositions( longs, shorts, signal.symbol // ); } else { // mTrader.GetPositions( longs, shorts, NULL // All Symbols ... ); } // // Counting ... int longsCount = ArraySize(longs); int shortsCount = ArraySize(shorts); // int maxAllowedLongs = MaxAllowedLongs(); int maxAllowedShorts = MaxAllowedShorts(); // // Check Max Allowed Positions ... if (maxAllowedLongs > 0 || maxAllowedShorts > 0) { // if (isLong && maxAllowedLongs > 0 && longsCount > 0) { result = longsCount < maxAllowedLongs; } else if (!isLong && maxAllowedShorts > 0 && shortsCount > 0) { result = shortsCount < maxAllowedShorts; } if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED; return result; } } // // Check Delays Bar if Provided ... int delaysBarBetweenTwoSignal = DelaysBetweenTwoSignalsInBar(); if (delaysBarBetweenTwoSignal > 0) { // // Try To Detect Youngest Position ... 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 // ); } // // Check Delays When Youngest Position Exists ... if (youngestAge > 0 && youngestPosition.IsValid()) { // result = youngestAge >= delaysBarBetweenTwoSignal; if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED; return result; } } // // Check Delays When Youngest Position is not Exists ... if (!youngestPosition.IsValid()) { // // Try to Detect Last Issued Signal in Model Collections ... int symbolIDX = FindLastExecutedSignalItem(signal); if (IsValidIndex(symbolIDX)) { // // Calculate Requirements ... datetime cTime = TimeCurrent(); int signalPeriodSeconds = PeriodSeconds(signal.period); datetime lastExecutedTime = mLastExecutedSignals[symbolIDX].time; datetime passedTime = ((datetime)lastExecutedTime + ((delaysBarBetweenTwoSignal * signalPeriodSeconds))); // // Check Conditions ... result = cTime >= passedTime; if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED; return result; } } } } // // Check Max Drawdown Percent for Open Trades ... double maxAllowedDrawdownPercent = MaxAllowedDrawdownToOpenTrades(); if (maxAllowedDrawdownPercent > 0) { // // Calculate and Update Drawdown Percent ... double cdPercent = CalculateMaxDrawdownPercent(); // result = cdPercent < maxAllowedDrawdownPercent; if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_NO_EQUITY; return result; } } // // Check Spread ... double spread = GetSpread(signal.symbol); double maxAllowedSpread = MaxAllowedSpread(); if (maxAllowedSpread > 0) { // result = spread <= maxAllowedSpread; if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_SPREAD; return result; } } // return result; } /** * Execute Specific Signal using Trade Handler ... * * @param signal: XSignal instance Reference ... * @param state: ENUM_X_SIGNAL_EXECUTION_RESULT Reference for olding Signal Execution Result Reason ... * @param ignorePolicies: Boolean ... * * @return ( bool ) */ bool ExecuteSignal( XSignal &signal, // Signal for Execution ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Execution State bool ignorePolicies = false // Ignore Execution Policies ) { // bool result = false; // // Check Signal Validation ... result = signal.IsValid(); if (!result) { return result; } // // Check Policies ... if (!ignorePolicies) { // // Filter Signals if Necessary ... result = CanExecute( signal, state // ); if (!result) { return result; } } // // Apply Additional Volume to Signal if Provided ... double additionalVolume = AdditionalVolume(); if (additionalVolume > 0) { signal.volume += mAdditionalVolume; } // // Execute Signal ... result = mTrader.ExecuteSignal( signal, state // ); if (result) { // // Add XTradeHandler Data ... Add(signal); // // Handle Last Executed Signal ... HandleSignalExecuted(signal); // // Alert Executed Signal ... 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); } // if (!result) { // // Alert Signal Execution Failed ... string msg = "Failed To Execute " + (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) + " due Reason: " + ToString(state) + " ..."; Alert(msg); } // return result; } // // Timing Actions ... /** * Update Currently Open Positions Info on Data Collection ... */ void UpdateData() { // // Retrieve Positions ... XPosition positions[]; int count = mTrader.GetPositions(positions); if (!IsValidSize(count)) { return; } // // Loop Through Positions ... for (int i = 0; i < count; i++) { // XPosition iPosition = positions[i]; // // Check Position Registered as Data or not ... int idx = -1; bool isExists = HasItem( iPosition.ticket, idx // ); if (isExists) { // // Update Position Data ... mData[idx].Update(iPosition); } } } /** * Handle Positiona Protections */ void HandleProtection() { // // Implement Protection Senario Here ... int count = Count(); if (!IsValidSize(count)) { // currentDrawdown = 0; return; } // // Calculate Max Same Time Trades ... maxSameTimeTrades = maxSameTimeTrades == 0 || maxSameTimeTrades < count ? count : maxSameTimeTrades; // double bepSummary = 0; double volumeSummary = 0; double profitSummary = 0; XPosition positions[]; // // Loop through Open Positions ... for (int i = 0; i < count; i++) { // X121SMCTradeData iData = mData[i]; // XPosition iPosition; bool hasPosition = mTrader.GetPosition( iData.ticket, iPosition // ); if (!hasPosition) { continue; } AddRef( iPosition, positions // ); // // Calculate Break Even Point ... double entry = iPosition.entry; double points = iData.Points(); double volume = iPosition.volume; bool isLong = IsLong(iData.Type()); double spread = GetSpread(iData.GetSymbol()); double bep = iData.CalculateBreakEvenPoint(); double exitPrice = GetExit( iPosition.symbol, iPosition.type // ); // double tps[]; double reachedTPLevel = -1; double reachedTPPrice = 0; int tpLevelsCount = iPosition.CalculateTPLevels(tps); iPosition.CalculateReahedTP( reachedTPLevel, reachedTPPrice // ); // bepSummary += bep; volumeSummary += volume; profitSummary += iPosition.profit; // // All Protections Done for InProfit Positions ... if (iData.profit > 0) { // // Check Break Even ... bool canRFOnBEP = iData.CanRiskFreeOnBreakEvenPoint(); if (canRFOnBEP && reachedTPLevel > 0) { // double tpLevel = iData.TPLevelForBreakEven(); int tpIDX = (int)tpLevel - 1; double rfTPPrice = tps[tpIDX]; bool isSLReady = isLong ? iPosition.sl < rfTPPrice : iPosition.sl > rfTPPrice; if (isSLReady && tpLevel == reachedTPLevel - 1) { // double sl = rfTPPrice; double tp = iPosition.tp; string comment = "RF on BEP ..."; bool isModified = mTrader.Modify( iData.ticket, sl, tp, comment // ); if (isModified) { // string message = ToString(iData.Type()) + " Position: " + ToString(iData.ticket) + " RF On BEP Successfully ..."; Alert(message); } } } // // Check Partial Close ... bool canPartialClose = iData.CanPartialClose(); if (canPartialClose && reachedTPLevel > 0) { // double mainVolume = iData.Volume(); double currentVolume = iPosition.volume; double partialCloseOnTP = iData.PartialCloseOnTPLevel(); double partialCloseVolumeMultiplier = iData.PartialCloseMultiplier(); double closeVolume = currentVolume * partialCloseVolumeMultiplier; closeVolume = NormalizeVolume(closeVolume, iPosition.symbol); canPartialClose = currentVolume == mainVolume && reachedTPLevel == partialCloseOnTP; if (canPartialClose) { // string comment = "PC On TP Level: " + ToString(partialCloseOnTP) + " ..."; bool isModified = mTrader.ClosePartial( iData.ticket, closeVolume, comment // ); if (isModified) { // string message = ToString(iData.Type()) + " Position: " + ToString(iData.ticket) + " PC (" + ToString(closeVolume) + ") On TP Level: " + ToString(partialCloseOnTP) + " Successfully ..."; Alert(message); // // Finish Position ... if (closeVolume == mainVolume) { // Finish( iPosition.ticket, iPosition, comment // ); // break; } } } } // // Check for SL Trail ... bool canTrailSL = iData.CanTrailSL(); if (canTrailSL && reachedTPLevel > 0) { // double startTrailTPLevel = iData.TrailSLStartOnReachTPLevel(); int tSLTPIndex = (int)reachedTPLevel - 1; double tSLTPPrice = tps[tSLTPIndex]; canTrailSL = reachedTPLevel >= startTrailTPLevel && (isLong ? iPosition.sl < tSLTPPrice : iPosition.sl > tSLTPPrice); if (canTrailSL) { // string comment = "Trail SL on Reached TP: " + ToString(reachedTPLevel) + " ..."; double sl = tSLTPPrice; double tp = iPosition.tp; bool isModified = mTrader.Modify( iData.ticket, sl, tp, comment // ); if (isModified) { // string message = ToString(iData.Type()) + " Position: " + ToString(iData.ticket) + " Trailed SL On Reached TP: " + ToString(reachedTPLevel) + " Successfully ..."; Alert(message); } } } } } // // Calculate Max Draw Down ... maxDrawdown = profitSummary < 0 && (maxDrawdown == 0 || maxDrawdown < profitSummary) ? profitSummary : maxDrawdown; // // Calculate Current Drawdown ... currentDrawdown = profitSummary < 0 ? profitSummary : 0; // // Checking Hedge ... bool allowHedge = AllowHedging(); if (allowHedge) { // double minHedgeVolumeStep = HedgingMinVolumeStep(); int minRequiredPositionsForHedge = MinOpenTradesFroHedging(); double minRequiredProfitPerVolumeStepForHedge = HedgeingMinRequiredProfitPerVolumeStep(); // double minRequiredAdditionalProfit = bepSummary + ((volumeSummary / minHedgeVolumeStep) * minRequiredProfitPerVolumeStepForHedge); // bool canHedge = AllowHedging() && profitSummary > 0 && minHedgeVolumeStep > 0 && minRequiredProfitPerVolumeStepForHedge > 0 && profitSummary >= minRequiredAdditionalProfit && (minRequiredPositionsForHedge <= 0 ? true : count >= minRequiredPositionsForHedge); if (canHedge) { // string comment = "Hedge (" + ToString(count) + ") Positions By: " + ToString(profitSummary) + "..."; int closedPositionsCount = mTrader.Close( positions, comment // ); if (IsValidSize(closedPositionsCount)) { // // Finish Positions and Clear Data ... for (int i = 0; i < ArraySize(positions); i++) { // XPosition iPosition = positions[i]; Finish( iPosition.ticket, iPosition, comment // ); } // string message = "Hedge (" + ToString(count) + ") Positions By: " + ToString(profitSummary) + " Successfully ..."; Alert(message); } } } } // // Protected ... protected: // XCTrade *mTrader; // Instance of Trader Class X121SMCTradeCollector *mCollector; // Instance of Trade Collector Class // X121SMCTradeData mData[]; // Hold Trade Data X121SMCSymbolPositionInfo mSymbolInfos[]; // Symbol Positions Info XSymbolLastPosition mLastExecutedSignals[]; // Last Executed Signals // // Hedge Related Functions ... // // Private ... private: // // Props ... // // Read Only ... int maxSameTimeTrades; // Holds Max Same Time Trades double maxDrawdown; // Max Drawdown double currentDrawdown; // Current 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 // // Signalling Props ... bool mAllowLong; // Allow Long Signals ... bool mAllowShort; // Allow Short Signals ... int mMaxAllowedLongs; // Max Allowed Long Signals ... int mMaxAllowedShorts; // Max Allowed Short Signals ... bool mUseMaxAllowedSignalsPerSymbol; // Use Max Allowed Signal Types Per Symbol ... double mLastPositionProfitForAcceptNextInPoint; // Last Position Profit In Points for Accept new Signal ... int mDelaysBetweenTwoSignalsInBar; // Delay between two Signals in Bars ... double mMaxAllowedSpread; // Max Allowed Spread for Signalling ... double mAdditionalVolume; // Volume Additional ... // // Risk Management Props ... double mMaxAllowedDrawdownToOpenTrades; // Max Allowed Drawdown for Open Trades ... int mMaxAllowedSLToPauseSignallingPerSymbol; // Max Allowed SL for Pause Signalling Per Symbol ... int mPauseSignallingAfterReachesMaxAllowedSLInSecconds; // Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds ... // // Protection Props ... bool mAllowHedging; // Allow Hedge Positions ... int mMinOpenTradesFroHedging; // Minimum Open Positions for Hedging ... double mHedgingMinVolumeStep; // Minimum Volume Step for Hedging ... double mHedgeingMinRequiredProfitPerVolumeStep; // Minimum Required Profit Per Volume Step for Hedging ... // XCBarAnalyser mBarAnalyser; // // Common Functions ... // // Count Data ... int Count() { return ArraySize(mData); } // // Add Item ... bool Add(X121SMCTradeData &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.signal, 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; } // bool HasItem( XSignal &signal, int &index // ) { // bool result = false; // index = -1; // int count = Count(); result = signal.IsValid() && IsValidSize(count); if (!result) { return result; } // for (int i = 0; i < count; i++) { // bool isOwn = mData[i].IsOwn(signal); if (isOwn) { // index = i; break; } } // result = IsValidIndex(index); // return result; } // bool HasItem( XPosition &position, int &index // ) { // bool result = false; // index = -1; // int count = Count(); result = position.IsValid() && IsValidSize(count); if (!result) { return result; } // for (int i = 0; i < count; i++) { // bool isOwn = mData[i].IsOwn(position); if (isOwn) { // index = i; break; } } // result = IsValidIndex(index); // return result; } // bool HasItemByPosition( XPosition &position, int &index // ) { // bool result = false; // index = -1; // int count = Count(); result = position.IsValid() && IsValidSize(count); if (!result) { return result; } // for (int i = 0; i < count; i++) { // bool isOwn = mData[i].IsOwnPosition(position); if (isOwn) { // index = i; break; } } // result = IsValidIndex(index); // return result; } /** * Find Specific Symbo Indo Item index ... * * @param symbol: String ... * @param index: Integer ... * * @return ( bool ) */ bool HasSymbol( string symbol, int &index // ) { // bool result = false; // index = -1; // result = IsValid(symbol); if (!result) { return result; } // int count = ArraySize(mSymbolInfos); result = IsValidSize(count); if (!result) { return result; } // for (int i = 0; i < count; i++) { // bool isOwn = mSymbolInfos[i] .IsOwn(symbol); if (isOwn) { // index = i; break; } } // result = IsValidIndex(index); // 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(X121SMCTradeData &item) { // if (!mSaveSignals) { return; } // // Save Signal ... mCollector.SaveSignal(item); } // // Find Last Signal Execution ... int FindLastExecutedSignalItem(XSignal &signal) { // int result = -1; // if (!signal.IsValid()) { return result; } // int count = ArraySize(mLastExecutedSignals); if (!IsValidSize(count)) { return result; } // for (int i = 0; i < count; i++) { // XSymbolLastPosition iLast = mLastExecutedSignals[i]; if (iLast.symbol == signal.symbol && iLast.provider == signal.provider) { // result = i; break; } } // return result; } // // Handle Last Signal Execution ... void HandleSignalExecuted(XSignal &signal) { // if (!signal.IsValid()) { return; } // datetime cTime = TimeCurrent(); int symbolIDX = FindLastExecutedSignalItem(signal); bool hasItem = IsValidIndex(symbolIDX); if (hasItem) { mLastExecutedSignals[symbolIDX].time = cTime; } else { // XSymbolLastPosition item; // item.time = cTime; item.symbol = signal.symbol; item.provider = signal.provider; // AddRef( item, mLastExecutedSignals // ); } } // double CalculateMaxDrawdownPercent() { // double result = 0; // double mEquity = mTrader.mAccount.GetEquity(); if (mEquity > currentDrawdown) { currentDrawdown = mEquity; } // if (currentDrawdown >= 0) { // drawdownPercent = 0; return result; } // drawdownPercent = (currentDrawdown - mEquity) / (staticBalanceForCalculateDrawdown > 0 ? staticBalanceForCalculateDrawdown : currentDrawdown) * 100; drawdownPercent = NormalizeDouble(drawdownPercent, 3); result = drawdownPercent; // return result; } // // End of XC121SMCTradeHandler Class ... }; //