diff --git a/Classes/x-saherelm.xtrade.class.mq5 b/Classes/x-saherelm.xtrade.class.mq5 index 9f7e1d7e..30d08701 100644 --- a/Classes/x-saherelm.xtrade.class.mq5 +++ b/Classes/x-saherelm.xtrade.class.mq5 @@ -3773,6 +3773,279 @@ private: } }; +// +// a Class For Read and Write Trade Info Data in Files ... +class XTradeCollector +{ + // + // Public ... +public: + // + // Props ... + + // + // Constructor(s) ... + void XTradeCollector( + string _path = NULL // Base Path + ) + { + // + mAccount = new XSCAccount(); + + // + if (IsValid(_path)) + { + mPath = _path; + } + else + { + mPath = "XTradeData" + "\\" + mAccount.GetCompany(); + } + } + + // + // Deconstructor ... + void ~XTradeCollector() {} + + // + bool IsExists(XTradeData &item) + { + // + bool result = false; + + // + int mHandler = GetFileHandlerForRead(item); + result = mHandler != INVALID_HANDLE; + FileClose(mHandler); + + // + return result; + } + + // + bool Save(XTradeData &item) + { + // + bool result = false; + + // + // Check info is Valid ... + result = item.IsValid(); + if (!result) + { + return result; + } + + // + string content = item.ToString(); + 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(XTradeData &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; + } + + // + // Protected ... +protected: + // + // Private ... +private: + // + // Props ... + + // + string mPath; // Base Path ... + + // + XSCAccount *mAccount; + + // + string GetFilePath(XTradeData &item) + { + // + string fileName = item.GetFileName(); + + // + return GetFilePath(fileName); + } + string GetFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + mPath + "\\" + "Trades" + "\\" + fileName + ".x121.log" + // + ; + + // + return result; + } + + // + string GetSignalFilePath(XTradeData &item) + { + // + string fileName = item.GetSignalFileName(); + + // + return GetSignalFilePath(fileName); + } + string GetSignalFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + mPath + "\\" + "Signals" + "\\" + fileName + ".x121.log" + // + ; + + // + return result; + } + + // + int GetFileHandlerForRead(XTradeData &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(XTradeData &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(XTradeData &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(XTradeData &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; + } +}; + // // Trade Handler Class ... class XSCXTradeHandler : public XSCBaseAlert @@ -3788,6 +4061,7 @@ public: { // mTrader = trader; + mCollector = new XTradeCollector(); } // @@ -3796,8 +4070,39 @@ public: { // 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; + } + + // + // Tools ... + // // First Step of Trade Handling ... // Since Must Call when a Signal Executed ... @@ -3826,6 +4131,70 @@ public: // 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); } // @@ -3912,7 +4281,15 @@ public: // Protected ... protected: // - XSCTrade *mTrader; // Instance of Trader Class + // Props ... + + // + bool mSaveSignals; // Save Signals + bool mSaveTrades; // Save Trades + + // + XSCTrade *mTrader; // Instance of Trader Class + XTradeCollector *mCollector; // Instance of Trade Collector Class // XTradeData mData[]; // Hold Trade Data @@ -4081,6 +4458,46 @@ private: // return result; } + + // + void Save(int index) + { + // + int count = Count(); + if (!IsValidIndex(index) || index > count - 1) + { + return; + } + + // + // Save Trade ... + if (mSaveTrades) + { + mCollector.Save(mData[index]); + } + + // + // Remove Item From List ... + ArrayRemove( + mData, + index, + 1 // + ); + } + + // + void SaveSignal(XTradeData &item) + { + // + if (!mSaveSignals) + { + return; + } + + // + // Save Signal ... + mCollector.SaveSignal(item); + } }; // \ No newline at end of file diff --git a/Experts/x-test-strategies.ea.mq5 b/Experts/x-test-strategies.ea.mq5 index e526dc45..00ac814b 100644 --- a/Experts/x-test-strategies.ea.mq5 +++ b/Experts/x-test-strategies.ea.mq5 @@ -145,6 +145,13 @@ void OnTick() HandleStrategiesOnTick(); } +// +// Handle On Trade Event ... +void OnTrade() +{ + eaTrader.HandleOnTrade(); +} + // // On Timer ... void OnTimer() @@ -212,7 +219,14 @@ bool InitialEA() eaSlippage, eaMagicNumber // ); + eaTrader.AddOnStopLossEventHandler(OnStopLossTriggered); + eaTrader.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); + eaTrader.AddOnForceClosePositionEventHandler(OnPositionForceClosed); + + // eaTradeHandler = new XSCXTradeHandler(eaTrader); + eaTradeHandler.SaveTrades(true); + eaTradeHandler.SaveSignals(true); // XSymbolParser symbolParser; @@ -324,7 +338,7 @@ void HandleTradeState() { // // Implement All Trade States here ... - eaTradeHandler.UpdateData(); + eaTradeHandler.UpdateData(); } // @@ -388,6 +402,36 @@ void OnSignalRecieved(XSignal &signal) } // -// Custom Testing Functions ... +// Trader Event Handlers for Trade Handling ... + +// +void OnStopLossTriggered(const XDeal &deal) +{ + // Finish ... + eaTradeHandler.Finish(deal); +} + +// +void OnTakeProfitTriggered(const XDeal &deal) +{ + // Finish ... + eaTradeHandler.Finish(deal); +} + +// +void OnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // +) +{ + // + // Finish ... + eaTradeHandler.Finish( + ticket, + position, + comment // + ); +} // \ No newline at end of file diff --git a/Libraries/x-saherelm.xtrade.lib.mq5 b/Libraries/x-saherelm.xtrade.lib.mq5 index 4c09d2e2..997c25ba 100644 --- a/Libraries/x-saherelm.xtrade.lib.mq5 +++ b/Libraries/x-saherelm.xtrade.lib.mq5 @@ -3480,13 +3480,15 @@ struct XTradeData // // Update Data ... - bool Update(XPosition &_position) { + bool Update(XPosition &_position) + { // bool result = false; // result = _position.IsValid(); - if (!result) { + if (!result) + { return result; } @@ -3654,7 +3656,7 @@ struct XTradeData // symbol + "\\" + ToString(type) + "\\" + - (profit >= 0 ? "Profit" : "Loss") + + (profit >= 0 ? "Profit" : "Loss") + "\\" + ToString(ticket) + "_" + ToString(period) + "_" + ToFormatString(time) @@ -3731,6 +3733,23 @@ struct XTradeData return result; } + // + // There are some Controlling Situations for each Trade + // which implemented here ... + + // + // Trailing Stop .... + + // + bool canTrail; // Specified Position Can Trail Stop or not + + // + // Reset all Trailing Configurations .... + void ResetTrail() { + // + canTrail = false; + } + // };