/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class Library // -------------------------------------- // Name: XClass // Description: provides all 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 // #include #include #include #include #include #include // #include "../Libraries/x-saherelm.draw.lib.mq5" #include "../Libraries/x-saherelm.alert.lib.mq5" #include "../Libraries/x-saherelm.models.lib.mq5" #include "../Libraries/x-saherelm.common.lib.mq5" // // START Constant Definitions ... // static uchar _md5_PADDING[64] = { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; #define _md5_F(x, y, z) (((x) & (y)) | ((~x) & (z))) #define _md5_G(x, y, z) (((x) & (z)) | ((y) & (~z))) #define _md5_H(x, y, z) ((x) ^ (y) ^ (z)) #define _md5_I(x, y, z) ((y) ^ ((x) | (~z))) #define _md5_ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) #define _md5_FF(a, b, c, d, x, s, ac) \ { \ (a) += _md5_F((b), (c), (d)) + (x) + (uint)(ac); \ (a) = _md5_ROTATE_LEFT((a), (s)); \ (a) += (b); \ } #define _md5_GG(a, b, c, d, x, s, ac) \ { \ (a) += _md5_G((b), (c), (d)) + (x) + (uint)(ac); \ (a) = _md5_ROTATE_LEFT((a), (s)); \ (a) += (b); \ } #define _md5_HH(a, b, c, d, x, s, ac) \ { \ (a) += _md5_H((b), (c), (d)) + (x) + (uint)(ac); \ (a) = _md5_ROTATE_LEFT((a), (s)); \ (a) += (b); \ } #define _md5_II(a, b, c, d, x, s, ac) \ { \ (a) += _md5_I((b), (c), (d)) + (x) + (uint)(ac); \ (a) = _md5_ROTATE_LEFT((a), (s)); \ (a) += (b); \ } #define _md5_INIT_STATE_0 0x67452301 #define _md5_INIT_STATE_1 0xefcdab89 #define _md5_INIT_STATE_2 0x98badcfe #define _md5_INIT_STATE_3 0x10325476 #define _md5_S11 7 #define _md5_S12 12 #define _md5_S13 17 #define _md5_S14 22 #define _md5_S21 5 #define _md5_S22 9 #define _md5_S23 14 #define _md5_S24 20 #define _md5_S31 4 #define _md5_S32 11 #define _md5_S33 16 #define _md5_S34 23 #define _md5_S41 6 #define _md5_S42 10 #define _md5_S43 15 #define _md5_S44 21 // // END Constant Definitions ... // // // START Model Definitions ... // // string X_SIGNAL_TP = "TP"; string X_SIGNAL_SL = "SL"; string X_SIGNAL_TYPE = "TY"; string X_SIGNAL_TICKET = "T"; string X_SIGNAL_RISKFREE_STEP = "RFS"; string X_SIGNAL_RISKFREE_RATE = "RFR"; // // Model Signal Handler Result on XCTrade Class ... struct XTraderHandlerResult { // // List Of Closed On SL Signals ... XSignal sl[]; // // List Of Closed On TP Signals ... XSignal tp[]; // // List Of Risk Free Signals ... XSignal rf[]; }; // // Model OnTrade Event Handler Result on XCTrade Class ... struct XOnTradeHandlerResult { // bool hasNewDeal; int newDeals; // bool hasNewOrder; int newOrders; // bool hasNewPosition; int newPositions; // bool hasNewHistoryOrder; int newHistoryOrders; }; // // Model Guard Action Applied Signals ... struct XGuardHandlerResult { // // Critical Guard ... XSignal criticals[]; // // Max Guard ... XSignal maxes[]; // // Old ... XSignal olds[]; // // Determines Stopout Action Cals or not ... bool isStopOut; }; // // Define Volume States ... struct XVolumeInfo { // // Current Available Static Volume ... double staticVolume; // // Static Volume Calculation Method ... string staticVolumeCalculationMethod; // // Current Maximum Appliable Volume ... double maxAllowedVolume; // // Static Volume Increase Multiplier ... double volumeIncreaseMultiplier; // // Multiply Volume Based On Balance Growing ... double balanceGowingToApplyMultiplier; // // Where to Increase MaxAllowed Volume ... double balanceGrowingToIncreaseMaxAllowedVolume; }; // // Model a Simple Provider Status ... struct XSignallerInfo { // // Provider Name ... string name; // // Number of Longs ... int longs; // // Number of Shorts ... int shorts; }; // // Model Some of Usefull Signals and Market Data ... struct XSummaryInfo { // // Define Max Signal Volume ... double maxSignalVolume; // // Max DrawDown ... double maxDrawDown; // // Max DrawUp ... double maxDrawUp; // // Max Number of Same Time Signals ... int maxSameTimeSignals; // // Number of Long Trades ... int longSignals; // // Number of Short Trades ... int shortSignals; // // Number of TPs Attached ... int numberOfTPs; // // Number of SLs Attached ... int numberOfSLs; }; // // Model Account info ... struct XAccountInfo { // // User Account ... string user; // // Name of Client ... string name; // // Trade Server Name ... string server; // // Broker Name ... string broker; // // Account Trade Mode ... ENUM_ACCOUNT_TRADE_MODE mode; // // Account Leverage ... long leverage; // // Currency ... string currency; // // Deposit ... double deposit; // // Balance ... double balance; // // Min Balance for Open Trades ... double minBalanceForOpenTrades; }; // // this is a Model Which holds Reports for Specific Time Periods ... struct XReport { // datetime start; // datetime end; // XAccountInfo accountInfo; // XVolumeInfo volumeInfo; // XSignallerInfo signallersInfo[]; // XSummaryInfo summaryInfo; }; // // an Enumeration Object which determines Report Type ... enum ENUM_XREPORT_TYPES { // // Main Report ... XREPORT_MAIN, // // Daily Report ... XREPORT_DAILY, // // Weekly Report ... XREPORT_WEEKLY, // // Monthly Report ... XREPORT_MONTHLY, }; // // a Signal Protection Structure ... struct XProtectedSignal { // ulong ticket; // datetime time[]; // double profit[]; }; // // Represent Collector State Based on Time ... struct XCollector { // // time in checking ... datetime time; // // Signal Volume ... double volume; // // Max DrawDown in Check Time ... double maxDrawDown; // // Max Allowed Volume in Check Time ... double maxAllowedVolume; // // Minimum required Balance for Opening Trades at Check Time ... double minBalanceForOpenTrade; }; // // Cross Signals Methods ... enum ENUM_X_CROSS_SIGNAL_METHOD { // // Do Nothing and Ignore them ... X_CROSS_SIGNAL_DO_NOTHING, // // Accept all Cross Signals and Act Usually ... X_CROSS_SIGNAL_REGULAR, // // Accept all Cross Signals and for Directional Act Usually and for Indirectional Ac Important ... X_CROSS_SIGNAL_DIRECTION_REGULAR_INDIRECTION_IMPORTANT, // // Accept all Cross Signals and for Directional Act Important and for Indirectional Ac Usually ... X_CROSS_SIGNAL_DIRECTION_IMPORTANT_INDIRECTION_REGULAR, // // Accept Only Indirectional Signals and Act Usually ... X_CROSS_SIGNAL_INDIRECTION_REGULAR, // // Accept Only Directional Signals and Act Usually ... X_CROSS_SIGNAL_DIRECTION_REGULAR, // // Accept Only Indirectional Signals and Act Important ... X_CROSS_SIGNAL_INDIRECTION_IMPORTANT, // // Accept Only Directional Signals and Act Important ... X_CROSS_SIGNAL_DIRECTION_IMPORTANT, }; // // the Action which Guard Handler Can Done when Attacked ... enum ENUM_X_GUARD_ACTIONS { // // Do Nothing ... X_GUARD_DO_NOTHING, // // Close All Open Positions ... X_GUARD_CLOSE_ALL, // // Close Max In Drawdown Position ... X_GUARD_CLOSE_MAX_IN_DD, // // Partial Close Max In Drawdown Position by 1% of Volume ... X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_1, // // Partial Close Max In Drawdown Position by 2% of Volume ... X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_2, // // Partial Close Max In Drawdown Position by 3% of Volume ... X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_3, // // Partial Close Max In Drawdown Position by 5% of Volume ... X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_5, // // Partial Close Max In Drawdown Position by 10% of Volume ... X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_10, // // Partial Close Max In Drawdown Position by 15% of Volume ... X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_15, // // Partial Close Max In Drawdown Position by 20% of Volume ... X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_20, // // Partial Close Max In Drawdown Position by 25% of Volume ... X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_25, // // Partial Close Max In Drawdown Position by 30% of Volume ... X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_30, // // Partial Close Max In Drawdown Position by 40% of Volume ... X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_40, // // Partial Close Max In Drawdown Position by 50% of Volume ... X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_50, // // Partial Close Max In Drawdown Position by 60% of Volume ... X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_60, // // Partial Close Max In Drawdown Position by 70% of Volume ... X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_70, // // Partial Close Max In Drawdown Position by 75% of Volume ... X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_75, }; // // Guard Reason ... enum ENUM_X_GUARD_REASONS { // // Critical ... X_GUARDED_CRITICAL, // // Max ... X_GUARDED_MAX, // // Old ... X_GUARDED_OLD }; // // All Suuported Support Positions Guard ... enum ENUM_X_GUARD_SUPPORT_METHODS { // // Ignore Supporting ... X_SUPPORT_DO_NOTHING, // // Full Both Side Support ... X_SUPPORT_FULL, // // Indirectional Supports On Drawing Down ... X_SUPPORT_IN_DRAWDOWN_INDIRECTIONAL, // // Directional Supports On Drawing Up ... X_SUPPORT_IN_DRAWUP_DIRECTIONAL, }; // // END Model Definitions ... // // // START Overrides ... // // // XBase Class ... class XCBase { // // Public ... public: // // Protected ... protected: // void AddItemToBuffer( double item, // Specified Item double &buffer[] // Specified Buffer ) { // int bufferSize = ArraySize(buffer); // ArrayResize( buffer, bufferSize + 1); // buffer[bufferSize] = item; } void AddItemToBuffer( datetime item, // Specified Item datetime &buffer[] // Specified Buffer ) { // int bufferSize = ArraySize(buffer); // ArrayResize( buffer, bufferSize + 1); // buffer[bufferSize] = item; } void AddItemToBuffer( XSignal &item, XSignal &buffer[]) { // ArrayResize( buffer, ArraySize(buffer) + 1); // buffer[ArraySize(buffer) - 1] = item; } void AddItemToBuffer( XCollector &item, // Specified Item XCollector &buffer[] // Specified Buffer ) { // int bufferSize = ArraySize(buffer); // ArrayResize( buffer, bufferSize + 1); // buffer[bufferSize] = item; } void AddItemToBuffer( XSignallerInfo &item, XSignallerInfo &buffer[]) { // ArrayResize( buffer, ArraySize(buffer) + 1); // buffer[ArraySize(buffer) - 1] = item; } void AddItemToBuffer( XProtectedSignal &item, // Item ... XProtectedSignal &buffer[] // Buffer ... ) { // int bufferSize = ArraySize(buffer); // ArrayResize( buffer, bufferSize + 1); buffer[bufferSize] = item; } // void CleanBuffer(double &buffer[]) { // ArrayFree(buffer); ArrayResize(buffer, 0); } void CleanBuffer(XDeal &buffer[]) { // ArrayFree(buffer); ArrayResize(buffer, 0); } void CleanBuffer(XOrder &buffer[]) { // ArrayFree(buffer); ArrayResize(buffer, 0); } void CleanBuffer(XSignal &buffer[]) { // ArrayFree(buffer); ArrayResize(buffer, 0); } void CleanBuffer(XCollector &buffer[]) { // ArrayFree(buffer); ArrayResize(buffer, 0); } void CleanBuffer(XSignallerInfo &buffer[]) { // ArrayFree(buffer); ArrayResize(buffer, 0); } void CleanBuffer(XProtectedSignal &buffer[]) { // ArrayFree(buffer); ArrayResize(buffer, 0); } // void CopyBuffer( const XSignallerInfo &source[], // Source Buffer ... XSignallerInfo &dest[] // Dest Buffer ... ) { // CleanBuffer(dest); // int sourceCount = ArraySize(source); if (sourceCount <= 0) { return; } // // Loop ... for (int i = 0; i < sourceCount; i++) { // XSignallerInfo iInfo = source[i]; // AddItemToBuffer( iInfo, dest); } } void CopyBuffer( XProtectedSignal &source[], // Source Buffer to Copy XProtectedSignal &dest[] // Fill this buffer using source ) { // CleanBuffer(dest); // int sourceCount = ArraySize(source); if (sourceCount <= 0) { return; } // for (int i = 0; i < sourceCount; i++) { // XProtectedSignal iItem = source[i]; // AddItemToBuffer( iItem, dest); } } // // Private ... private: }; // // XCTrade Base Class ... class XSCTrade : public CTrade { public: // // Modify Specific Position, by Specific Comment ... bool PositionModify( const string symbol, // Symbol const double sl, // Stop Loss const double tp, // Take Profit const string comment = "" // Comment For Modify ) { // // check stopped if (IsStopped(__FUNCTION__)) { return (false); } // // check position existence if (!SelectPosition(symbol)) { return (false); } // // clean ClearStructures(); // // setting request m_request.action = TRADE_ACTION_SLTP; m_request.symbol = symbol; m_request.magic = m_magic; m_request.sl = sl; m_request.tp = tp; m_request.position = PositionGetInteger(POSITION_TICKET); // // Specified Comment ... if (StringLen(comment) > 0) { m_request.comment = comment; } // // action and return the result return (OrderSend(m_request, m_result)); } bool PositionModify( const ulong ticket, // Position Ticket const double sl, // Stop Loss const double tp, // Take Profit const string comment = "" // Comment For Modify ) { // // check stopped if (IsStopped(__FUNCTION__)) { return (false); } // // check position existence if (!PositionSelectByTicket(ticket)) { return (false); } // // clean ClearStructures(); // // setting request m_request.action = TRADE_ACTION_SLTP; m_request.position = ticket; m_request.symbol = PositionGetString(POSITION_SYMBOL); m_request.magic = m_magic; m_request.sl = sl; m_request.tp = tp; // // Specified Comment ... if (StringLen(comment) > 0) { m_request.comment = comment; } // // action and return the result return (OrderSend(m_request, m_result)); } // // Close Specific Position, by Specific Comment ... bool PositionClose( const string symbol, // Symbol const ulong deviation, // Deviation const string comment = "" // Comment For Close ) { // bool partial_close = false; int retry_count = 10; uint retcode = TRADE_RETCODE_REJECT; // // check stopped if (IsStopped(__FUNCTION__)) { return (false); } // // clean ClearStructures(); // // check filling if (!FillingCheck(symbol)) { return (false); } // do { // // check if (SelectPosition(symbol)) { // if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { // // prepare request for close BUY position m_request.type = ORDER_TYPE_SELL; m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); } else { // // prepare request for close SELL position m_request.type = ORDER_TYPE_BUY; m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); } } else { // // position not found m_result.retcode = retcode; return (false); } // // setting request m_request.action = TRADE_ACTION_DEAL; m_request.symbol = symbol; m_request.volume = PositionGetDouble(POSITION_VOLUME); m_request.magic = m_magic; m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; m_request.position = PositionGetInteger(POSITION_TICKET); // // Specify Comment ... m_request.comment = comment; // // check volume double max_volume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); if (m_request.volume > max_volume) { // m_request.volume = max_volume; partial_close = true; } else { partial_close = false; } // // hedging? just send order if (IsHedging()) { return (OrderSend(m_request, m_result)); } // // order send if (!OrderSend(m_request, m_result)) { // if (--retry_count != 0) { continue; } // if (retcode == TRADE_RETCODE_DONE_PARTIAL) { m_result.retcode = retcode; } // return (false); } // //--- WARNING. If position volume exceeds the maximum volume allowed for deal, //--- and when the asynchronous trade mode is on, for safety reasons, position is closed not completely, //--- but partially. It is decreased by the maximum volume allowed for deal. if (m_async_mode) { break; } // retcode = TRADE_RETCODE_DONE_PARTIAL; if (partial_close) { Sleep(1000); } } while (partial_close); // // succeed return (true); } bool PositionClose( const ulong ticket, // Position Ticket const ulong deviation, // Deviation const string comment = "" // Comment For Close ) { // // check stopped if (IsStopped(__FUNCTION__)) { return (false); } // // check position existence if (!PositionSelectByTicket(ticket)) { return (false); } // string symbol = PositionGetString(POSITION_SYMBOL); // // clean ClearStructures(); // // check filling if (!FillingCheck(symbol)) { return (false); } // // check if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { // // prepare request for close BUY position m_request.type = ORDER_TYPE_SELL; m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); } else { // // prepare request for close SELL position m_request.type = ORDER_TYPE_BUY; m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); } // // setting request m_request.action = TRADE_ACTION_DEAL; m_request.position = ticket; m_request.symbol = symbol; m_request.volume = PositionGetDouble(POSITION_VOLUME); m_request.magic = m_magic; m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; // // Specify Comment ... m_request.comment = comment; // // close position return (OrderSend(m_request, m_result)); } // // Partial Close Specific Position, by Specific Comment ... bool PositionClosePartial( const string symbol, // Symbol const double volume, // Partial Closing Volume const ulong deviation, // Deviation const string comment = "" // Comment For Close ) { // uint retcode = TRADE_RETCODE_REJECT; // // check stopped if (IsStopped(__FUNCTION__)) { return (false); } // // for hedging mode only if (!IsHedging()) { return (false); } // // clean ClearStructures(); // // check filling if (!FillingCheck(symbol)) { return (false); } // // check if (SelectPosition(symbol)) { // if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { // // prepare request for close BUY position m_request.type = ORDER_TYPE_SELL; m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); } else { // // prepare request for close SELL position m_request.type = ORDER_TYPE_BUY; m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); } } else { // // position not found m_result.retcode = retcode; return (false); } // // check volume double position_volume = PositionGetDouble(POSITION_VOLUME); if (position_volume > volume) { position_volume = volume; } // // setting request m_request.action = TRADE_ACTION_DEAL; m_request.symbol = symbol; m_request.volume = position_volume; m_request.magic = m_magic; m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; m_request.position = PositionGetInteger(POSITION_TICKET); // // Specifieng Comment ... m_request.comment = comment; // // hedging? just send order return (OrderSend(m_request, m_result)); } bool PositionClosePartial( const ulong ticket, // Position Ticket const double volume, // Partial Closing Volume const ulong deviation, // Deviation const string comment = "" // Comment For Close ) { // // check stopped if (IsStopped(__FUNCTION__)) { return (false); } // // for hedging mode only if (!IsHedging()) { return (false); } // // check position existence if (!PositionSelectByTicket(ticket)) { return (false); } // string symbol = PositionGetString(POSITION_SYMBOL); // // clean ClearStructures(); // // check filling if (!FillingCheck(symbol)) { return (false); } // // check if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { // // prepare request for close BUY position m_request.type = ORDER_TYPE_SELL; m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); } else { // // prepare request for close SELL position m_request.type = ORDER_TYPE_BUY; m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); } // // check volume double position_volume = PositionGetDouble(POSITION_VOLUME); if (position_volume > volume) { position_volume = volume; } // // setting request m_request.action = TRADE_ACTION_DEAL; m_request.position = ticket; m_request.symbol = symbol; m_request.volume = position_volume; m_request.magic = m_magic; m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; // // Specifieng Comment ... m_request.comment = comment; // // close position return (OrderSend(m_request, m_result)); } }; // // END Overrides ... // // // START Global Definitions: Variables, Properties and etc ... // // // XCMD5 a library for Hashing ... class XCMD5 : public XCBase { // // Public Provides ... public: // // Protected Provides ... // // Constructor ... XCMD5(void) {} // // Deconstructor ... ~XCMD5(void) {} // // Hash Specified Char Array ... string Hash( uchar &source[], // Specify Char Array to Hash int length = 0 // Specify Length of Char Array which required to hash ) { // string result = ""; // int sourceCount = ArraySize(source); // // Validate Args ... if ( sourceCount <= 0 || (sourceCount > 0 && length > sourceCount)) { return result; } // // Normalize Args ... if (length == 0) { length = sourceCount; } // // Init MD5 ... MD5Init(); // // Update Buffer ... MD5Update(source, length); // // Calculate Result ... result = MD5Final(); // return result; } // // Hash Specified String ... string Hash( string source // Specified String ) { // string result = ""; // // Converts String to Char Array ... uchar bytes[]; StringToCharArray( source, bytes, 0, StringLen(source)); // result = Hash( bytes, ArraySize(bytes)); // return result; } protected: // // Private Provides ... private: // uint m_lMD5[4]; uint m_nCount[2]; uchar m_lpszBuffer[64]; // // Convert Byte to DWord ... void ByteToDWord(int &out[], uint &in[], uint len) { // uint i = 0; uint j = 0; // for (; j < len; i++, j += 4) { out[i] = (int)in[j] | (int)in[j + 1] << 8 | (int)in[j + 2] << 16 | (int)in[j + 3] << 24; } } // // Convert DWord to Byte ... void DWordToByte(uchar &out[], int &in[], uint len) { // uint i = 0; uint j = 0; // for (; j < len; i++, j += 4) { // out[j] = (uchar)(in[i] & 0xff); out[j + 1] = (uchar)((in[i] >> 8) & 0xff); out[j + 2] = (uchar)((in[i] >> 16) & 0xff); out[j + 3] = (uchar)((in[i] >> 24) & 0xff); } } // // Init MD5 Array ... void MD5Init() { // ArrayInitialize(m_lpszBuffer, 64); // m_nCount[0] = m_nCount[1] = 0; m_lMD5[0] = _md5_INIT_STATE_0; m_lMD5[1] = _md5_INIT_STATE_1; m_lMD5[2] = _md5_INIT_STATE_2; m_lMD5[3] = _md5_INIT_STATE_3; } // // Update MD5 ... void MD5Update(uchar &inBuf[], uint inLen) { // int i, ii; int mdi; // uint in[16]; int i0 = 0; // mdi = (int)((m_nCount[0] >> 3) & 0x3F); // if ((m_nCount[0] + ((uint)inLen << 3)) < m_nCount[0]) { m_nCount[1]++; } // m_nCount[0] += ((uint)inLen << 3); m_nCount[1] += ((uint)inLen >> 29); // while ((inLen--) > 0) { // m_lpszBuffer[mdi++] = inBuf[i0++]; if (mdi == 0x40) { // for (i = 0, ii = 0; i < 16; i++, ii += 4) { in[i] = (((uint)m_lpszBuffer[ii + 3]) << 24) | (((uint)m_lpszBuffer[ii + 2]) << 16) | (((uint)m_lpszBuffer[ii + 1]) << 8) | ((uint)m_lpszBuffer[ii]); } // Transform(m_lMD5, in); // mdi = 0; } } } // // Finalize an MD5 Expression ... string MD5Final() { // uchar bits[8]; int nIndex; uint nPadLen; const int nMD5Size = 16; uchar lpszMD5[16]; string temp; string out = ""; int i; // DWordToByte(bits, m_nCount, 8); nIndex = (int)((m_nCount[0] >> 3) & 0x3f); nPadLen = (nIndex < 56) ? (56 - nIndex) : (120 - nIndex); MD5Update(_md5_PADDING, nPadLen); MD5Update(bits, 8); DWordToByte(lpszMD5, m_lMD5, nMD5Size); // for (i = 0; i < nMD5Size; i++) { // if (lpszMD5[i] == 0) { temp = "00"; } else if (lpszMD5[i] <= 15) { temp = StringFormat("0%x", lpszMD5[i]); } else { temp = StringFormat("%x", lpszMD5[i]); } // out += temp; } // lpszMD5[0] = '\0'; // return (out); } // // Transform Buffers ... void Transform(uint &buf[], uint &in[]) { // uint a = buf[0], b = buf[1], c = buf[2], d = buf[3]; // _md5_FF(a, b, c, d, in[0], _md5_S11, 0xD76AA478); _md5_FF(d, a, b, c, in[1], _md5_S12, 0xE8C7B756); _md5_FF(c, d, a, b, in[2], _md5_S13, 0x242070DB); _md5_FF(b, c, d, a, in[3], _md5_S14, 0xC1BDCEEE); _md5_FF(a, b, c, d, in[4], _md5_S11, 0xF57C0FAF); _md5_FF(d, a, b, c, in[5], _md5_S12, 0x4787C62A); _md5_FF(c, d, a, b, in[6], _md5_S13, 0xA8304613); _md5_FF(b, c, d, a, in[7], _md5_S14, 0xFD469501); _md5_FF(a, b, c, d, in[8], _md5_S11, 0x698098D8); _md5_FF(d, a, b, c, in[9], _md5_S12, 0x8B44F7AF); _md5_FF(c, d, a, b, in[10], _md5_S13, 0xFFFF5BB1); _md5_FF(b, c, d, a, in[11], _md5_S14, 0x895CD7BE); _md5_FF(a, b, c, d, in[12], _md5_S11, 0x6B901122); _md5_FF(d, a, b, c, in[13], _md5_S12, 0xFD987193); _md5_FF(c, d, a, b, in[14], _md5_S13, 0xA679438E); _md5_FF(b, c, d, a, in[15], _md5_S14, 0x49B40821); // _md5_GG(a, b, c, d, in[1], _md5_S21, 0xF61E2562); _md5_GG(d, a, b, c, in[6], _md5_S22, 0xC040B340); _md5_GG(c, d, a, b, in[11], _md5_S23, 0x265E5A51); _md5_GG(b, c, d, a, in[0], _md5_S24, 0xE9B6C7AA); _md5_GG(a, b, c, d, in[5], _md5_S21, 0xD62F105D); _md5_GG(d, a, b, c, in[10], _md5_S22, 0x02441453); _md5_GG(c, d, a, b, in[15], _md5_S23, 0xD8A1E681); _md5_GG(b, c, d, a, in[4], _md5_S24, 0xE7D3FBC8); _md5_GG(a, b, c, d, in[9], _md5_S21, 0x21E1CDE6); _md5_GG(d, a, b, c, in[14], _md5_S22, 0xC33707D6); _md5_GG(c, d, a, b, in[3], _md5_S23, 0xF4D50D87); _md5_GG(b, c, d, a, in[8], _md5_S24, 0x455A14ED); _md5_GG(a, b, c, d, in[13], _md5_S21, 0xA9E3E905); _md5_GG(d, a, b, c, in[2], _md5_S22, 0xFCEFA3F8); _md5_GG(c, d, a, b, in[7], _md5_S23, 0x676F02D9); _md5_GG(b, c, d, a, in[12], _md5_S24, 0x8D2A4C8A); // _md5_HH(a, b, c, d, in[5], _md5_S31, 0xFFFA3942); _md5_HH(d, a, b, c, in[8], _md5_S32, 0x8771F681); _md5_HH(c, d, a, b, in[11], _md5_S33, 0x6D9D6122); _md5_HH(b, c, d, a, in[14], _md5_S34, 0xFDE5380C); _md5_HH(a, b, c, d, in[1], _md5_S31, 0xA4BEEA44); _md5_HH(d, a, b, c, in[4], _md5_S32, 0x4BDECFA9); _md5_HH(c, d, a, b, in[7], _md5_S33, 0xF6BB4B60); _md5_HH(b, c, d, a, in[10], _md5_S34, 0xBEBFBC70); _md5_HH(a, b, c, d, in[13], _md5_S31, 0x289B7EC6); _md5_HH(d, a, b, c, in[0], _md5_S32, 0xEAA127FA); _md5_HH(c, d, a, b, in[3], _md5_S33, 0xD4EF3085); _md5_HH(b, c, d, a, in[6], _md5_S34, 0x04881D05); _md5_HH(a, b, c, d, in[9], _md5_S31, 0xD9D4D039); _md5_HH(d, a, b, c, in[12], _md5_S32, 0xE6DB99E5); _md5_HH(c, d, a, b, in[15], _md5_S33, 0x1FA27CF8); _md5_HH(b, c, d, a, in[2], _md5_S34, 0xC4AC5665); // _md5_II(a, b, c, d, in[0], _md5_S41, 0xF4292244); _md5_II(d, a, b, c, in[7], _md5_S42, 0x432AFF97); _md5_II(c, d, a, b, in[14], _md5_S43, 0xAB9423A7); _md5_II(b, c, d, a, in[5], _md5_S44, 0xFC93A039); _md5_II(a, b, c, d, in[12], _md5_S41, 0x655B59C3); _md5_II(d, a, b, c, in[3], _md5_S42, 0x8F0CCC92); _md5_II(c, d, a, b, in[10], _md5_S43, 0xFFEFF47D); _md5_II(b, c, d, a, in[1], _md5_S44, 0x85845DD1); _md5_II(a, b, c, d, in[8], _md5_S41, 0x6FA87E4F); _md5_II(d, a, b, c, in[15], _md5_S42, 0xFE2CE6E0); _md5_II(c, d, a, b, in[6], _md5_S43, 0xA3014314); _md5_II(b, c, d, a, in[13], _md5_S44, 0x4E0811A1); _md5_II(a, b, c, d, in[4], _md5_S41, 0xF7537E82); _md5_II(d, a, b, c, in[11], _md5_S42, 0xBD3AF235); _md5_II(c, d, a, b, in[2], _md5_S43, 0x2AD7D2BB); _md5_II(b, c, d, a, in[9], _md5_S44, 0xEB86D391); // buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } }; // // XSaherElm Account Info Class ... class XCAccountInfo : public XCBase { // // Public properties ... public: // // Constructro ... void XCAccountInfo() { // mAccountInfo = new CAccountInfo(); // mInitialBalance = mAccountInfo.Balance(); } // // Deconstructor ... void ~XCAccountInfo() { // mInitialBalance = 0; } // // User Account ... long GetUserAccount() { return mAccountInfo.Login(); } // // Account Leverage ... long GetLeverage() { return mAccountInfo.Leverage(); } // // Get Trade Expert State ... bool CanExpertTrade() { return mAccountInfo.TradeExpert(); } // // User Account Trade Mopde (ENUM_ACCOUNT_TRADE_MODE) ... // -------------------------- // ACCOUNT_TRADE_MODE_DEMO // ACCOUNT_TRADE_MODE_CONTEST // ACCOUNT_TRADE_MODE_REAL ENUM_ACCOUNT_TRADE_MODE GetTradeMode() { return mAccountInfo.TradeMode(); } // // Get Account Balance ... double GetBalance() { return mAccountInfo.Balance(); } // // Get Initial Deposit Balance ... double GetInitialBalance() { return mInitialBalance; } // // Get the amount of give Credit ... double GetCredit() { return mAccountInfo.Credit(); } // // Get the amount of current Profit on account ... double GetProfit() { return mAccountInfo.Profit(); } // // Get the amount of current Equity on account ... double GetEquity() { return mAccountInfo.Equity(); } // // Get the amount of reserved Margin ... double GetMargin() { return mAccountInfo.Margin(); } // // Get the amount of free Margin ... double GetFreeMargin() { return mAccountInfo.FreeMargin(); } // // Get the Level of Margin ... double GetMarginLevel() { return mAccountInfo.MarginLevel(); } // // Get the Level Of Margin for a Deposit ... double GetMarginCall() { return mAccountInfo.MarginCall(); } // // Get the Level of Margin for Stop out ... double GetMarginStopOut() { return mAccountInfo.MarginStopOut(); } // // Get the Client Name ... string GetName() { return mAccountInfo.Name(); } // // Get the Trade Server Name ... string GetServerName() { return mAccountInfo.Server(); } // // Get deposit Currency Name ... string GetCurrency() { return mAccountInfo.Currency(); } // // Get the Company Name that serves an Account ... string GetCompany() { return mAccountInfo.Company(); } // // Calculate Profits for the current account based on passed parameters ... double CalculateTradeProfit( const string symbol, // trading symbol ENUM_ORDER_TYPE type, // order type double volume, // volume double entry, // open price double exit // close price ) { // double result = mAccountInfo.OrderProfitCheck( symbol, type, volume, entry, exit); // return result; } // // Calculate amount of margin which required for trade operation ... double CalculateMarging( const string symbol, // trading symbol ENUM_ORDER_TYPE type, // order type double volume, // volume double entry // open price ) { // double result = mAccountInfo.MarginCheck( symbol, type, volume, entry); // return result; } // // Calculate amount of free margin left after trade operation ... double CalculateFreeMarging( const string symbol, // trading symbol ENUM_ORDER_TYPE type, // order type double volume, // volume double entry // open price ) { // double result = mAccountInfo.FreeMarginCheck( symbol, type, volume, entry); // return result; } // // Calculate the Maximum possible volume of trade operation ... double CalculateMaxVolume( const string symbol, // trading symbol ENUM_ORDER_TYPE type, // order type double entry, // open price double percent = 100 // percent of available margin ) { // double result = mAccountInfo.MaxLotCheck( symbol, type, entry, percent); // return result; } // // Protected properties ... protected: // // Private properties ... private: // // Initial Account Balance ... double mInitialBalance; // // Account Info ... CAccountInfo mAccountInfo; }; // // XSaherElm Report Info Class ... class XCReporter : public XCBase { // // Public Provided ... public: // // Constructro ... void XCReporter() { // mAccountInfo = new XCAccountInfo(); // Reset(); } // // Deconstructor ... void ~XCReporter() { } // // Reset Specific Report ... void Reset( ENUM_XREPORT_TYPES type // Specify Report Type ) { CleanReport(type); } // // Reset All Reports ... void Reset() { // CleanReport(XREPORT_MAIN); CleanReport(XREPORT_MONTHLY); CleanReport(XREPORT_WEEKLY); CleanReport(XREPORT_DAILY); } // // Update Volume Info ... void UpdateReportVolumeInfo( ENUM_XREPORT_TYPES type, // Specified Report Type // double staticVolume, // Current Available Static Volume string staticVolumeCalculationMethod, // Static Volume Calculation Method double maxAllowedVolume, // Current Maximum Appliable Volume double volumeIncreaseMultiplier, // Static Volume Increase Multiplier double balanceGowingToApplyMultiplier, // Multiply Volume Based On Balance Growing double balanceGrowingToIncreaseMaxAllowedVolume // Where to Increase MaxAllowed Volume ) { // // Filling Account Info ... FillReportAccountInfo(type); // switch (type) { // // Main ... case XREPORT_MAIN: // FillingVolumeInfo( mMainReport, staticVolume, staticVolumeCalculationMethod, maxAllowedVolume, volumeIncreaseMultiplier, balanceGowingToApplyMultiplier, balanceGrowingToIncreaseMaxAllowedVolume); break; // // Monthly ... case XREPORT_MONTHLY: // FillingVolumeInfo( mMonthlyReport, staticVolume, staticVolumeCalculationMethod, maxAllowedVolume, volumeIncreaseMultiplier, balanceGowingToApplyMultiplier, balanceGrowingToIncreaseMaxAllowedVolume); break; // // Weekly ... case XREPORT_WEEKLY: // FillingVolumeInfo( mWeeklyReport, staticVolume, staticVolumeCalculationMethod, maxAllowedVolume, volumeIncreaseMultiplier, balanceGowingToApplyMultiplier, balanceGrowingToIncreaseMaxAllowedVolume); break; // // Daily ... case XREPORT_DAILY: // FillingVolumeInfo( mDailyReport, staticVolume, staticVolumeCalculationMethod, maxAllowedVolume, volumeIncreaseMultiplier, balanceGowingToApplyMultiplier, balanceGrowingToIncreaseMaxAllowedVolume); break; } } // // Update Volume Info on All Reports ... void UpdateReportsVolumeInfo( double staticVolume, // Current Available Static Volume string staticVolumeCalculationMethod, // Static Volume Calculation Method double maxAllowedVolume, // Current Maximum Appliable Volume double volumeIncreaseMultiplier, // Static Volume Increase Multiplier double balanceGowingToApplyMultiplier, // Multiply Volume Based On Balance Growing double balanceGrowingToIncreaseMaxAllowedVolume // Where to Increase MaxAllowed Volume ) { // // Main ... UpdateReportVolumeInfo( XREPORT_MAIN, staticVolume, staticVolumeCalculationMethod, maxAllowedVolume, volumeIncreaseMultiplier, balanceGowingToApplyMultiplier, balanceGrowingToIncreaseMaxAllowedVolume); // // Monthly ... UpdateReportVolumeInfo( XREPORT_MONTHLY, staticVolume, staticVolumeCalculationMethod, maxAllowedVolume, volumeIncreaseMultiplier, balanceGowingToApplyMultiplier, balanceGrowingToIncreaseMaxAllowedVolume); // // Weekly ... UpdateReportVolumeInfo( XREPORT_WEEKLY, staticVolume, staticVolumeCalculationMethod, maxAllowedVolume, volumeIncreaseMultiplier, balanceGowingToApplyMultiplier, balanceGrowingToIncreaseMaxAllowedVolume); // // Daily ... UpdateReportVolumeInfo( XREPORT_DAILY, staticVolume, staticVolumeCalculationMethod, maxAllowedVolume, volumeIncreaseMultiplier, balanceGowingToApplyMultiplier, balanceGrowingToIncreaseMaxAllowedVolume); } // // Add Specific Signal to Report ... void AddSignalToReport( ENUM_XREPORT_TYPES type, // Specified Report Type const XSignal &signal, // Specified Signal const string &providers[] // Specified Signal Providers ) { // // // Filling Account Info ... FillReportAccountInfo(type); // switch (type) { // // Main ... case XREPORT_MAIN: AddSignalToReport( mMainReport, signal, providers); break; // // Monthly ... case XREPORT_MONTHLY: AddSignalToReport( mMonthlyReport, signal, providers); break; // // Weekly ... case XREPORT_WEEKLY: AddSignalToReport( mWeeklyReport, signal, providers); break; // // Daily ... case XREPORT_DAILY: AddSignalToReport( mDailyReport, signal, providers); break; } } // // Add Specific Signal to All Reports ... void AddSignalToReports( const XSignal &signal, // Specified Signal const string &providers[] // Specified Signal Providers ) { // // Main ... AddSignalToReport( XREPORT_MAIN, signal, providers); // // Monthly ... AddSignalToReport( XREPORT_MONTHLY, signal, providers); // // Weekly ... AddSignalToReport( XREPORT_WEEKLY, signal, providers); // // Daily ... AddSignalToReport( XREPORT_DAILY, signal, providers); } // // Report a TP for Specific Report ... void AddTradeTPInReport( ENUM_XREPORT_TYPES type // Specified Report Type ) { // switch (type) { // // Main ... case XREPORT_MAIN: AddTradeTPInReport(mMainReport); break; // // Monthly ... case XREPORT_MONTHLY: AddTradeTPInReport(mMonthlyReport); break; // // Weekly ... case XREPORT_WEEKLY: AddTradeTPInReport(mWeeklyReport); break; // // Daily ... case XREPORT_DAILY: AddTradeTPInReport(mDailyReport); break; } } // // Report a TP for All Reports ... void AddTradeTPInReports() { // // Main ... AddTradeTPInReport(XREPORT_MAIN); // // Monthly ... AddTradeTPInReport(XREPORT_MONTHLY); // // Weekly ... AddTradeTPInReport(XREPORT_WEEKLY); // // Daily ... AddTradeTPInReport(XREPORT_DAILY); } // // Report a SL for Specific Report ... void AddTradeSLInReport( ENUM_XREPORT_TYPES type // Specified Report Type ) { // switch (type) { // // Main ... case XREPORT_MAIN: AddTradeSLInReport(mMainReport); break; // // Monthly ... case XREPORT_MONTHLY: AddTradeSLInReport(mMonthlyReport); break; // // Weekly ... case XREPORT_WEEKLY: AddTradeSLInReport(mWeeklyReport); break; // // Daily ... case XREPORT_DAILY: AddTradeSLInReport(mDailyReport); break; } } // // Report a SL for All Reports ... void AddTradeSLInReports() { // // Main ... AddTradeSLInReport(XREPORT_MAIN); // // Monthly ... AddTradeSLInReport(XREPORT_MONTHLY); // // Weekly ... AddTradeSLInReport(XREPORT_WEEKLY); // // Daily ... AddTradeSLInReport(XREPORT_DAILY); } // // Update Number of Same Time Trades in Specific Report ... void UpdateMaxSameTimeTradesInReport( ENUM_XREPORT_TYPES type, // Specified Report Type int value // number of same time trades ) { // switch (type) { // // Main ... case XREPORT_MAIN: UpdateMaxSameTimeTradesInReport( mMainReport, value); break; // // Monthly ... case XREPORT_MONTHLY: UpdateMaxSameTimeTradesInReport( mMonthlyReport, value); break; // // Weekly ... case XREPORT_WEEKLY: UpdateMaxSameTimeTradesInReport( mWeeklyReport, value); break; // // Daily ... case XREPORT_DAILY: UpdateMaxSameTimeTradesInReport( mDailyReport, value); break; } } // // Update Number of Same Time Trades in All Report ... void UpdateMaxSameTimeTradesInReports( int value // number of same time trades ) { // // Main ... UpdateMaxSameTimeTradesInReport( XREPORT_MAIN, value); // // Monthly ... UpdateMaxSameTimeTradesInReport( XREPORT_MONTHLY, value); // // Weekly ... UpdateMaxSameTimeTradesInReport( XREPORT_WEEKLY, value); // // Daily ... UpdateMaxSameTimeTradesInReport( XREPORT_DAILY, value); } // // Update Max DrawDown in Specific Report ... void UpdateMaxDrawDownInReport( ENUM_XREPORT_TYPES type, // Specified Report Type double value // draw down value ) { // switch (type) { // // Main ... case XREPORT_MAIN: UpdateMaxDrawDownInReport( mMainReport, value); break; // // Monthly ... case XREPORT_MONTHLY: UpdateMaxDrawDownInReport( mMonthlyReport, value); break; // // Weekly ... case XREPORT_WEEKLY: UpdateMaxDrawDownInReport( mWeeklyReport, value); break; // // Daily ... case XREPORT_DAILY: UpdateMaxDrawDownInReport( mDailyReport, value); break; } } // // Update Max DrawDown in All Report ... void UpdateMaxDrawDownInReports( double value // draw down value ) { // // Main ... UpdateMaxDrawDownInReport( XREPORT_MAIN, value); // // Monthly ... UpdateMaxDrawDownInReport( XREPORT_MONTHLY, value); // // Weekly ... UpdateMaxDrawDownInReport( XREPORT_WEEKLY, value); // // Daily ... UpdateMaxDrawDownInReport( XREPORT_DAILY, value); } // // Update Max DrawUp in Specific Report ... void UpdateMaxDrawUpInReport( ENUM_XREPORT_TYPES type, // Specified Report Type double value // draw up value ) { // switch (type) { // // Main ... case XREPORT_MAIN: UpdateMaxDrawUpInReport( mMainReport, value); break; // // Monthly ... case XREPORT_MONTHLY: UpdateMaxDrawUpInReport( mMonthlyReport, value); break; // // Weekly ... case XREPORT_WEEKLY: UpdateMaxDrawUpInReport( mWeeklyReport, value); break; // // Daily ... case XREPORT_DAILY: UpdateMaxDrawUpInReport( mDailyReport, value); break; } } // // Update Max DrawUp in All Report ... void UpdateMaxDrawUpInReports( double value // draw up value ) { // // Main ... UpdateMaxDrawUpInReport( XREPORT_MAIN, value); // // Monthly ... UpdateMaxDrawUpInReport( XREPORT_MONTHLY, value); // // Weekly ... UpdateMaxDrawUpInReport( XREPORT_WEEKLY, value); // // Daily ... UpdateMaxDrawUpInReport( XREPORT_DAILY, value); } // // Update Min Balance for Open Trades in Specific Report ... void UpdateMinBalanceForOpenTradesInReport( ENUM_XREPORT_TYPES type, // Specified Report Type double value // min balance for open trades ) { // switch (type) { // // Main ... case XREPORT_MAIN: UpdateMinBalanceForOpenTradesInReport( mMainReport, value); break; // // Monthly ... case XREPORT_MONTHLY: UpdateMinBalanceForOpenTradesInReport( mMonthlyReport, value); break; // // Weekly ... case XREPORT_WEEKLY: UpdateMinBalanceForOpenTradesInReport( mWeeklyReport, value); break; // // Daily ... case XREPORT_DAILY: UpdateMinBalanceForOpenTradesInReport( mDailyReport, value); break; } } // // Update Min Balance for Open Trades in All Report ... void UpdateMinBalanceForOpenTradesInReports( double value // min balance for open trades ) { // // Main ... UpdateMinBalanceForOpenTradesInReport( XREPORT_MAIN, value); // // Monthly ... UpdateMinBalanceForOpenTradesInReport( XREPORT_MONTHLY, value); // // Weekly ... UpdateMinBalanceForOpenTradesInReport( XREPORT_WEEKLY, value); // // Daily ... UpdateMinBalanceForOpenTradesInReport( XREPORT_DAILY, value); } // // Gnerate Specific Type Of Report String Representation ... string GenerateReportString( ENUM_XREPORT_TYPES type, // Specified Report Type string separator = "\n" // Separator ) { // string result = ""; // switch (type) { // // Main ... case XREPORT_MAIN: result = GenerateReportString( mMainReport, separator); break; // // Monthly ... case XREPORT_MONTHLY: result = GenerateReportString( mMonthlyReport, separator); break; // // Weekly ... case XREPORT_WEEKLY: result = GenerateReportString( mWeeklyReport, separator); break; // // Daily ... case XREPORT_DAILY: result = GenerateReportString( mDailyReport, separator); break; } // return result; } // // Protected Provided ... protected: // // Private Provided ... private: // // Account Info Instance ... XCAccountInfo mAccountInfo; // // Main Report ... XReport mMainReport; // // Monthly Report ... XReport mMonthlyReport; // // Weekly Report ... XReport mWeeklyReport; // // Daily Report ... XReport mDailyReport; // // Clean Specific Report ... void CleanReport( XReport &report // Specified Report ) { // datetime time = TimeCurrent(); // // Reset Times ... report.start = time; report.end = -1; // // Reset Account Info ... FillReportAccountInfo(report); // // Reset Summary Info ... report.summaryInfo.maxDrawUp = 0; report.summaryInfo.maxDrawDown = 0; report.summaryInfo.longSignals = 0; report.summaryInfo.numberOfTPs = 0; report.summaryInfo.numberOfSLs = 0; report.summaryInfo.shortSignals = 0; report.summaryInfo.maxSignalVolume = 0; report.summaryInfo.maxSameTimeSignals = 0; // // Reset Volume Info ... report.volumeInfo.staticVolume = 0; report.volumeInfo.maxAllowedVolume = 0; report.volumeInfo.volumeIncreaseMultiplier = 0; report.volumeInfo.balanceGowingToApplyMultiplier = 0; report.volumeInfo.staticVolumeCalculationMethod = NULL; report.volumeInfo.balanceGrowingToIncreaseMaxAllowedVolume = 0; // // Reset Signallers Info ... CleanBuffer(report.signallersInfo); } void CleanReport( ENUM_XREPORT_TYPES type // Specify Report Type ) { // switch (type) { // // Main ... case XREPORT_MAIN: CleanReport(mMainReport); break; // // Monthly ... case XREPORT_MONTHLY: CleanReport(mMonthlyReport); break; // // Weekly ... case XREPORT_WEEKLY: CleanReport(mWeeklyReport); break; // // Daily ... case XREPORT_DAILY: CleanReport(mDailyReport); break; } } // // Update Specific Reports End Time ... void FillReportEndTime( XReport &report // Specified Report ) { // datetime time = TimeCurrent(); report.end = time; } // // Filleing Report Account Info ... void FillReportAccountInfo( XReport &report // Specified Report ) { // FillReportEndTime(report); // report.accountInfo.user = (string)mAccountInfo.GetUserAccount(); report.accountInfo.name = mAccountInfo.GetName(); report.accountInfo.server = mAccountInfo.GetServerName(); report.accountInfo.broker = mAccountInfo.GetCompany(); report.accountInfo.mode = mAccountInfo.GetTradeMode(); report.accountInfo.leverage = mAccountInfo.GetLeverage(); report.accountInfo.currency = mAccountInfo.GetCurrency(); report.accountInfo.deposit = mAccountInfo.GetInitialBalance(); report.accountInfo.balance = mAccountInfo.GetBalance(); } void FillReportAccountInfo( ENUM_XREPORT_TYPES type // Specify Report Type ) { // switch (type) { // // Main ... case XREPORT_MAIN: FillReportAccountInfo(mMainReport); break; // // Monthly ... case XREPORT_MONTHLY: FillReportAccountInfo(mMonthlyReport); break; // // Weekly ... case XREPORT_WEEKLY: FillReportAccountInfo(mWeeklyReport); break; // // Daily ... case XREPORT_DAILY: FillReportAccountInfo(mDailyReport); break; } } // // Filling Volume Info ... void FillingVolumeInfo( XReport &report, // Specified Report // double staticVolume, // Current Available Static Volume string staticVolumeCalculationMethod, // Static Volume Calculation Method double maxAllowedVolume, // Current Maximum Appliable Volume double volumeIncreaseMultiplier, // Static Volume Increase Multiplier double balanceGowingToApplyMultiplier, // Multiply Volume Based On Balance Growing double balanceGrowingToIncreaseMaxAllowedVolume // Where to Increase MaxAllowed Volume ) { // FillReportEndTime(report); // report.volumeInfo.staticVolume = staticVolume; report.volumeInfo.maxAllowedVolume = maxAllowedVolume; report.volumeInfo.volumeIncreaseMultiplier = volumeIncreaseMultiplier; report.volumeInfo.staticVolumeCalculationMethod = staticVolumeCalculationMethod; report.volumeInfo.balanceGowingToApplyMultiplier = balanceGowingToApplyMultiplier; report.volumeInfo.balanceGrowingToIncreaseMaxAllowedVolume = balanceGrowingToIncreaseMaxAllowedVolume; } // // Add Signal to Report ... void AddSignalToReport( XReport &report, // Specified Report const XSignal &signal, // Specified Signal const string &providers[] // Specified Signal Providers ) { // FillReportEndTime(report); // double volume = signal.volume; bool isLong = signal.type == X_SIGNAL_LONG; // // Update Longs and Shorts ... if (isLong) { report.summaryInfo.longSignals++; } else { report.summaryInfo.shortSignals++; } // // Chack Max Volume ... if (volume > report.summaryInfo.maxSignalVolume) { report.summaryInfo.maxSignalVolume = volume; } // // Update Signallers Info ... for (int i = 0; i < ArraySize(providers); i++) { // string iProvider = providers[i]; // AddOrUpdateSignaller( report, iProvider, signal); } } // // Add or Update Signaller Info of Specific Report ... void AddOrUpdateSignaller( XReport &report, // Specified Report const string provider, // Signal Provider name const XSignal &signal // Specified Signal ) { // int providerIdx = -1; int signallersInfoCount = 0; bool isLong = signal.type == X_SIGNAL_LONG; // // Prepare New One Provider ... XSignallerInfo info = {}; info.name = provider; if (isLong) { info.longs = 1; } else { info.shorts = 1; } // // Find Provider idx if Exists ... providerIdx = FindProviderInSignallersInfo( provider, report.signallersInfo); // // Check IDX ... if (providerIdx > -1) { // // Update Exists ... if (isLong) { report.signallersInfo[providerIdx].longs++; } else { report.signallersInfo[providerIdx].shorts++; } } else { // // Add New One ... AddItemToBuffer( info, report.signallersInfo); } } // // Add TP in Report ... void AddTradeTPInReport( XReport &report // Specified Report ) { // FillReportEndTime(report); // report.summaryInfo.numberOfTPs++; } // // Add SL in Report ... void AddTradeSLInReport( XReport &report // Specified Report ) { // FillReportEndTime(report); // report.summaryInfo.numberOfSLs++; } // // Update Number of Same Time Trades in Report ... void UpdateMaxSameTimeTradesInReport( XReport &report, // Specified Report int value // number of same time trades ) { // // Validate Args ... if (value <= report.summaryInfo.maxSameTimeSignals) { return; } // FillReportEndTime(report); // report.summaryInfo.maxSameTimeSignals = value; } // // Update Number of Same Time Trades in Report ... void UpdateMaxDrawUpInReport( XReport &report, // Specified Report double value // draw up value ) { // // Validate Args ... if (value <= report.summaryInfo.maxDrawUp) { return; } // FillReportEndTime(report); // report.summaryInfo.maxDrawUp = value; } // // Update Number of Same Time Trades in Report ... void UpdateMaxDrawDownInReport( XReport &report, // Specified Report double value // draw down value ) { // // Validate Args ... if (value <= report.summaryInfo.maxDrawDown) { return; } // FillReportEndTime(report); // report.summaryInfo.maxDrawDown = value; } // // Update Min Balance for Open Trades Value in Report ... void UpdateMinBalanceForOpenTradesInReport( XReport &report, // Specified Report double value // min balance for open trades ) { // // Validate Arg ... if (value <= 0) { return; } // FillReportEndTime(report); // report.accountInfo.minBalanceForOpenTrades = value; } // // Generate Specific Report String Representation ... string GenerateReportString( XReport &report, // Specified Report string separator = "\n" // Separator ) { // string result = ""; // // Start and End Date ... result += "Start: " + (string)report.start + separator; result += "End: " + (string)report.end + separator; // // Account Info ... string accountStr = GenerateAccountInfoReportString(report.accountInfo); result += "Account: " + separator + accountStr + separator; // // Summary Info ... string summaryStr = GenerateSummaryInfoReportString(report.summaryInfo); result += "Summary: " + separator + summaryStr + separator; // // Volume Info ... string volumeStr = GenerateVolumeInfoReportString(report.volumeInfo); result += "Volume: " + separator + volumeStr + separator; // // Signallers Info ... string signallersStr = GenerateSignallersInfoReportString(report.signallersInfo); result += "Signallers: " + separator + signallersStr + separator; // return result; } // // Generate Account info String Representation ... string GenerateAccountInfoReportString( XAccountInfo &info, // Specified Account Info string separator = "\n" // Separator ) { // string result = ""; // // Generate Report ... result += "user: " + info.user + separator; result += "name: " + info.name + separator; result += "server: " + info.server + separator; result += "broker: " + info.broker + separator; result += "mode: " + EnumToString(info.mode) + separator; result += "leverage: " + (string)info.leverage + separator; result += "currency: " + info.currency + separator; result += "deposit: " + (string)info.deposit + separator; result += "balance: " + (string)info.balance + separator; result += "minBalanceForTrading: " + (string)info.minBalanceForOpenTrades + separator; // return result; } // // Generate Summary info String Representation ... string GenerateSummaryInfoReportString( XSummaryInfo &info, // Specified Summary Info string separator = "\n" // Separator ) { // string result = ""; // // Generate Report ... result += "longSignals: " + (string)info.longSignals + separator; result += "shortSignals: " + (string)info.shortSignals + separator; result += "numberOfTps: " + (string)info.numberOfTPs + separator; result += "numberOfSLs: " + (string)info.numberOfSLs + separator; result += "maxDrawUp: " + (string)info.maxDrawUp + separator; result += "maxDrawDown: " + (string)info.maxDrawDown + separator; result += "maxSignalVolume: " + (string)info.maxSignalVolume + separator; result += "maxSameTimeSignals: " + (string)info.maxSameTimeSignals + separator; // return result; } // // Generate Volume info String Representation ... string GenerateVolumeInfoReportString( XVolumeInfo &info, // Specified Volume Info string separator = "\n" // Separator ) { // string result = ""; // // Generate Report ... result += "staticVolume: " + (string)info.staticVolume + separator; result += "staticVolumeCalculationMethod: " + info.staticVolumeCalculationMethod + separator; result += "maxAllowedVolume: " + (string)info.maxAllowedVolume + separator; result += "volumeIncreaseMultiplier: " + (string)info.volumeIncreaseMultiplier + separator; result += "balanceGowingToApplyMultiplier: " + (string)info.balanceGowingToApplyMultiplier + separator; result += "balanceGrowingToIncreaseMaxAllowedVolume: " + (string)info.balanceGrowingToIncreaseMaxAllowedVolume + separator; // return result; } // // Generate Signallers info String Representation ... string GenerateSignallersInfoReportString( XSignallerInfo &infos[], // Specified Signallers Info string separator = "\n" // Separator ) { // string result = ""; // // Validate Signallers Array Size ... int signallersCount = ArraySize(infos); if (signallersCount <= 0) { // result += "EMPTY" + separator; return result; } // // Generate Report ... for (int i = 0; i < signallersCount; i++) { // XSignallerInfo iSignaller = infos[i]; // result += "name: " + iSignaller.name + separator; result += "longs: " + (string)iSignaller.longs + separator; result += "shorts: " + (string)iSignaller.shorts + separator; // if (i < signallersCount - 1) { result += separator; } } // return result; } // // Find a Provider Index in SignallersInfo ... int FindProviderInSignallersInfo( string provider, // Specified Provider Name ... XSignallerInfo &infoBuffer[] // Specified XSignallerInfo Buffer ... ) { // int result = -1; // int bufferSize = ArraySize(infoBuffer); if (bufferSize <= 0) { return result; } // // Loop through buffer to find provider index ... for (int i = 0; i < bufferSize; i++) { // XSignallerInfo iInfo = infoBuffer[i]; // if (iInfo.name != provider) { continue; } // result = i; } // return result; } }; // // a Class For Collectiong Info ... class XCCollector : public XCBase { // // Public ... public: // // Constructor ... XCCollector() { Reset(); } // // Deconstructor ... ~XCCollector() {} // // Reset All Collectors ... void Reset() { Clean(); } // // Count Data ... int Count() { // int result = 0; // result = ArraySize(mTimes); // return result; } // // TODO: Implement Business Logic here ... // // Add Specific item to Collection ... bool Add( XCollector &item // Specified Info ) { // bool result = false; // // Validate Args ... result = IsValid( item, false); if (!result) { return result; } // // Add Items Values to Buffers ... // AddItemToBuffer( item.time, mTimes); // AddItemToBuffer( item.volume, mVolumes); // AddItemToBuffer( item.maxDrawDown, mMaxDrawDowns); // AddItemToBuffer( item.maxAllowedVolume, mMaxAllowedVolumes); // AddItemToBuffer( item.minBalanceForOpenTrade, mMinBalanceForTradePrices); // return result; } // // Retrieve Specific Item ... bool Get( XCollector &item, // Hold's Result int index = 0 // Specified Index to Retrieve ) { // bool result = false; // result = IsValidIndex(index); if (!result) { return result; } // // Filling Item ... item.time = mTimes[index]; item.volume = mVolumes[index]; item.maxDrawDown = mMaxDrawDowns[index]; item.maxAllowedVolume = mMaxAllowedVolumes[index]; item.minBalanceForOpenTrade = mMinBalanceForTradePrices[index]; // return result; } XCollector Get( int index = 0 // Specified Index to Retrieve ) { // XCollector result = {}; // bool isValidIndex = IsValidIndex(index); if (!isValidIndex) { return result; } // // Filling Item ... result.time = mTimes[index]; result.volume = mVolumes[index]; result.maxDrawDown = mMaxDrawDowns[index]; result.maxAllowedVolume = mMaxAllowedVolumes[index]; result.minBalanceForOpenTrade = mMinBalanceForTradePrices[index]; // return result; } bool Get( XCollector &item, // Hold's Result datetime time // Specified Index to Retrieve ) { // bool result = false; // if (time <= 0) { return result; } // int timesCount = ArraySize(mTimes); result = timesCount > 0; if (!result) { return result; } // int index = -1; for (int i = 0; i < timesCount; i++) { // datetime iTime = mTimes[i]; // if (iTime == time) { // index = i; break; } } // result = index >= 0; if (!result) { return result; } // result = Get( item, index); // return result; } XCollector Get( datetime time // Specified Index to Retrieve ) { // XCollector result = {}; // if (time <= 0) { return result; } // int timesCount = ArraySize(mTimes); if (timesCount <= 0) { return result; } // int index = -1; for (int i = 0; i < timesCount; i++) { // datetime iTime = mTimes[i]; // if (iTime == time) { // index = i; break; } } // if (index <= -1) { return result; } // result = Get( index); // return result; } // // Retrieve All ... void GetAll( XCollector &result[], // Hold's Result bool reversal = false // Extract Direction ) { // CleanBuffer(result); // int timesCount = ArraySize(mTimes); if (timesCount <= 0) { return; } // if (!reversal) { // for (int i = 0; i < timesCount; i++) { // XCollector iCollector = Get(i); // AddItemToBuffer( iCollector, result); } } else { // for (int i = timesCount - 1; i >= 0; i--) { // XCollector iCollector = Get(i); // AddItemToBuffer( iCollector, result); } } } // // Extract History ... void Extract( XCollector &result[], // Hold's Result int start, // Start Index int end // End Index ) { // CleanBuffer(result); // // Validate Args ... if ( end < 0 || start < 0 || (start == 0 && end == 0) || MathAbs(start - end == 0)) { return; } // // Validate Start and End Index ... bool isValidEnd = IsValidIndex(end); bool isValidStart = IsValidIndex(start); if (!isValidEnd || !isValidStart) { return; } // bool direction = end > start; if (direction) { // for (int i = start; i < end - 1; i++) { // XCollector iCollect = Get(i); // AddItemToBuffer( iCollect, result); } } else { // for (int i = end - 1; i >= start; i--) { // XCollector iCollect = Get(i); // AddItemToBuffer( iCollect, result); } } } // // Validate an Item ... bool IsValid( XCollector &item, // Specified Info bool ignoreTime = true // Ignore Times Checking ... ) { // bool result = false; // // Check Each Items contains Correct Value ... // result = item.volume >= 0; if (!result) { return result; } // result = item.maxDrawDown >= 0; if (!result) { return result; } // result = item.maxAllowedVolume >= 0; if (!result) { return result; } // result = item.minBalanceForOpenTrade >= 0; if (!result) { return result; } // // Check Time has Proper Value ... result = item.time > 0; if (!result) { return result; } // // Check time bigger than last Time ... int timesCount = ArraySize(mTimes); if ( !ignoreTime && timesCount >= 0) { // // Retrieve Last Added Times ... datetime lastTime; result = GetLastItem(lastTime, mTimes); if (!result) { return result; } // // Compare Last Time by current Time ... result = item.time > lastTime; if (!result) { return result; } } // return result; } // // Generate Logging String Representation ... string GenerateString( XCollector &item, // Specified Info string separator = "\n" // Separator Character ) { // string result = ""; // result += "time: " + (string)item.time + separator; result += "volume: " + (string)item.volume + separator; result += "maxDrawDown: " + (string)item.maxDrawDown + separator; result += "maxAllowedVolume: " + (string)item.maxAllowedVolume + separator; result += "minBalanceForOpenTrade: " + (string)item.minBalanceForOpenTrade + separator; // return result; } // // Protected ... protected: // // Private ... private: // // Max Draw Up touched till now ... double mMaxDrawUp; // // Max Draw Down touched till now ... double mMaxDrawDown; // // Last Time for Checks ... datetime mTimes[]; // // Volume at the Check Time ... double mVolumes[]; // // DrawDown for each Check ... double mMaxDrawDowns[]; // // Max Allowed Volume for each check ... double mMaxAllowedVolumes[]; // // Min Balance for Open Trades for Each Check ... double mMinBalanceForTradePrices[]; // // Reset ... void Clean() { // mMaxDrawUp = 0; mMaxDrawDown = 0; // CleanBuffer(mTimes); CleanBuffer(mVolumes); CleanBuffer(mMaxDrawDowns); CleanBuffer(mMaxAllowedVolumes); CleanBuffer(mMinBalanceForTradePrices); } // // Validate Index ... bool IsValidIndex( int index // Specified Index ) { // bool result = false; // int bufferSize = ArraySize(mTimes); if (bufferSize <= 0) { return result; } // result = index <= bufferSize - 1; // return result; } }; // // a Class for Managing Volumes ... class XCVolumeManager : public XCBase { // // Public ... public: // // Constructor ... XCVolumeManager( double staticVolumeRate, // Static Volume Calculation Mutiplier ENUM_STATIC_VOLUME_METHODS volumeMethod = X_STATIC_VOLUME_BASED_ON_DEPOSIT, // How to Calculate Static Volume double volumeMultiplier = 0, // Volume Multiplier double volumeMultiplierAppliedRate = 0, // Apply Volume Multiplier when Balance Increased by this rate double maxAllowedVolume = 0, // Max Allowed Volume double increaseMaxAllowedVolumeRate = 0 // Increase Max Allowed Volumes when Balance Increased by this rate ) { // mAccountInfo = new XCAccountInfo(); // ResetForceVolumeMultiplier(); // mVolumeMethod = volumeMethod; mStaticVoluemRate = staticVolumeRate; mVolumeMultiplier = volumeMultiplier; mMaxAllowedVolume = maxAllowedVolume; mVolumeMultiplierAppliedRate = volumeMultiplierAppliedRate; mIncreaseMaxAllowedVolumeRate = increaseMaxAllowedVolumeRate; } // // Deconstructor ... ~XCVolumeManager(void) {} // // Check Volume Multiplier ... bool CanUseVolumeMultiplier() { // bool result = false; // result = mVolumeMultiplier > 0 && mVolumeMultiplierAppliedRate > 0; // return result; } // // Check Max Volume ... bool CanUseMaxVolume() { // bool result = false; // result = mMaxAllowedVolume > 0; // return result; } // // Calculate Volume for Position ... double CalculateVolume( int numberOfOpenPositions = 0, // Number Of Open Signals string symbol = NULL // Specify Symbol ) { // double result = 0; // // Normalize Symbol ... if (StringLen(symbol) == 0) { symbol = _Symbol; } // // Static Volume ... result = GetStaticVolume(); // double multiplier = GetVolumeMultiplier(); result *= multiplier; // // Check Max Allowed Volume Exists ... double maxAllowedVolume = GetMaxAllowedVolume(); if (maxAllowedVolume > 0) { // result = result > maxAllowedVolume ? maxAllowedVolume : result; } // // Check Number of Open Positions ... if (numberOfOpenPositions >= 0) { // // Decrease Volume ... result /= (1 + numberOfOpenPositions); } // // Apply Force Volume Multiplier ... result *= mForceVolumeMultiplier; // // Retrieve Symbol Volume Info ... result = NormalizeVolume(result, symbol, 2); // return result; } // // Calculate Volume Multiplier ... double GetVolumeMultiplier() { // double result = 1; // double deposit = mAccountInfo.GetInitialBalance(); double balance = mAccountInfo.GetBalance(); bool canUseVolumeMultiplier = CanUseVolumeMultiplier(); if ( balance < deposit || !canUseVolumeMultiplier) { return result; } // // Apply Multiplier to Volume ... double baseGrowBalance = deposit * mVolumeMultiplierAppliedRate; double balanceGrows = balance - deposit; if (balanceGrows < baseGrowBalance) { return result; } // double applyMultiplierTimes = balanceGrows / baseGrowBalance; double roundedApplyMultiplierTimes = MathRound(applyMultiplierTimes); // if (applyMultiplierTimes < roundedApplyMultiplierTimes) { applyMultiplierTimes -= (1 - (roundedApplyMultiplierTimes - applyMultiplierTimes)); } // // Calculate result ... result = applyMultiplierTimes * mVolumeMultiplier; // return result; } // // Retrieve Required Balance Grows for Increase Max Allowed Volume ... double GetIncreaseMaxAllowedVolumeBalance() { // double result = 0; // if ( mMaxAllowedVolume <= 0 || mIncreaseMaxAllowedVolumeRate <= 0) { return result; } // result = mAccountInfo.GetInitialBalance() * mIncreaseMaxAllowedVolumeRate; // return result; } // // Calculate Max Allowed Volume ... double GetMaxAllowedVolume() { // double result = 0; // // Validate Args ... result = mMaxAllowedVolume <= 0 ? 0 : mMaxAllowedVolume; // double deposit = mAccountInfo.GetInitialBalance(); double balance = mAccountInfo.GetBalance(); bool canUseMaxAllowedVolume = CanUseMaxVolume(); if ( balance <= deposit || !canUseMaxAllowedVolume || mIncreaseMaxAllowedVolumeRate <= 0) { // return result; } // // Apply Multiplier to Volume ... double baseGrowBalance = GetIncreaseMaxAllowedVolumeBalance(); double balanceGrows = balance - deposit; if (balanceGrows < baseGrowBalance) { return result; } // double applyMultiplierTimes = balanceGrows / baseGrowBalance; double roundedApplyMultiplierTimes = MathRound(applyMultiplierTimes); // if (applyMultiplierTimes < roundedApplyMultiplierTimes) { applyMultiplierTimes -= (1 - (roundedApplyMultiplierTimes - applyMultiplierTimes)); } // result *= applyMultiplierTimes; // return result; } // // Get Static Volume ... double GetStaticVolume() { // double result = 0; // double deposit = mAccountInfo.GetInitialBalance(); double balance = mAccountInfo.GetBalance(); // switch (mVolumeMethod) { // case X_STATIC_VOLUME_BASED_ON_DEPOSIT: result = mStaticVoluemRate * deposit; break; // case X_STATIC_VOLUME_BASED_ON_BALANCE: result = mStaticVoluemRate * balance; break; } // return result; } // // Reset Froce Volume Multiplier ... void ResetForceVolumeMultiplier() { mForceVolumeMultiplier = 1; } // // Retrieve Current Force Volume Multiplier ... double GetCurrentForceVolumeMultiplier() { return mForceVolumeMultiplier; } // // Retrieve Next Increase Multiplier Price ... double GetIncreaseMultiplierBalance() { return mAccountInfo.GetInitialBalance() * mVolumeMultiplierAppliedRate; } // // Change Force Volume Multiplier ... void ChangeForceVolumeMultiplier( double rate // Change rate ) { // // Normalize rate ... if (rate <= 1) { rate = 1; } // mForceVolumeMultiplier = rate; } // // Increase Force Volume Multiplier ... void IncreaseForceVolumeMultiplier() { mForceVolumeMultiplier += 0.5; } // // Decrease Force Volume Multiplier ... void DecreaseForceVolumeMultiplier() { // if (mForceVolumeMultiplier <= 1) { return; } // mForceVolumeMultiplier -= 0.5; } // // Generate Current State Log String ... string GenerateStateString( string separator = "\n" // Log Separator ... ) { // string result = ""; // // Normallize Separator ... if (StringLen(separator) == 0) { separator = "\n"; } // result += "ForceVolumeMultiplier: " + (string)mForceVolumeMultiplier + separator; // result += "StaticVoluemRate: " + (string)mStaticVoluemRate + separator; result += "StaticVoluem: " + (string)GetStaticVolume() + separator; result += "VolumeMethod: " + EnumToString(mVolumeMethod) + separator; // result += "VolumeMultiplier: " + (string)mVolumeMultiplier + separator; result += "VolumeMultiplierAppliedRate: " + (string)mVolumeMultiplierAppliedRate + separator; // result += "MaxAllowedVolume: " + (string)mMaxAllowedVolume + separator; result += "IncreaseMaxAllowedVolumeRate: " + (string)mIncreaseMaxAllowedVolumeRate + separator; // return result; } // // Protected ... protected: // // Private ... private: // // an Instance of Account Info for reading Balance and Deposit and etc ... XCAccountInfo mAccountInfo; // // Force Volume Rate Multiplier ... double mForceVolumeMultiplier; // // Static Volume Calculation Mutiplier ... double mStaticVoluemRate; // // How to Calculate Static Volume ... ENUM_STATIC_VOLUME_METHODS mVolumeMethod; // // Volume Multiplier ... double mVolumeMultiplier; // // Apply Volume Multiplier when Balance Increased by this rate ... double mVolumeMultiplierAppliedRate; // // Max Allowed Volume double mMaxAllowedVolume; // // Increase Max Allowed Volumes when Balance Increased by this rate double mIncreaseMaxAllowedVolumeRate; }; // // a Class For Managing Signals Additional Data ... class XCSignalManager : public XCBase { // // Public ... public: // // Constructor ... XCSignalManager(void) { CleanData(); } // // Deconstructor ... ~XCSignalManager(void) {} // void Reset() { CleanData(); } // // Retrieve All Signals ... void GetAll( XSignal &result[] // Hold's Result ) { // CleanBuffer(result); // int signalsCount = ArraySize(mSignals); if (signalsCount <= 0) { return; } // for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = mSignals[i]; // AddItemToBuffer( iSignal, result); } } // // Count Items ... int Count() { return ArraySize(mSignals); } // // Retrieve Specific Signal by Ticket ... XSignal Get( ulong ticket // Signals Ticket ... ) { // XSignal result = {}; // // Check Exists ... bool isExists = IsExists(ticket); if (!isExists) { return result; } // int signalsCount = ArraySize(mSignals); if (signalsCount <= 0) { return result; } // for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = mSignals[i]; // if (iSignal.ticket == ticket) { // result = iSignal; break; } } // return result; } // // Check Signal Exists or not ... bool IsExists( ulong ticket // Specified Signal Ticket ) { // bool result = false; // int signalsCount = ArraySize(mSignals); if (signalsCount <= 0) { return result; } // for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = mSignals[i]; // if (iSignal.ticket == ticket) { // result = true; break; } } // return result; } bool IsExists( XSignal &signal // Specified Signal ) { // bool result = false; // int signalsCount = ArraySize(mSignals); if (signalsCount <= 0) { return result; } // for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = mSignals[i]; // if (iSignal.ticket == signal.ticket) { // result = true; break; } } // return result; } // // Add Signal ... bool Add( XSignal &signal // Specified Signal ) { // bool result = false; // // Validate Args ... if (signal.ticket <= 0) { return result; } // // Chekc Signal Exists ... bool isExists = IsExists(signal); if (isExists) { return result; } // AddItemToBuffer( signal, mSignals); result = true; // return result; } // // Update Specific Buffer ... bool Update( XSignal &signal // Specified Signal ) { // bool result = false; // // Validate Args ... if (signal.ticket <= 0) { return result; } // // Chekc Signal Exists ... bool isExists = IsExists(signal); if (!isExists) { return result; } // // Remove Signal ... Remove(signal); // // Add new One ... AddItemToBuffer( signal, mSignals); // result = true; // return result; } // // Remove Signal ... bool Remove( ulong ticket // Specified Signal Ticket ) { // bool result = false; // // Check Signal Exists ... bool isExists = IsExists(ticket); if (!isExists) { return result; } // int signalsCount = ArraySize(mSignals); if (signalsCount <= 0) { return result; } // XSignal signals[]; // for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = mSignals[i]; // if (iSignal.ticket != ticket) { AddItemToBuffer( iSignal, signals); } } // // Now we have to Clean All Signals and Replace them by signals[] buffer ... UpdateData(signals); // result = true; return result; } bool Remove( XSignal &signal // Specified Signal ) { // bool result = false; // // Check Signal Exists ... bool isExists = IsExists(signal); if (!isExists) { return result; } // int signalsCount = ArraySize(mSignals); if (signalsCount <= 0) { return result; } // XSignal signals[]; // for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = mSignals[i]; // if (iSignal.ticket != signal.ticket) { AddItemToBuffer( iSignal, signals); } } // // Now we have to Clean All Signals and Replace them by signals[] buffer ... UpdateData(signals); // result = true; return result; } // // Add Or Update ... bool AddOrUpdate( XSignal &signal // Specified Signal ) { // bool result = false; // // Validate Args ... if (signal.ticket <= 0) { return result; } // // Chekc Signal Exists ... bool isExists = IsExists(signal); if (!isExists) { result = Add(signal); } else { result = Update(signal); } // return result; } // // Protected ... protected: // // Private ... private: // // Holds Signals ... XSignal mSignals[]; // // Clean All Exists Data ... void CleanData() { CleanBuffer(mSignals); } // // Update Data ... void UpdateData( XSignal &source[] // a Buffer which needs to Replace ... ) { // CleanData(); // int sourceCount = ArraySize(source); if (sourceCount <= 0) { return; } // for (int i = 0; i < sourceCount; i++) { // XSignal iSignal = source[i]; // AddItemToBuffer( iSignal, mSignals); } } }; // // XSaherElm Trade Class ... class XCTrade : public XCBase { // // all public features ... public: // // Constructor ... void XCTrade( string tag, // Specify a Tag for Trader instance string symbol, // Specify Trader Symbol int slippage, // Specify Slippage ulong magicNumber, // Specify Magic Number bool useVirtualTPSL, // Use Virtual TP SL int maxAllowedTrades, // Specify Max Allowed Trades double minBallanceForOpenTrades, // Specify Minimum Balance for Open Trades double minAllowedFreeMarginForOpenTrades, // Specify Minimum Free Marging for Open Trades bool useSignalProtector = true // Specify Use Signal Protector or not ) { // mTag = tag; mSymbol = symbol; mSlippage = slippage; mMagicNumber = magicNumber; mUseVirtualTPSL = useVirtualTPSL; mMaxAllowedTrades = maxAllowedTrades; mMinBallanceForOpenTrades = minBallanceForOpenTrades; mMinAllowedFreeMarginForOpenTrades = minAllowedFreeMarginForOpenTrades; // mTrader = new XSCTrade(); // mTrader.SetAsyncMode(false); mTrader.SetDeviationInPoints(mSlippage); mTrader.SetExpertMagicNumber(mMagicNumber); // // Setting Log Level ... mTrader.LogLevel(LOG_LEVEL_ERRORS); // mSignalManager = new XCSignalManager(); // Reset(); } // // Deconstructor ... void ~XCTrade() { } // // START Configuring Class Functions ... // // // Reset all Variables ... void Reset() { // mSignalManager.Reset(); // mDaysForRead = 1; mScanStarted = false; // // Reset On Trade Counter ... ResetOnTradeContext(); // // Init On Trade Context ... InitOnTradeContext(); } // // END Configuring Class Functions ... // // // START Count ... // // // Count Open Positions ... int Count() { // int result = 0; // int total = PositionsTotal(); for (int i = 0; i < total; i++) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mPositionInfo.Magic() != mMagicNumber) { continue; } // if (mPositionInfo.Symbol() != mSymbol) { continue; } // result++; } // return result; } // // Count Longs ... int CountLongs() { int result = CountByType(X_SIGNAL_LONG); return result; } // // Count Shorts ... int CountShorts() { int result = CountByType(X_SIGNAL_SHORT); return result; } // // Count Specific Type Of Positions ... int CountByType(ENUM_POSITION_TYPE type) { // int result = 0; // int total = PositionsTotal(); for (int i = 0; i < total; i++) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mPositionInfo.Symbol() != mSymbol) { continue; } // if (mPositionInfo.PositionType() != type) { continue; } // result++; } // return result; } // // Count By Type ... int CountByType(ENUM_X_SIGNAL_TYPE type) { // // Validate Args ... ENUM_POSITION_TYPE mType = POSITION_TYPE_BUY; if (type == X_SIGNAL_LONG) { mType = POSITION_TYPE_BUY; } else if (type == X_SIGNAL_SHORT) { mType = POSITION_TYPE_SELL; } // int result = CountByType(mType); return result; } // // END Count ... // // // START Retrieve ... // // // Retrieve Specified Position by it's Ticket ... XSignal GetSignal( ulong ticket // Specified Ticket ) { // XSignal result = {}; // result = PositionToSignal(ticket); // return result; } // // Get Last Signal ... XSignal GetLastSignal() { // XSignal result = {}; // XSignal signals[]; GetSignals(signals); int signalsCount = ArraySize(signals); if (signalsCount <= 0) { return result; } // result = signals[0]; // return result; } // // Retrieve Last Executed Signal ... bool GetLastSignal(XSignal &signal) { // bool result = false; // XSignal signals[]; GetSignals(signals); int signalsCount = ArraySize(signals); if (signalsCount <= 0) { return result; } // signal = signals[0]; result = true; // return result; } // // Retrieve All Positions ... void GetSignals( XSignal &result[] // Holds Result ... ) { // CleanBuffer(result); // int totalPositions = PositionsTotal(); for (int i = 0; i < totalPositions; i++) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mPositionInfo.Magic() != mMagicNumber) { continue; } // if (mPositionInfo.Symbol() != mSymbol) { continue; } // // Position to Signal ... XSignal signal = PositionToSignal(i); Add( signal, result); } } // // Retrieve Type Specific Signals ... void GetSignals( XSignal &result[], // Holds Result ... ENUM_X_SIGNAL_TYPE type // Specified Sginal Type ... ) { // CleanBuffer(result); // XSignal signals[]; GetSignals(signals); // int signalsCount = ArraySize(signals); if (signalsCount <= 0) { return; } // // Loop ... for (int i = signalsCount - 1; i >= 0; i--) { // XSignal iSignal = signals[i]; // if (type == X_SIGNAL_UNKNOWN) { Add( iSignal, result); } else if (iSignal.type == type) { Add( iSignal, result); } } } // // Filter Signals By Searching Comments ... void FilterSignals( XSignal &result[], // Holds Result ... const string query, // Search in Comment Qeury ... ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specified Sginal Type ... ) { // CleanBuffer(result); // XSignal signals[]; GetSignals( signals, type); int signalsCount = ArraySize(signals); // // Validate Args ... if ( StringLen(query) <= 0 || signalsCount <= 0) { return; } // // Loop ... for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = signals[i]; // int queryPos = StringFind( iSignal.comment, query); bool isContains = queryPos > -1; if (!isContains) { continue; } // Add( iSignal, result); } } // // Get All Trades Which Candle Passed after Open ... void GetOldSignals( XSignal &result[], // Holds Result int life, // Max Candle Passed after Trades Open ENUM_TIMEFRAMES period = NULL, // Calculate Candles based on time frame ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specify Type of Positions ) { // CleanBuffer(result); // // Normalize Period ... if (period == NULL) { period = _Period; } // XSignal signals[]; GetSignals( signals, type); int signalsCount = ArraySize(signals); if (signalsCount <= 0) { return; } // // Current Time Frame Candle Index ... int currentBarIndex = 0; // // Loop through Positions ... for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = signals[i]; // // Retrieve Trade Open Bar Index based on Current Period ... int tradeOpenBarIndex = iBarShift( mSymbol, period, iSignal.time); // // Calculate Trade Life ... int diff = MathAbs(currentBarIndex - tradeOpenBarIndex); // bool isPassed = diff >= life; if (isPassed) { // Add( iSignal, result); } } } // // Get In Profit Signals ... void GetInProfitSignals( XSignal &result[], // Holds Result double minProfit = 0, // Minimum Profit To Close Trades ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specify Type of Positions ) { // CleanBuffer(result); // XSignal signals[]; GetSignals( signals, type); int signalsCount = ArraySize(signals); if (signalsCount <= 0) { return; } // // Loop ... for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = signals[i]; // bool isPassed = minProfit <= 0 && iSignal.profit > 0 ? true : iSignal.profit >= minProfit; if (isPassed) { Add( iSignal, result); } } } // // Get In Drawdown Signals ... void GetInDrawdownSignals( XSignal &result[], // Holds Result double maxDrawDown = 0, // Minimum Profit To Close Trades ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specify Type of Positions ) { // CleanBuffer(result); // XSignal signals[]; GetSignals( signals, type); int signalsCount = ArraySize(signals); if (signalsCount <= 0) { return; } // // Loop ... for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = signals[i]; // bool isPassed = maxDrawDown <= 0 && iSignal.profit < 0 ? true : iSignal.profit >= (-1 * maxDrawDown); if (isPassed) { Add( iSignal, result); } } } // // Retrieve Max In Draw Down Trade ... XSignal GetMaxInDrawdownSignal( ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specify Type of Positions ) { // XSignal result = {}; // XSignal signals[]; GetInDrawdownSignals( signals, 0, type); int signalsCount = ArraySize(signals); if (signalsCount <= 0) { return result; } // // Loop ... for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = signals[i]; // result = (result.ticket <= 0 && result.profit == 0) || result.profit > iSignal.profit ? iSignal : result; } // return result; } // // Calculate Profits Of all Open Signals ... double GetSignalsProfit( ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specify Type of Positions ) { // double result = 0; // XSignal signals[]; GetSignals(signals, type); int signalsCount = ArraySize(signals); if (signalsCount <= 0) { return result; } // // Loop ... for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = signals[i]; // result += iSignal.profit; } // return result; } // // END Retrieve ... // // // START Signal Execution Actions ... // // // Execute a Signal in Market ... ENUM_EXECUTION_SIGNAL_RESULT ExecuteSignal( XSignal &signal, // Specified Signal bool ignoreNumberOfTraes = false, // Ignore Number of Trades bool checkAccountConditions = true // Check Account Balance, Equity and Free Margin for Signal Execution ) { // ENUM_EXECUTION_SIGNAL_RESULT result = X_TRADER_UNKNOWN_ERROR; // // Validate Signal ... bool isValid = IsValidSignal(signal); if (!isValid) { // result = X_TRADER_INVALID_SIGNAL_ERROR; return result; } // // Check Account Equity ... bool isEquityPassed = !checkAccountConditions ? true : IsEquityReadyForTrade(); if (!isEquityPassed) { // result = X_TRADER_NOT_ENOUGH_EQUITY_ERROR; return result; } // // Check Account Balance ... bool isBalancePassed = !checkAccountConditions ? true : IsBalanceReadyForTrade(); if (!isBalancePassed) { // result = X_TRADER_NOT_ENOUGH_BALANCE_ERROR; return result; } // // Check Account FreeMargin ... bool isFreeMarginPassed = !checkAccountConditions ? true : IsFreeMarginReadyForTrade(); if (!isFreeMarginPassed) { // result = X_TRADER_NOT_ENOUGH_MARIGIN_ERROR; return result; } // // Check Number of Open Trades ... int openTradesCount = Count(); bool isTradeCountPassed = ignoreNumberOfTraes ? true : openTradesCount < mMaxAllowedTrades; if (!isTradeCountPassed) { // result = X_TRADER_MAX_TRADES_REACHED_ERROR; return result; } // bool isExecuted = signal.type == X_SIGNAL_LONG ? Buy( signal.volume, signal.entry, mUseVirtualTPSL ? 0 : signal.sl, mUseVirtualTPSL ? 0 : signal.tp, signal.comment) : signal.type == X_SIGNAL_SHORT ? Sell( signal.volume, signal.entry, mUseVirtualTPSL ? 0 : signal.sl, mUseVirtualTPSL ? 0 : signal.tp, signal.comment) : false; if (isExecuted) { // ulong ticket = PositionGetTicket(PositionsTotal() - 1); // signal.id = ticket; signal.ticket = ticket; // AddOrUpdateSignalInfo(signal); // result = X_TRADER_SUCCEED_EXECUTION; } // return result; } // // This Function, Handling Following Works on Open Positions: // - Close On SL if Reached ... // - Close On TP if Reached ... // - Make Risk Free Trades ... bool HandleSignals( XTraderHandlerResult &handlerResult, // Holds Result bool ignoreRiskFree = false // Ignore Risk Free Trdaes ) { // bool result = false; // // Cleanup Result ... CleanBuffer(handlerResult.sl); CleanBuffer(handlerResult.tp); CleanBuffer(handlerResult.rf); // // Reading Open Positions ... XSignal signals[]; GetSignals(signals); int signalsCount = ArraySize(signals); if (signalsCount <= 0) { return result; } // double deviation = mSlippage * GetPoints(mSymbol); // // Loop ... for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = signals[i]; // bool isLong = iSignal.type == X_SIGNAL_LONG; double entry = GetEntry(iSignal.symbol, iSignal.type); double exit = GetExit(iSignal.symbol, iSignal.type); double spread = GetSpread(iSignal.symbol); double appliedTPPrice = iSignal.tp > 0 ? isLong ? iSignal.tp - deviation : iSignal.tp + deviation : 0; double appliedSLPrice = iSignal.sl > 0 ? isLong ? iSignal.sl + deviation : iSignal.sl - deviation : 0; // double usedPrice = exit; // bool isSLTouched = isLong ? usedPrice <= appliedSLPrice : usedPrice >= appliedSLPrice; // bool isTPTouched = isLong ? usedPrice >= appliedTPPrice : usedPrice <= appliedTPPrice; // // Handle SL ... if ( // iSignal.sl > 0 // && // isSLTouched // && // mUseVirtualTPSL) { // string comment = GenerateSignalSLComment(iSignal); // bool isClosed = Close( iSignal.ticket, comment); if (isClosed) { AddItemToBuffer( iSignal, handlerResult.sl); } } // // Handle TP ... if ( // iSignal.tp > 0 // && // isTPTouched // && // mUseVirtualTPSL) { // string comment = GenerateSignalTPComment(iSignal); // bool isClosed = Close( iSignal.ticket, comment); if (isClosed) { AddItemToBuffer( iSignal, handlerResult.tp); } } // // Handle Risk Free ... if ( // !ignoreRiskFree // && // iSignal.riskFreeStep > 0 // && // iSignal.riskFreeRate > 0 // ) { // // Make Signals Risk Free Only if Signal In Profit ... if (iSignal.profit <= 0) { continue; } // // Base Price is ENTRY, then Last Level, in each level SL is Last Level ... // // Calculate Risk Free Level/Multiplier ... double level = 0; double roundedLevel = 0; double rStepPrice = PipsToPrice(iSignal.riskFreeStep); double rBasePrice = iSignal.sl > 0 && iSignal.sl > iSignal.entry ? iSignal.sl : iSignal.entry; // double exit = GetExit(iSignal.type); // // Check Base Price for Signal reached with Exit Price ... bool isExitPriceReachedBasePrice = isLong ? exit > rBasePrice : exit < rBasePrice; if (!isExitPriceReachedBasePrice) { continue; } // // Calculate Risk Free Step Multiplier ... level = MathAbs(exit - rBasePrice) / rStepPrice; // // Check Level Must Bigger than 1 ... if (level < 1) { continue; } // // Normalize Level ... roundedLevel = MathRound(level); if (level < roundedLevel) { level -= (1 - (roundedLevel - level)); } else if (level > roundedLevel) { level -= (level - roundedLevel); } // // Generate Comment ... string comment = GenerateSignalRFComment(iSignal, (int)level); // // Calculate SL ... double slDistance = spread; double sl = isLong ? exit - slDistance : exit + slDistance; // // Increase TP One Level if Exists ... double tp = iSignal.tp; if (iSignal.tp > 0 && (isLong ? iSignal.tp < rBasePrice + rStepPrice : iSignal.tp > rBasePrice - rStepPrice)) { // tp = isLong ? iSignal.tp + rStepPrice : iSignal.tp - rStepPrice; } // double rVolume = NormalizeVolume((iSignal.volume * iSignal.riskFreeRate), iSignal.symbol); // // Update Signal Volume ... double volume = iSignal.volume - rVolume; // bool isClosedPartial = ClosePartial( iSignal.ticket, rVolume, comment); if (isClosedPartial) { // bool isModified = true; if (!mUseVirtualTPSL) { // isModified = Modify( iSignal.ticket, sl, tp, comment); } // if (isModified) { // // Try to Update Signal ... XSignal s = mSignalManager.Get(iSignal.ticket); // // Apply Changes on Signal ... s.sl = sl; s.tp = tp; s.volume = volume; // // Update Signal ... bool isUpdated = false; bool isRemoved = false; if (volume == 0) { isRemoved = mSignalManager.Remove(s); } else if (volume > 0) { isUpdated = mSignalManager.AddOrUpdate(s); } if ( isUpdated || isRemoved) { // AddItemToBuffer( s, handlerResult.rf); } } } else { mSignalManager.Remove(iSignal.ticket); } } } // result = ArraySize(handlerResult.tp) > 0 || ArraySize(handlerResult.sl) > 0 || ArraySize(handlerResult.rf) > 0; // return result; } // // Close All Trades ... void CloseSignals( XSignal &result[], // Holds Result ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specify Type of Positions ) { // CleanBuffer(result); // XSignal signals[]; GetSignals( signals, type); int signalsCount = ArraySize(signals); if (signalsCount <= 0) { return; } // for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = signals[i]; // string comment = GenerateSignalForceCloseComment(iSignal); // bool isClosed = Close( iSignal.ticket, comment); if (isClosed) { Add( iSignal, result); } } } // // Close Pyramid Signals ... void CloseInPyramidSignals( XSignal &result[], // Holds Result double pyramid = 0, // Close Pyramid Profit ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specify Type of Positions ) { // CleanBuffer(result); // XSignal signals[]; GetSignals( signals, type); int signalsCount = ArraySize(signals); if (signalsCount <= 0) { return; } // double profit = 0; for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = signals[i]; // profit += iSignal.profit; } // // Normalize Pyramid ... if (pyramid < 0) { pyramid = 0; } // if (profit > pyramid) { CloseSignals(result); } } // // Close All Trades Which Candle Passed after Open ... void CloseOldSignals( XSignal &result[], // Holds Result int life, // Max Candle Passed after Trades Open ENUM_TIMEFRAMES period = NULL, // Calculate Candles based on time frame ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specify Type of Positions ) { // CleanBuffer(result); // XSignal signals[]; GetOldSignals( signals, life, period, type); int signalsCount = ArraySize(signals); if (signalsCount <= 0) { return; } // for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = signals[i]; // string comment = GenerateSignalAgeComment(iSignal); // bool isClosed = Close( iSignal.ticket, comment); if (isClosed) { Add( iSignal, result); } } } // // Close In Profit Signals ... void CloseInProfitSignals( XSignal &result[], // Holds Result double minProfit = 0, // Minimum Profit To Close Trades ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specify Type of Positions ) { // CleanBuffer(result); // XSignal signals[]; GetInProfitSignals( signals, minProfit, type); int signalsCount = ArraySize(signals); if (signalsCount <= 0) { return; } // for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = signals[i]; // string comment = GenerateSignalProfitComment(iSignal); // bool isClosed = Close( iSignal.ticket, comment); if (isClosed) { Add( iSignal, result); } } } // // Close In Drawdown Signals ... void CloseInDrawdownSignals( XSignal &result[], // Holds Result double maxDrawDown = 0, // Minimum Profit To Close Trades ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specify Type of Positions ) { // CleanBuffer(result); // XSignal signals[]; GetInDrawdownSignals( signals, maxDrawDown, type); int signalsCount = ArraySize(signals); if (signalsCount <= 0) { return; } // for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = signals[i]; // string comment = GenerateSignalProfitComment(iSignal); // bool isClosed = Close( iSignal.ticket, comment); if (isClosed) { Add( iSignal, result); } } } // // END Signal Execution Actions ... // // // START Actions ... // // // Force Open a Buy/Long Position ... bool Buy( double volume, // position volume double price, // execution price double sl = 0, // stop loss price double tp = 0, // take profit price const string comment = "" // comment ) { // bool result = false; // result = mTrader.Buy( volume, mSymbol, price, sl, tp, comment); // return result; } // // Send BUY LIMIT order ... bool BuyLimit( double volume, // order volume double price, // order price double sl = 0.0, // stop loss price double tp = 0.0, // take profit price ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime datetime expiration = 0, // order expiration time string comment = "" // comment ) { // bool result = false; // result = mTrader.BuyLimit( volume, price, mSymbol, sl, tp, typeTime, expiration, comment); // return result; } // // Send BUY STOP order ... bool BuyStop( double volume, // order volume double price, // order price double sl = 0.0, // stop loss price double tp = 0.0, // take profit price ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime datetime expiration = 0, // order expiration time string comment = "" // comment ) { // bool result = false; // result = mTrader.BuyStop( volume, price, mSymbol, sl, tp, typeTime, expiration, comment); // return result; } // // Force Open a Sell/Short Position ... bool Sell( double volume, // position volume double price, // execution price double sl = 0, // stop loss price double tp = 0, // take profit price const string comment = "" // comment ) { // bool result = false; // result = mTrader.Sell( volume, mSymbol, price, sl, tp, comment); // return result; } // // Send SELL LIMIT order ... bool SellLimit( double volume, // order volume double price, // order price double sl = 0.0, // stop loss price double tp = 0.0, // take profit price ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime datetime expiration = 0, // order expiration time string comment = "" // comment ) { // bool result = false; // result = mTrader.SellLimit( volume, price, mSymbol, sl, tp, typeTime, expiration, comment); // return result; } // // Send SELL STOP order ... bool SellStop( double volume, // order volume double price, // order price double sl = 0.0, // stop loss price double tp = 0.0, // take profit price ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime datetime expiration = 0, // order expiration time string comment = "" // comment ) { // bool result = false; // result = mTrader.SellStop( volume, price, mSymbol, sl, tp, typeTime, expiration, comment); // return result; } // // Modify Position ... bool Modify( const ulong ticket, // position ticket double sl = 0, // stop loss price double tp = 0, // take profit const string comment = "" // comment ) { // bool result = false; // // Validate Args ... if (tp <= 0 && sl <= 0) { result = false; return result; } // result = mTrader.PositionModify( ticket, sl, tp, comment); if (result) { // if (mSignalManager.IsExists(ticket)) { // XSignal signal = GetSignal(ticket); // mSignalManager.Update(signal); } } // return result; } // // Close Position By Ticket ... bool Close( ulong ticket, // Position Ticket string comment = "" // Close Position By Specific Comment ) { // bool result = false; // // Try to Select Position ... if (!mPositionInfo.SelectByTicket(ticket)) { return result; } // // Close Position By Specific Comment ... result = mTrader.PositionClose( ticket, mSlippage, comment); if (result) { // if (mSignalManager.IsExists(ticket)) { mSignalManager.Remove(ticket); } } // return result; } // // Close Partial By Ticket ... bool ClosePartial( ulong ticket, // Position Ticket double volume, // Volume Size for Partial Closing string comment = "" // Close Position By Specific Comment ) { // bool result = false; // if (!mPositionInfo.SelectByTicket(ticket)) { return result; } // result = mTrader.PositionClosePartial( ticket, volume, mSlippage, comment); if (result) { // if (mSignalManager.IsExists(ticket)) { // XSignal signal = GetSignal(ticket); // mSignalManager.Update(signal); } } // return result; } // // END Actions ... // // // START Account Related ... // // // Retrieve Minimum Balance For Open Trades ... double GetMinBalanceForOpenTrades() { // double result = mMinBallanceForOpenTrades; // double balance = mAccountInfo.GetBalance(); double deposit = mAccountInfo.GetInitialBalance(); if (balance > deposit) { // double rate = mMinBallanceForOpenTrades / deposit; // double ratedBalance = balance * rate; // result = MathMax(mMinBallanceForOpenTrades, ratedBalance); } // return result; } // // Check Account Has Minimum Balance For Trade ... bool IsBalanceReadyForTrade() { // bool result = false; // double minBalance = GetMinBalanceForOpenTrades(); result = mAccountInfo.GetBalance() >= minBalance; // return result; } // // Check Free Margin Has Enough For Trade ... bool IsFreeMarginReadyForTrade() { // bool result = false; // double freeMargin = mAccountInfo.GetFreeMargin(); // result = freeMargin >= mMinAllowedFreeMarginForOpenTrades; // return result; } // // Check Equity Has Enough For Trade ... bool IsEquityReadyForTrade() { // bool result = false; // double equity = mAccountInfo.GetEquity(); // result = equity >= mMinAllowedFreeMarginForOpenTrades; // return result; } // // END Account Related ... // // // START Signal Related ... // // // Validate Signal ... bool IsValidSignal( XSignal &signal // Specified Signal for Execution ) { // bool result = false; // // Validate Signal Type ... result = signal.type != X_SIGNAL_UNKNOWN; if (!result) { return result; } // // Check Symbol ... result = StringLen(signal.symbol) == 0 ? true : signal.symbol == mSymbol; if (!result) { return result; } // // Check magic number ... result = signal.magicNumber <= 0 ? true : signal.magicNumber == mMagicNumber; if (!result) { return result; } // // Check Entry ... result = signal.entry > 0; if (!result) { return result; } // // // // Check SL ... // // For Fix RiskFree Issues Ignore this ... // result = signal.sl == 0 ? true : signal.type == X_SIGNAL_LONG ? signal.sl < signal.entry // : signal.sl > signal.entry; // if (!result) // { // return result; // } // // Check TP ... result = signal.tp == 0 ? true : signal.type == X_SIGNAL_LONG ? signal.tp > signal.entry : signal.tp < signal.entry; if (!result) { return result; } // // Check Volume ... result = signal.volume > 0; if (!result) { return result; } // // Check Time ... result = signal.time > 0; if (!result) { return result; } // return result; } // // Get Signal InDirection (Reversal) Type ... ENUM_X_SIGNAL_TYPE GetSignalIndirectionType( XSignal &signal // Specified Signal ) { // ENUM_X_SIGNAL_TYPE result = X_SIGNAL_UNKNOWN; // switch (signal.type) { // case X_SIGNAL_LONG: result = X_SIGNAL_SHORT; break; // case X_SIGNAL_SHORT: result = X_SIGNAL_LONG; break; } // return result; } // // Get Signal InDirection (Reversal) Type ... ENUM_X_SIGNAL_TYPE GetIndirectionSignalType( ENUM_X_SIGNAL_TYPE type // Specified Type ) { // ENUM_X_SIGNAL_TYPE result = X_SIGNAL_UNKNOWN; // switch (type) { // case X_SIGNAL_LONG: result = X_SIGNAL_SHORT; break; // case X_SIGNAL_SHORT: result = X_SIGNAL_LONG; break; } // return result; } // // Calculate SignalAge ... int GetSignalAge( datetime time // Signal Execution Time ) { // int result = 0; // // Validate Arg ... if (time <= 0) { return result; } // int sIndex = iBarShift( mSymbol, _Period, time); // datetime cTime = iTime( mSymbol, _Period, 0); int cIndex = iBarShift( mSymbol, _Period, cTime); // result = MathAbs(cIndex - sIndex); // return result; } int GetSignalAge( datetime time, // Signal Execution Time ENUM_TIMEFRAMES period // Specify Time Frame ) { // int result = 0; // // Validate Arg ... if (time <= 0) { return result; } // int sIndex = iBarShift( mSymbol, period, time); // datetime cTime = iTime( mSymbol, period, 0); int cIndex = iBarShift( mSymbol, _Period, cTime); // result = MathAbs(cIndex - sIndex); // return result; } int GetSignalAge( XSignal &signal // Specified Signal ) { // int result = 0; // // Validate Arg ... if ( signal.time <= 0 || !IsValid(signal, mMagicNumber)) { return result; } // result = GetSignalAge(signal.time); // return result; } int GetSignalAge( XSignal &signal, // Specify Signal ENUM_TIMEFRAMES period // Specify Time Frame ) { // int result = 0; // // Validate Arg ... if ( signal.time <= 0 || !IsValid(signal, mMagicNumber)) { return result; } // result = GetSignalAge( signal.time, period); // return result; } // // Prepare a Signall ... XSignal GenerateSignal( ENUM_X_SIGNAL_TYPE type, // Signal Type double tp = 0, // Take Profit double sl = 0, // Stop Loss double volume = 0, // Volume double riskFreeStep = 0, // Risk Free Step Price double riskFreeRate = 0 // Risk Free Rate ) { // XSignal result = {}; // // Validate Arg ... if (type == X_SIGNAL_UNKNOWN) { return result; } // // Check Signal Type ... bool isLong = type == X_SIGNAL_LONG; // // Retrieve entry Price ... double entry = GetEntry(mSymbol, type); double spread = GetSpread(mSymbol); // result.tp = tp; result.sl = sl; result.type = type; result.entry = entry; result.symbol = mSymbol; result.magicNumber = mMagicNumber; result.riskFreeStep = riskFreeStep; result.riskFreeRate = riskFreeRate; result.time = iTime(mSymbol, _Period, 0); result.volume = NormalizeVolume(volume, mSymbol); // // Since we Use signal instance to Generate Comment, this must be at the end ... result.comment = GenerateSignalComment(result); // return result; } // // Convert a Signal to String Representation ... string ToString( XSignal &signal // Specified Signal ) { // string result = ""; // if (!IsValid(signal, mMagicNumber) || signal.ticket <= 0) { return result; } // // TICKET ... // it is very importants since they hold position info ... result += X_SIGNAL_TICKET + "(" + (string)signal.ticket + ")"; // // TYPE ... string typeStr = GetSignalType(signal.type); result += "_" + X_SIGNAL_TYPE + "(" + typeStr + ")"; // // TP ... result += "_" + X_SIGNAL_TP + "(" + (string)signal.tp + ")"; // // SL ... result += "_" + X_SIGNAL_SL + "(" + (string)signal.sl + ")"; // // RFS ... result += "_" + X_SIGNAL_RISKFREE_STEP + "(" + (string)signal.riskFreeStep + ")"; // // RFR ... result += "_" + X_SIGNAL_RISKFREE_RATE + "(" + (string)signal.riskFreeRate + ")"; // return result; } // // Generate Comments for Specific Signal ... string GenerateSignalComment( ENUM_X_SIGNAL_TYPE type, // Specify Kind Signal Type double volume, // Signal Volume bool isCrossSignal = false // Specify Signal Cross ) { // string result = ""; // string typeStr = GetSignalType(type); if ( volume <= 0 || StringLen(typeStr) == 0) { return result; } // volume = NormalizeVolume(volume, mSymbol); // result = mTag + (!isCrossSignal ? "" : "_Cross_") + "_" + typeStr; // return result; } string GenerateSignalComment( XSignal &signal, // Specified Signal bool isCrossSignal = false // Specify Signal Cross ) { // string result = GenerateSignalComment( signal.type, signal.volume, isCrossSignal // ); // return result; } // // Generate Signal RF TP Comment ... string GenerateSignalRFComment( XSignal &signal, // Specified Signal int level // Which Step of RFS ) { // string result = ""; // // Validate Signal and it's Ticket ... if (!IsValidSignal(signal) || signal.ticket <= 0) { return result; } // double exit = NormalizePrice(GetExit(signal.symbol, signal.type), signal.symbol); // string prefix = X_SIGNAL_RISKFREE_STEP + "(" + (string)signal.ticket + ")"; // result = // level > 0 ? prefix + "_" + (string)level + ": " + (string)exit : prefix + ": " + (string)exit; // ; // return result; } // // Generate Signal TP Comment ... string GenerateSignalTPComment( XSignal &signal // Specified Signal ) { // string result = ""; // // Validate Signal and it's Ticket ... if (!IsValidSignal(signal) || signal.ticket <= 0) { return result; } // double exit = NormalizePrice(GetExit(signal.symbol, signal.type), signal.symbol); // result = // X_SIGNAL_TP + "(" + (string)signal.ticket + "): " + (string)exit; // ; // return result; } // // Generate Signal SL Comment ... string GenerateSignalSLComment( XSignal &signal // Specified Signal ) { // string result = ""; // // Validate Signal and it's Ticket ... if (!IsValidSignal(signal) || signal.ticket <= 0) { return result; } // double exit = NormalizePrice(GetExit(signal.symbol, signal.type), signal.symbol); // result = // X_SIGNAL_SL + "(" + (string)signal.ticket + "): " + (string)exit; // ; // return result; } // // Generate Signal Profit Comment ... string GenerateSignalProfitComment( XSignal &signal // Specified Signal ) { // string result = ""; // // Validate Signal and it's Ticket ... if (!IsValidSignal(signal) || signal.ticket <= 0) { return result; } // result = // "Profit(" + (string)signal.ticket + "): " + (string)signal.profit; // ; // return result; } // // Generate Signal Force Close Comment ... string GenerateSignalForceCloseComment( XSignal &signal // Specified Signal ) { // string result = ""; // // Validate Signal and it's Ticket ... if (!IsValidSignal(signal) || signal.ticket <= 0) { return result; } // result = // "FC(" + (string)signal.ticket + "): " + (string)signal.profit; // ; // return result; } // // Generate Signal Age Comment ... string GenerateSignalAgeComment( XSignal &signal // Specified Signal ) { // string result = ""; // // Validate Signal and it's Ticket ... if (!IsValidSignal(signal) || signal.ticket <= 0) { return result; } // int age = GetSignalAge(signal); // result = // "(" + (string)signal.ticket + ") A: " + (string)age + ", P:" + (string)signal.profit; // ; // return result; } // // Generate a Signal Object name for Draw Events On Chart ... string GenerateSignalObjectName( ulong ticket // Specify Ticket ) { // string result = ""; // // Validate Arg ... if (ticket <= 0) { return result; } // // TICKET ... // it is very importants since they hold position info ... result += "T(" + (string)ticket + ")"; // return result; } string GenerateSignalObjectName( XSignal &signal // Specified Signal ) { // string result = ""; // // Validate Arg ... if (!IsValid(signal, mMagicNumber)) { return result; } // result = GenerateSignalObjectName(signal.ticket); // return result; } // // Genrate a Signal Event Object Name ... string GenerateSignalEventObjectName( ulong ticket // Specify Ticket ) { // string result = ""; // result = GenerateSignalObjectName(ticket) + "_Event"; // return result; } string GenerateSignalEventObjectName( XSignal &signal // Specified Signal ) { // string result = ""; // result = GenerateSignalEventObjectName(signal.ticket); // return result; } // // END Signal Related ... // // // START Deals ... // // // Count Deals ... int DealsCount( datetime start = -1, // Start Date datetime end = -1 // End Date ) { // int result = 0; // XDeal deals[]; GetDeals( deals, start, end); result = ArraySize(deals); // return result; } // // Retrieve All Deals ... void GetDeals( XDeal &result[], // Hold's Result datetime start = -1, // Start Date datetime end = -1 // End Date ) { // CleanBuffer(result); // // Select History if Start and End date provided ... if (start > -1) { // // Normalize End date ... if (end == -1) { end = TimeCurrent(); } // bool isSelect = HistorySelect(start, end); if (!isSelect) { return; } } // int total = HistoryDealsTotal(); if (total <= 0) { return; } // // Loop ... for (int i = total - 1; i >= 0; i--) { // // Select by Index ... bool isSelect = mDealInfo.SelectByIndex(i); if (!isSelect) { continue; } // // Check Magic ... ulong magic = mDealInfo.Magic(); bool isMagicSame = magic == mMagicNumber; if (!isMagicSame) { continue; } // // Check Symbol ... string symbol = mDealInfo.Symbol(); bool isSymbolSame = symbol == mSymbol; if (!isSymbolSame) { continue; } // XDeal deal = ToXDealByIndex(i); // Add( deal, result); } } // // Retrieve Last Deal ... XDeal GetLastDeal() { // XDeal result = {}; // XDeal deals[]; GetDeals(deals); int dealsCount = ArraySize(deals); if (dealsCount <= 0) { return result; } // result = deals[0]; // return result; } // // END Deals ... // // // START Orders ... // // // Count Orders ... int OrdersCount( datetime start = -1, // Start Date datetime end = -1 // End Date ) { // int result = 0; // XOrder orders[]; GetOrders( orders, start, end); result = ArraySize(orders); // return result; } // // Retrieve Orders ... void GetOrders( XOrder &result[], // Hold's Result datetime start = -1, // Start Date datetime end = -1 // End Date ) { // CleanBuffer(result); // // Select History if Start and End date provided ... if (start > -1) { // // Normalize End date ... if (end == -1) { end = TimeCurrent(); } // bool isSelect = HistorySelect(start, end); if (!isSelect) { return; } } // int total = HistoryOrdersTotal(); if (total <= 0) { return; } // // Loop ... for (int i = total - 1; i >= 0; i--) { // // Select by Index ... bool isSelect = mOrderInfo.SelectByIndex(i); if (!isSelect) { continue; } // // Check Magic ... ulong magic = mOrderInfo.Magic(); bool isMagicSame = magic == mMagicNumber; if (!isMagicSame) { continue; } // // Check Symbol ... string symbol = mOrderInfo.Symbol(); bool isSymbolSame = symbol == mSymbol; if (!isSymbolSame) { continue; } // XOrder order = ToXOrderByIndex(i); // Add( order, result); } } // // Retrieve Last Order ... XOrder GetLastOrder() { // XOrder result = {}; // XOrder orders[]; GetOrders(orders); int ordersCount = ArraySize(orders); if (ordersCount <= 0) { return result; } // result = orders[0]; // return result; } // // END Orders ... // // // START OnTrade Handlers ... // // // Handle OnTrade Event ... void HandleOnTradeEvent( XOnTradeHandlerResult &result // Hold's Result ) { // if (mScanStarted) { ProcessOnTradeContext(result); } else { InitOnTradeContext(); } } // // END OnTrade Handlers ... // // // Retrieve Magic Number ... ulong GetMagicNumber() { return mMagicNumber; } // // all protected features ... protected: // // all private features ... private: // // Specified Unique Tag ... string mTag; // // which Symbol ... string mSymbol; // // using deviation, it must be in Point ... int mSlippage; // // using magic number ... ulong mMagicNumber; // // Detect Using Virtual TP or SL ... bool mUseVirtualTPSL; // // Specify Max Allowed Trades int mMaxAllowedTrades; // // Minimum Free Marging for Open Trades double mMinAllowedFreeMarginForOpenTrades; // // Minimum Balance for Open Trades double mMinBallanceForOpenTrades; // // using CTrade instance ... XSCTrade mTrader; // // Deals Info ... CDealInfo mDealInfo; // // Order Info ... COrderInfo mOrderInfo; // // An Instance Of XCAccount Info for Handling Account Related Actions ... XCAccountInfo mAccountInfo; // // using PositionInfo instance ... CPositionInfo mPositionInfo; // // Signal Manager ... XCSignalManager mSignalManager; // // START OnTrade Handlers ... // // int mDaysForRead; // // set the limits of the trade history on the global scope ... // // // start date for trade history in cache ... datetime mStartDate; // // end date for trade history in cache ... datetime mEndDate; // // global OnTrade counters ... // // number of active orders ... int mOrdersCount; // // number of open positions ... int mPositionsCount; // // number of deals in the trade history cache ... int mDealsCount; // // number of orders in the trade history cache ... int mHistoryOrdersCount; // // flag of counter relevance ... bool mScanStarted; // // Check Statrt Date In Trade History ... void CheckStartDateInTradeHistory() { // // initial interval, if we were to start working right now .. datetime currStart = TimeCurrent() - (mDaysForRead * PeriodSeconds(PERIOD_D1)); // // make sure that the start limit of the trade history has not gone // more than 1 day over the intended date ... if (currStart - mStartDate > PeriodSeconds(PERIOD_D1)) { // // correct the start date of history to be loaded in the cache ... mStartDate = currStart; // // now reload the trade history for the updated interval ... HistorySelect(mStartDate, mEndDate); // // correct the deal and order counters in history for further comparison mHistoryOrdersCount = HistoryOrdersTotal(); mDealsCount = HistoryDealsTotal(); } } // // Process On Trade Context ... void ProcessOnTradeContext( XOnTradeHandlerResult &result // Hold's Result ) { // mEndDate = TimeCurrent(); // ResetLastError(); // // download trading history from the specified interval to the program cache ... bool selected = HistorySelect(mStartDate, mEndDate); if (!selected) { // LogMessage("Failed to Load OnTrade Context History ..."); // return; } // // get the current values ... int currOrders = OrdersTotal(); int currPositions = PositionsTotal(); int currDeals = HistoryDealsTotal(); int currHistoryOrders = HistoryOrdersTotal(); // // Orders ... // check if the number of active orders has been changed ... if (currOrders != mOrdersCount) { // // number of active orders has been changed ... result.hasNewOrder = true; result.newOrders = currOrders - mOrdersCount; // // update the value ... mOrdersCount = currOrders; } // // Positions ... // changes in the number of open positions ... if (currPositions != mPositionsCount) { // // number of open positions has been changed ... result.hasNewPosition = true; result.newPositions = currPositions - mPositionsCount; // // update the value ... mPositionsCount = currPositions; } // // Deals ... // changes in the number of deals in the trade history cache ... if (currDeals != mDealsCount) { // // number of deals in the trade history cache has been changed ... result.hasNewDeal = true; result.newDeals = currDeals - mDealsCount; // // update the value ... mDealsCount = currDeals; } // // History Orders ... // changes in the number of history orders in the trade history cache ... if (currHistoryOrders != mHistoryOrdersCount) { // // number of history orders in the trade history cache has been changed ... result.hasNewHistoryOrder = true; result.newHistoryOrders = currHistoryOrders - mHistoryOrdersCount; // // update the value ... mHistoryOrdersCount = currHistoryOrders; } // // checking if it is necessary to change the limits of the trade history to be requested in cache ... CheckStartDateInTradeHistory(); } // // Reset On Trade Scanner Context ... void ResetOnTradeContext() { // mEndDate = TimeCurrent(); mStartDate = mEndDate - (mDaysForRead * PeriodSeconds(PERIOD_D1)); } // // Initial Context Of Trade Scanner ... void InitOnTradeContext() { // ResetLastError(); // // load history ... bool selected = HistorySelect(mStartDate, mEndDate); if (!selected) { // LogMessage("Failed to Load OnTrade Context History ..."); // return; } // // get the current value ... mOrdersCount = OrdersTotal(); mPositionsCount = PositionsTotal(); mDealsCount = HistoryDealsTotal(); mHistoryOrdersCount = HistoryOrdersTotal(); // mScanStarted = true; } // // END OnTrade Handlers ... // // // START Signal Private ... // // // Add Or Update Signal ... void AddOrUpdateSignalInfo( XSignal &signal // Specified Signal ) { // bool isExists = mSignalManager.IsExists(signal); if (isExists) { mSignalManager.Remove(signal.ticket); } // bool isAddOrUpdated = mSignalManager.AddOrUpdate(signal); if (isAddOrUpdated) { // color longColor = clrAqua; color shortColor = clrFuchsia; // DrawSignalShape( signal, longColor, shortColor); } } // // Retrieve Signal String From Chart Event ... XSignal RetrieveSignal( ulong ticket // Specify Position Ticket ) { // XSignal result = {}; // if (ticket <= 0) { return result; } // result = mSignalManager.Get(ticket); // return result; } void RetrieveSignal( XSignal &signal // Specified Signal ) { // XSignal tSignal = mSignalManager.Get(signal.ticket); // // Fill signal by tSignal Data ... // since tese properties may change in signal manipulation times ... signal.tp = tSignal.tp; signal.sl = tSignal.sl; signal.riskFreeStep = tSignal.riskFreeStep; signal.riskFreeRate = tSignal.riskFreeRate; } // // Convert Position to Signal by Index ... XSignal PositionToSignal(int index) { // XSignal result = {}; // if (!mPositionInfo.SelectByIndex(index)) { return result; } // ulong ticket = mPositionInfo.Ticket(); result = PositionToSignal(ticket); // return result; } // // Position To Signal by Ticket ... XSignal PositionToSignal(ulong ticket) { // XSignal result = {}; // if (!mPositionInfo.SelectByTicket(ticket)) { return result; } // bool isExists = mSignalManager.IsExists(ticket); if (isExists) { result = RetrieveSignal(ticket); } // // Ticket ... result.ticket = mPositionInfo.Ticket(); // // ID ... result.id = mPositionInfo.Identifier(); // // Symbol ... result.symbol = mPositionInfo.Symbol(); // // Type ... ENUM_POSITION_TYPE pType = (ENUM_POSITION_TYPE)mPositionInfo.PositionType(); ENUM_X_SIGNAL_TYPE type = pType == POSITION_TYPE_BUY ? X_SIGNAL_LONG : X_SIGNAL_SHORT; result.type = type; // // MagicNumber ... result.magicNumber = mPositionInfo.Magic(); // // Entry/Open Price ... result.entry = mPositionInfo.PriceOpen(); // // Take Profit ... result.tp = result.tp <= 0 && mPositionInfo.TakeProfit() > 0 ? mPositionInfo.TakeProfit() : result.tp; // // Stop Loss ... result.sl = result.sl <= 0 && mPositionInfo.StopLoss() > 0 ? mPositionInfo.StopLoss() : result.sl; // // Profit ... result.profit = mPositionInfo.Profit(); // // Time ... result.time = mPositionInfo.Time(); // // Volume ... result.volume = mPositionInfo.Volume(); // // Comment ... result.comment = mPositionInfo.Comment(); // return result; } // // Converts a Deal to XDeal by Index ... XDeal ToXDealByIndex(int index) { // XDeal result = {}; // bool isSelect = mDealInfo.SelectByIndex(index); if (!isSelect) { return result; } // // Read Deal Ticket ... ulong ticket = mDealInfo.Ticket(); result = ToXDealByTicket(ticket); // return result; } // // Converts a Deal to XDeal by Ticket ... XDeal ToXDealByTicket(ulong ticket) { // XDeal result = {}; // mDealInfo.Ticket(ticket); // result.time = mDealInfo.Time(); result.swap = mDealInfo.Swap(); result.magic = mDealInfo.Magic(); result.order = mDealInfo.Order(); result.entry = mDealInfo.Entry(); result.price = mDealInfo.Price(); result.ticket = mDealInfo.Ticket(); result.symbol = mDealInfo.Symbol(); result.type = mDealInfo.DealType(); result.profit = mDealInfo.Profit(); result.volume = mDealInfo.Volume(); result.comment = mDealInfo.Comment(); result.positionId = mDealInfo.PositionId(); result.commission = mDealInfo.Commission(); result.reason = (ENUM_DEAL_REASON)HistoryDealGetInteger( ticket, DEAL_REASON); // return result; } // // Convert an Order to XOrder by Index ... XOrder ToXOrderByIndex(int index) { // XOrder result = {}; // bool isSelect = mOrderInfo.SelectByIndex(index); if (!isSelect) { return result; } // ulong ticket = mOrderInfo.Ticket(); result = ToXOrderByTicket(ticket); // return result; } // // Convert an Order to XOrder by Ticket ... XOrder ToXOrderByTicket(ulong ticket) { // XOrder result = {}; // bool isSelect = mOrderInfo.Select(ticket); if (!isSelect) { return result; } // result.state = mOrderInfo.State(); result.magic = mOrderInfo.Magic(); result.ticket = mOrderInfo.Ticket(); result.symbol = mOrderInfo.Symbol(); result.type = mOrderInfo.OrderType(); result.comment = mOrderInfo.Comment(); result.stopLoss = mOrderInfo.StopLoss(); result.typeTime = mOrderInfo.TypeTime(); result.timeDone = mOrderInfo.TimeDone(); result.timeSetup = mOrderInfo.TimeSetup(); result.positionId = mOrderInfo.PositionId(); result.priceOpen = mOrderInfo.PriceOpen(); result.takeProfit = mOrderInfo.TakeProfit(); result.typeFilling = mOrderInfo.TypeFilling(); result.priceCurrent = mOrderInfo.PriceCurrent(); result.volumeInitial = mOrderInfo.VolumeInitial(); result.volumeCurrent = mOrderInfo.VolumeCurrent(); result.timeExpiration = mOrderInfo.TimeExpiration(); result.priceStopLimit = mOrderInfo.PriceStopLimit(); result.reason = (ENUM_ORDER_REASON)HistoryOrderGetInteger( ticket, ORDER_REASON); // return result; } // // END Signal Private ... // }; // // a Class For Guard Account ... class XCGuard : public XCBase { // // Public ... public: // // Constructor ... XCGuard( int oldAge, // Age for Old Trades ENUM_X_GUARD_ACTIONS oldGuardAction, // Guard Action for Too Old State double criticalFactor, // Critical DrawDown Factor based On Balance ENUM_X_GUARD_ACTIONS criticalAction, // Guard Action for Critical State double maxFactor, // Max DrawDown Factor based on Balance ENUM_X_GUARD_ACTIONS maxAction, // Guard Action for Max State int GuardStopoutFiredAfterTouches, // Guard Stopout if Max State touched ENUM_X_GUARD_SUPPORT_METHODS supportMethod // How to Support Signals ) { // mSupportPrefix = "SPT"; mDirectional = "SPD"; mInDirectional = "SPIND"; // mOldAge = oldAge; mOldGuardAction = oldGuardAction; // mMaxFactor = maxFactor; mMaxAction = maxAction; mCriticalFactor = criticalFactor; mCriticalAction = criticalAction; mGuardStopoutFiredAfterTouches = GuardStopoutFiredAfterTouches; // mSupportMethod = supportMethod; // mAccountInfo = new XCAccountInfo(); // double deposit = mAccountInfo.GetInitialBalance(); // if ( maxFactor > 0 && maxFactor < 1) { mMaxValue = maxFactor * deposit; } // if ( criticalFactor > 0 && criticalFactor < 1) { mCriticalValue = criticalFactor * deposit; } // Reset(); ResetMaxDrawDownTouches(); } // // Deconstructor ... ~XCGuard() {} // // Reset List ... void Reset() { // CleanBuffer(mGuardedSignals); CleanBuffer(mSupportedSignals); } // // Reset Consecutive Max DrawDown Touches ... void ResetMaxDrawDownTouches() { mOccuredconsecutiveMaxDraDownTouches = 0; } // // Calculate and Retrieve Critical DrawDown Value ... double GetCriticalValue() { // double result = mCriticalValue; if (mCriticalFactor <= 0) { return result; } // double deposit = mAccountInfo.GetInitialBalance(); double balance = mAccountInfo.GetBalance(); // if (balance > deposit) { // double balanceBasedCriticalDrawDown = mCriticalFactor * balance; // result = MathMax( mCriticalValue, balanceBasedCriticalDrawDown); } // return result; } // // Calculate and Retrieve Max Allowed DrawDown Value ... double GetMaxValue() { // double result = mMaxValue; if (mMaxValue <= 0) { return result; } // double deposit = mAccountInfo.GetInitialBalance(); double balance = mAccountInfo.GetBalance(); // if (balance > deposit) { // double balanceBasedMaxAllwedDrawDown = mMaxFactor * balance; // result = MathMax( mMaxValue, balanceBasedMaxAllwedDrawDown); } // return result; } // // Guard Account Protection ... bool Guard( XGuardHandlerResult &guardResult, // Hold's Message string &message, // Hold's Message XCTrade &trader, // Specified Trader ENUM_TIMEFRAMES period = NULL // Specified Time Frame for Detecting Signal Ages ) { // message = ""; // // Clean Result of Guard ... CleanBuffer(guardResult.olds); CleanBuffer(guardResult.maxes); CleanBuffer(guardResult.criticals); // bool result = false; // // So Important is to Guard DrawDowns ... result = GuardDrawDown( guardResult, message, trader); if (result) { return result; } // // Then we have to Guard Old Trades ... result = GuardOlds( guardResult, message, trader); // return result; } // // Handle Guard Old Trades ... bool GuardOlds( XGuardHandlerResult &guardResult, // Hold's Message string &message, // Hold's Message XCTrade &trader, // Specified Trader ENUM_TIMEFRAMES period = NULL // Specified Time Frame for Detecting Signal Ages ) { // // Cleanup Message ... message = ""; // // Clean Result of Guard ... CleanBuffer(guardResult.olds); // bool result = false; // // Validate Args ... if ( mOldAge <= 0 || mOldGuardAction == X_GUARD_DO_NOTHING) { return result; } // // Normalize Args ... if (period == NULL) { period = _Period; } // // Retrieve Old Trades ... XSignal oldSignals[]; trader.GetOldSignals( oldSignals, mOldAge, period); int oldSignalsCount = ArraySize(oldSignals); if (oldSignalsCount <= 0) { return result; } // result = DoGuardAction( guardResult, message, trader, mOldGuardAction, X_GUARDED_OLD, // Specify Guard Reason period // Specified Running Time Frame for Signal Age Calculations ); // return result; } // // Hnadle Guard DrawDown ... bool GuardDrawDown( XGuardHandlerResult &guardResult, // Hold's Message string &message, // Hold's Message XCTrade &trader // Specified Trader ) { // message = ""; // // Clean Result of Guard ... CleanBuffer(guardResult.maxes); CleanBuffer(guardResult.criticals); // bool result = false; // // Check State for Guard ... bool isCriticalGuardEnabled = mCriticalFactor > 0; bool isMaxGuardEnabled = mMaxFactor > 0; bool isGuardEnabled = isMaxGuardEnabled; // if (!isGuardEnabled) { return result; } // double maxValue = GetMaxValue(); double criticalValue = GetCriticalValue(); // double profitSums = trader.GetSignalsProfit(); // bool isMaxReached = profitSums < 0 && isMaxGuardEnabled && MathAbs(profitSums) >= maxValue; bool isCriticalReached = profitSums < 0 && isCriticalGuardEnabled && MathAbs(profitSums) >= criticalValue; // if (!isMaxReached && !isCriticalReached) { // // Reset Consecutive Max DrawDown Touches ... ResetMaxDrawDownTouches(); // return result; } // // Check For Critical Guard ... if (isCriticalReached && !isMaxReached) { // result = DoGuardAction( guardResult, message, trader, mCriticalAction, X_GUARDED_CRITICAL); } else if (isMaxReached) { // result = DoGuardAction( guardResult, message, trader, mMaxAction, X_GUARDED_MAX); // // Handle Guard StopOut Action ... mOccuredconsecutiveMaxDraDownTouches++; if ( mMaxAction != X_GUARD_DO_NOTHING && mMaxAction != X_GUARD_CLOSE_ALL && mGuardStopoutFiredAfterTouches > 0 && mOccuredconsecutiveMaxDraDownTouches >= mGuardStopoutFiredAfterTouches) { // XSignal closed[]; trader.CloseSignals(closed); int closedCount = ArraySize(closed); if (closedCount > 0) { // for (int i = 0; i < closedCount; i++) { // XSignal iSignal = closed[i]; // AddItemToBuffer( iSignal, guardResult.maxes); } // message = "Guard StopOut Action Closed (" + (string)closedCount + ") Signals and Release Account ..."; // guardResult.isStopOut = true; // result = true; } } } // return result; } // // Do Signal Protections and apply Support ... bool ProtectSignals( XSignal &mResult[], // Hold's Result XCTrade &trader, // Specified Trader int numberOfItemsCheck = 30 // Number of Items to check ) { // bool result = false; // CleanBuffer(mResult); // // Check Supports Enabled ... result = IsSupportEnabled(); if (!result) { return result; } // // Update Supports ... XSignal signals[]; trader.GetSignals(signals); int signalsCount = ArraySize(signals); if (signalsCount > 0) { // for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = signals[i]; // bool isExists = IsSupportExists(iSignal.ticket); if (isExists) { UpdateSupport(iSignal); } } } // // Count Supporteds ... XProtectedSignal supporteds[]; GetAllSupports(supporteds); int supportedCount = ArraySize(supporteds); result = supportedCount > 0; if (!result) { return result; } // // Loop through ... for (int i = 0; i < supportedCount; i++) { // XProtectedSignal iP = supporteds[i]; // bool canDoDirectional = CanDoDirectionalSupport( trader, iP.ticket, numberOfItemsCheck); bool canDoInDirectional = CanDoInDirectionalSupport( trader, iP.ticket, numberOfItemsCheck); // if ( !canDoDirectional && !canDoInDirectional) { continue; } // // Do Directional ... if (canDoDirectional) { // // Generate Propper Signal ... XSignal sdSignal = GenerateDirectionalSupportSignal( iP.ticket, trader); // ENUM_EXECUTION_SIGNAL_RESULT executionResult = trader.ExecuteSignal( sdSignal, true, false); bool isExecuted = executionResult == X_TRADER_SUCCEED_EXECUTION; if (isExecuted) { // XSignal eSignal = trader.GetSignal(sdSignal.ticket); // AddItemToBuffer( eSignal, mResult); } } // // Do Indirectional ... else if (canDoInDirectional) { // // Generate Propper Signal ... XSignal sindSignal = GenerateDirectionalSupportSignal( iP.ticket, trader); // ENUM_EXECUTION_SIGNAL_RESULT executionResult = trader.ExecuteSignal( sindSignal, true, false); bool isExecuted = executionResult == X_TRADER_SUCCEED_EXECUTION; if (isExecuted) { // XSignal eSignal = trader.GetSignal(sindSignal.ticket); // AddItemToBuffer( eSignal, mResult); } } } // result = ArraySize(mResult) > 0; // return result; } // // Validate State ... bool Validate() { // bool result = false; // result = mMaxFactor > 0 && (mCriticalFactor > 0 ? mCriticalFactor < mMaxFactor : true); // return result; } // // START Guarded Signals Functions ... // // // Add new Protecte Signal ... bool Add( XSignal &signal // Specified Signal ) { // bool result = false; // bool isExists = IsExists(signal.ticket); if (isExists) { return result; } // XProtectedSignal item; // datetime time = TimeCurrent(); // item.ticket = signal.ticket; // AddItemToBuffer( time, item.time); // AddItemToBuffer( signal.profit, item.profit); // AddItemToBuffer( item, mGuardedSignals); // return result; } // // Get All ... void GetAll( XProtectedSignal &result[] // Hold's Result ) { // CopyBuffer( mGuardedSignals, result); } // // Get ... XProtectedSignal Get( ulong ticket // Specified Signal Ticket ) { // XProtectedSignal result; // bool isExists = IsExists(ticket); if (!isExists) { return result; } // int protectedCounts = ArraySize(mGuardedSignals); if (protectedCounts <= 0) { return result; } // for (int i = 0; i < protectedCounts; i++) { // XProtectedSignal iProtected = mGuardedSignals[i]; // if (iProtected.ticket == ticket) { // result = iProtected; break; } } // return result; } // // Remove ... bool Remove( ulong ticket // Specified Signal Ticket ) { // bool result = false; // result = IsExists(ticket); if (!result) { return result; } // int protectedCounts = ArraySize(mGuardedSignals); result = protectedCounts > 0; if (!result) { return result; } // XProtectedSignal cleared[]; for (int i = 0; i < protectedCounts; i++) { // XProtectedSignal iProtected = mGuardedSignals[i]; // if (iProtected.ticket != ticket) { AddItemToBuffer( iProtected, cleared); } } // // Update Source by Cleared ... CopyBuffer( cleared, mGuardedSignals); // result = true; // return result; } // // Update ... bool Update( ulong ticket, // Specified Signal Ticket datetime time, // Specified Last Checked time double profit // Specified Signal Profit // XProtectedSignal &item // Specified which object to Update ) { // bool result = false; // int protectedCounts = ArraySize(mGuardedSignals); result = protectedCounts > 0; if (!result) { return result; } // result = IsExists(ticket); if (!result) { return result; } // // Retrieve Struct ... XProtectedSignal item = Get(ticket); AddItemToBuffer( time, item.time); AddItemToBuffer( profit, item.profit); // result = Remove(ticket); if (!result) { return result; } // AddItemToBuffer( item, mGuardedSignals); result = true; // return result; } bool Update( XProtectedSignal &item // Specified Protected Item ) { // bool result = false; // datetime time; result = GetLastItem( time, item.time); if (!result) { return result; } // double profit; result = GetLastItem( profit, item.profit); if (!result) { return result; } // result = Update( item.ticket, time, profit); // return result; } bool Update( XSignal &signal // Specified Signal ) { // bool result = false; // ulong ticket = signal.ticket; datetime time = TimeCurrent(); double profit = signal.profit; // result = Update( ticket, time, profit); // return result; } // // Add Or Update ... bool AddOrUpdate( XSignal &signal // Specified Signal ) { // bool result = false; // bool isExists = IsExists(signal.ticket); if (!isExists) { result = Add(signal); } else { result = Update(signal); } // return result; } // // Check Exists ... bool IsExists( ulong ticket // Specified Signal Ticket ) { // bool result = false; // // Validate Args ... if (ticket <= 0) { return result; } // int protectedCounts = ArraySize(mGuardedSignals); if (protectedCounts <= 0) { return result; } // for (int i = 0; i < protectedCounts; i++) { // XProtectedSignal iProtected = mGuardedSignals[i]; // if (iProtected.ticket == ticket) { // result = true; break; } } // return result; } // // Count Protecteds ... int Count() { // int result = 0; // result = ArraySize(mGuardedSignals); // return result; } // // END Guarded Signals Functions ... // // // START Supported Signals Functions ... // // // Check can Handle Support Signals or not ... bool IsSupportEnabled() { // bool result = false; // result = mSupportMethod != X_SUPPORT_DO_NOTHING; // return result; } // // Retrieve List Of Supported Signals ... void GetSupportSignals( XSignal &result[], // Hold's Result ... XCTrade &trader // Specified Trader class Instance ... ) { // CleanBuffer(result); // XSignal signals[]; trader.GetSignals(signals); int signalsCount = ArraySize(signals); if (signalsCount <= 0) { return; } // for (int i = -0; i < signalsCount; i++) { // XSignal iSignal = signals[i]; // bool isSupport = IsSupport(iSignal.comment); if (isSupport) { AddItemToBuffer( iSignal, result); } } } // // Retrieve List Of Specific Signals Supported Signals ... void GetSignalSupports( XSignal &result[], // Hold's Result ... XCTrade &trader, // Specified Trader class Instance ... ulong ticket // Specified Signal Ticket ... ) { // CleanBuffer(result); // // Validate Args ... if (ticket <= 0) { return; } // // Check Signal Exists using Trader ... XSignal parentSignal = trader.GetSignal(ticket); bool isValid = parentSignal.ticket > 0 && parentSignal.ticket == ticket && StringLen(parentSignal.comment) > 0; if (!isValid) { return; } // XSignal supportSignals[]; GetSupportSignals( supportSignals, trader); int supportSignalsCount = ArraySize(supportSignals); if (supportSignalsCount <= 0) { return; } // for (int i = 0; i < supportSignalsCount; i++) { // XSignal iSignal = supportSignals[i]; // bool isBelongsToParent = IsBelongsToParent( ticket, iSignal.comment); if (isBelongsToParent) { AddItemToBuffer( iSignal, result); } } } // // Check Specific Support Conditions for Opening Directional Support ... bool CanDoDirectionalSupport( XCTrade &trader, // Specified Trader class Instance ... ulong ticket, // Specified Signal Ticket ... int numberOfItemsCheck = 30 // Number of Items to check ... ) { // bool result = false; // // Check Supports Enabled ... result = IsSupportEnabled(); if (!result) { return result; } // // Check Support Method Allows Directional ... result = mSupportMethod == X_SUPPORT_FULL || mSupportMethod == X_SUPPORT_IN_DRAWUP_DIRECTIONAL; if (!result) { return result; } // // Validate Ticket ... result = ticket > 0; if (!result) { return result; } // // Check Supports Count ... int supportedCount = ArraySize(mSupportedSignals); result = supportedCount > 0; if (!result) { return result; } // // Check Ticket Exists in Supports ... result = IsSupportExists(ticket); if (!result) { return result; } // // Check signal Doesn't have any Support ... XSignal supports[]; GetSignalSupports( supports, trader, ticket); int supportsCount = ArraySize(supports); result = supportsCount <= 0; if (!result) { return result; } // // Retrieve Support Model ... XProtectedSignal sInfo = GetSupport(ticket); // // Validate Model ... int sTimesCount = ArraySize(sInfo.time); int sProfitsCount = ArraySize(sInfo.profit); result = sInfo.ticket == ticket && sTimesCount == sProfitsCount && sTimesCount >= numberOfItemsCheck && sProfitsCount >= numberOfItemsCheck; if (!result) { return result; } // // Validate Signal Age ... XSignal sSignal = trader.GetSignal(ticket); int sSignalAge = trader.GetSignalAge(sSignal.time); result = sSignalAge >= numberOfItemsCheck; if (!result) { return result; } // // Extrat Profits ... double lastProfits[]; for (int i = sProfitsCount - 1; i >= (sProfitsCount - numberOfItemsCheck); i++) { // double iProfit = sInfo.profit[i]; // AddItemToBuffer( iProfit, lastProfits); } // string logMsg = ToString(lastProfits); LogMessage("" + (string)ticket + " lastProfits: \n" + logMsg); // result = false; // // Now implement Business Logics ... // return result; } // // Check Specific Support Conditions for Opening InDirectional Support ... bool CanDoInDirectionalSupport( XCTrade &trader, // Specified Trader class Instance ... ulong ticket, // Specified Signal Ticket ... int numberOfItemsCheck = 30 // Number of Items to check ... ) { // bool result = false; // // Check Supports Enabled ... result = IsSupportEnabled(); if (!result) { return result; } // // Check Support Method Allows Directional ... result = mSupportMethod == X_SUPPORT_FULL || mSupportMethod == X_SUPPORT_IN_DRAWDOWN_INDIRECTIONAL; if (!result) { return result; } // // Validate Ticket ... result = ticket > 0; if (!result) { return result; } // // Check Supports Count ... int supportedCount = ArraySize(mSupportedSignals); result = supportedCount > 0; if (!result) { return result; } // // Check Ticket Exists in Supports ... result = IsSupportExists(ticket); if (!result) { return result; } // // Check signal Doesn't have any Support ... XSignal supports[]; GetSignalSupports( supports, trader, ticket); int supportsCount = ArraySize(supports); result = supportsCount <= 0; if (!result) { return result; } // // Retrieve Support Model ... XProtectedSignal sInfo = GetSupport(ticket); // // Validate Model ... int sTimesCount = ArraySize(sInfo.time); int sProfitsCount = ArraySize(sInfo.profit); result = sInfo.ticket == ticket && sTimesCount == sProfitsCount && sTimesCount >= numberOfItemsCheck && sProfitsCount >= numberOfItemsCheck; if (!result) { return result; } // // Validate Signal Age ... XSignal sSignal = trader.GetSignal(ticket); int sSignalAge = trader.GetSignalAge(sSignal.time); result = sSignalAge >= numberOfItemsCheck; if (!result) { return result; } // // Extrat Profits ... double lastProfits[]; for (int i = sProfitsCount - 1; i >= (sProfitsCount - numberOfItemsCheck); i++) { // double iProfit = sInfo.profit[i]; // AddItemToBuffer( iProfit, lastProfits); } // string logMsg = ToString(lastProfits); LogMessage("" + (string)ticket + " lastProfits: \n" + logMsg); // result = false; // // Now implement Business Logics ... // return result; } // // Generate Directional Support Signal for Parent Signal ... XSignal GenerateDirectionalSupportSignal( ulong ticket, // Specified Parent Signal Ticket ... XCTrade &trader // Specified Trader Class ... ) { // XSignal result = {}; // // Validate Args ... if (ticket <= 0) { return result; } // XSignal pSignal = trader.GetSignal(ticket); bool isValidParent = pSignal.ticket > 0 && pSignal.ticket == ticket && StringLen(pSignal.comment) > 0; if (!isValidParent) { return result; } // ENUM_X_SIGNAL_TYPE type = pSignal.type; bool isLong = IsLong(type); // double entry = GetEntry( pSignal.symbol, type); double exit = GetExit( pSignal.symbol, type); // double reward = PipsToPrice( pSignal.symbol, 6); double risk = PipsToPrice( pSignal.symbol, 1); // double tp = isLong ? entry + reward : entry - reward; // double sl = isLong ? exit - risk : exit + risk; // double rfStep = 2; double rfRate = 0.5; // double volume = NormalizeVolume( pSignal.volume / 2, pSignal.symbol, 2); // // Generate Signal using Trader Class Instance ... result = trader.GenerateSignal( // type, tp, sl, volume, rfStep, rfRate // ); // return result; } // // Generate InDirectional Support Signal for Parent Signal ... XSignal GenerateInDirectionalSupportSignal( ulong ticket, // Specified Parent Signal Ticket ... XCTrade &trader // Specified Trader Class ... ) { // XSignal result = {}; // // Validate Args ... if (ticket <= 0) { return result; } // XSignal pSignal = trader.GetSignal(ticket); bool isValidParent = pSignal.ticket > 0 && pSignal.ticket == ticket && StringLen(pSignal.comment) > 0; if (!isValidParent) { return result; } // ENUM_X_SIGNAL_TYPE type = trader .GetIndirectionSignalType(pSignal.type); bool isLong = IsLong(type); // double entry = GetEntry( pSignal.symbol, type); double exit = GetExit( pSignal.symbol, type); // double reward = PipsToPrice( pSignal.symbol, 6); double risk = PipsToPrice( pSignal.symbol, 1); // double tp = isLong ? entry + reward : entry - reward; // double sl = isLong ? exit - risk : exit + risk; // double rfStep = 2; double rfRate = 0.5; // double volume = NormalizeVolume( pSignal.volume / 2, pSignal.symbol, 2); // // Generate Signal using Trader Class Instance ... result = trader.GenerateSignal( // type, tp, sl, volume, rfStep, rfRate // ); // return result; } // // Generate Specific Signals Support Signal Comment ... string GenerateSupportSignalComment( ulong ticket, // Specified Parent Signal Ticket ENUM_X_SIGNAL_TYPE type, // Specified Support Signal Type bool isInDirectional = false // Specified Support Signal Direction ) { // string result = ""; // if (ticket <= 0) { return result; } // string typeString = GetSignalType(type); string directionStr = GenerateSupportDirection(isInDirectional); // result = mSupportPrefix + "(" + (string)ticket + ")_" + X_SIGNAL_TYPE + "(" + typeString + ")_" + directionStr; // return result; } // // Get Support Direction String Representation ... string GenerateSupportDirection( bool isInDirectional = false // Specified Support Signal Direction ) { // string result = ""; // result = isInDirectional ? mInDirectional : mDirectional; // return result; } // // Check an String Is Directional Or not ... bool IsDirectionalSupport( string comment // Specified Comment ... ) { // bool result = false; // result = IsSupport(comment); if (!result) { return result; } // int sPos = StringFind( comment, mDirectional); result = sPos >= 0; // return result; } // // Check an String Is In Directional Or not ... bool IsInDirectionalSupport( string comment // Specified Comment ... ) { // bool result = false; // result = IsSupport(comment); if (!result) { return result; } // int sPos = StringFind( comment, mInDirectional); result = sPos >= 0; // return result; } // // Check an String Is Support or not ... bool IsSupport( string comment // Specified Comment ... ) { // bool result = false; // int sPos = StringFind( comment, mSupportPrefix); result = sPos >= 0; // return result; } // // Extract Parent of Support Signal Ticket from a comment ... ulong ExtractParentTicket( string comment // Specified Comment ... ) { // ulong result = 0; // bool isSupport = IsSupport(comment); if (!isSupport) { return result; } // // TICKET ... string ticketStr = ExtractString( comment, mSupportPrefix + "(", ")"); if (StringLen(ticketStr) > 0) { result = (ulong)ticketStr; } // return result; } // // Check a Comment belongs to Support Signal or not ... bool IsBelongsToParent( ulong ticket, // Specified Parent Signal Ticket string comment // Specified Support Signal Comment ) { // bool result = false; // // Validate Arg ... if (ticket <= 0) { return result; } // result = IsSupport(comment); if (!result) { return result; } // ulong spTicket = ExtractParentTicket(comment); result = spTicket == ticket; // return result; } // // Add new Protecte Signal ... bool AddSupport( XSignal &signal // Specified Signal ) { // bool result = false; // bool isExists = IsSupportExists(signal.ticket); if (isExists) { return result; } // XProtectedSignal item; // datetime time = TimeCurrent(); // item.ticket = signal.ticket; // AddItemToBuffer( time, item.time); // AddItemToBuffer( signal.profit, item.profit); // AddItemToBuffer( item, mSupportedSignals); // return result; } // // Get All ... void GetAllSupports( XProtectedSignal &result[] // Hold's Result ) { // CopyBuffer( mSupportedSignals, result); } // // Get ... XProtectedSignal GetSupport( ulong ticket // Specified Signal Ticket ) { // XProtectedSignal result; // bool isExists = IsSupportExists(ticket); if (!isExists) { return result; } // int protectedCounts = ArraySize(mSupportedSignals); if (protectedCounts <= 0) { return result; } // for (int i = 0; i < protectedCounts; i++) { // XProtectedSignal iProtected = mSupportedSignals[i]; // if (iProtected.ticket == ticket) { // result = iProtected; break; } } // return result; } // // Remove ... bool RemoveSupport( ulong ticket // Specified Signal Ticket ) { // bool result = false; // result = IsSupportExists(ticket); if (!result) { return result; } // int protectedCounts = ArraySize(mSupportedSignals); result = protectedCounts > 0; if (!result) { return result; } // XProtectedSignal cleared[]; for (int i = 0; i < protectedCounts; i++) { // XProtectedSignal iProtected = mSupportedSignals[i]; // if (iProtected.ticket != ticket) { AddItemToBuffer( iProtected, cleared); } } // // Update Source by Cleared ... CopyBuffer( cleared, mSupportedSignals); // result = true; // return result; } // // Update ... bool UpdateSupport( ulong ticket, // Specified Signal Ticket datetime time, // Specified Last Checked time double profit // Specified Signal Profit ) { // bool result = false; // int protectedCounts = ArraySize(mSupportedSignals); result = protectedCounts > 0; if (!result) { return result; } // result = IsSupportExists(ticket); if (!result) { return result; } // // Retrieve Struct ... XProtectedSignal item = GetSupport(ticket); AddItemToBuffer( time, item.time); AddItemToBuffer( profit, item.profit); // result = RemoveSupport(ticket); if (!result) { return result; } // AddItemToBuffer( item, mSupportedSignals); result = true; // return result; } bool UpdateSupport( XProtectedSignal &item // Specified Protected Item ) { // bool result = false; // datetime time; result = GetLastItem( time, item.time); if (!result) { return result; } // double profit; result = GetLastItem( profit, item.profit); if (!result) { return result; } // result = UpdateSupport( item.ticket, time, profit); // return result; } bool UpdateSupport( XSignal &signal // Specified Signal ) { // bool result = false; // ulong ticket = signal.ticket; datetime time = TimeCurrent(); double profit = signal.profit; // result = UpdateSupport( ticket, time, profit); // return result; } // // Add Or Update ... bool AddOrUpdateSupport( XSignal &signal // Specified Signal ) { // bool result = false; // bool isExists = IsSupportExists(signal.ticket); if (!isExists) { result = Add(signal); } else { result = Update(signal); } // return result; } // // Check Exists ... bool IsSupportExists( ulong ticket // Specified Signal Ticket ) { // bool result = false; // // Validate Args ... if (ticket <= 0) { return result; } // int protectedCounts = ArraySize(mSupportedSignals); if (protectedCounts <= 0) { return result; } // for (int i = 0; i < protectedCounts; i++) { // XProtectedSignal iProtected = mSupportedSignals[i]; // if (iProtected.ticket == ticket) { // result = true; break; } } // return result; } // // Count Protecteds ... int CountSupports() { // int result = 0; // result = ArraySize(mSupportedSignals); // return result; } // // END Suppoprted Signals Functions ... // // // START Getter/Setter(s) ... // // int GetOldAge() { return mOldAge; } // bool SetOldAge(int value) { // bool result = false; // result = value > 0 && mOldAge != value; if (!result) { return result; } // mOldAge = value; // return result; } // ENUM_X_GUARD_ACTIONS GetOldGuardAction() { return mOldGuardAction; } // bool SetOldGuardAction(ENUM_X_GUARD_ACTIONS value) { // bool result = false; // result = value != mOldGuardAction; if (!result) { return result; } // mOldGuardAction = value; // return result; } // double GetCriticalFactor() { return mCriticalFactor; } // bool SetCriticalFactor(bool value) { // bool result = false; // result = value > 0 && value < 1 && mCriticalFactor != value; if (!result) { return result; } // mCriticalFactor = value; // double deposit = mAccountInfo.GetInitialBalance(); mCriticalValue = deposit * value; // return result; } // ENUM_X_GUARD_ACTIONS GetCriticalAction() { return mCriticalAction; } // bool SetCriticalAction(ENUM_X_GUARD_ACTIONS value) { // bool result = false; // result = value != mCriticalAction; if (!result) { return result; } // mCriticalAction = value; // return result; } // double GetMaxFactor() { return mMaxFactor; } // bool SetMaxFactor(bool value) { // bool result = false; // result = value > 0 && value < 1 && mMaxFactor != value; if (!result) { return result; } // mMaxFactor = value; // double deposit = mAccountInfo.GetInitialBalance(); mMaxValue = deposit * value; // return result; } // ENUM_X_GUARD_ACTIONS GetMaxAction() { return mMaxAction; } // bool SetMaxAction(ENUM_X_GUARD_ACTIONS value) { // bool result = false; // result = value != mMaxAction; if (!result) { return result; } // mMaxAction = value; // return result; } // ENUM_X_GUARD_SUPPORT_METHODS GetSupportMethod() { return mSupportMethod; } // bool SetSupportMethod(ENUM_X_GUARD_SUPPORT_METHODS value) { // bool result = false; // result = value != mSupportMethod; if (!result) { return result; } // mSupportMethod = value; // return result; } // // END Getter/Setter(s) ... // // // Generate Signal Guard Attacked Message ... string GenerateGuardedSignalComment( XSignal &signal, // Specified Signal ENUM_X_GUARD_REASONS reason // Specified Guard Reason ) { // string result = ""; // string reasonMessage = ( // reason == X_GUARDED_OLD ? "Because of Old Issue" : reason == X_GUARDED_CRITICAL ? "Because Of Crtical Drawdown Isuue" : reason == X_GUARDED_MAX ? "Because of Max Drawdown Issue" : "" // ) + " On Profit: " + (string)signal.profit; // result += "Guard Attacked (" + (string)signal.ticket + "), " + reasonMessage + " ..."; // return result; } // // Protected ... protected: // // Private ... private: // string mSupportPrefix; string mDirectional; string mInDirectional; // XProtectedSignal mGuardedSignals[]; XProtectedSignal mSupportedSignals[]; // int mOldAge; ENUM_X_GUARD_ACTIONS mOldGuardAction; // // Critical DrawDown Factor based On Balance ... double mCriticalFactor; double mCriticalValue; // // Guard Action for Critical State ... ENUM_X_GUARD_ACTIONS mCriticalAction; // // Max DrawDown Factor based on Balance ... double mMaxFactor; double mMaxValue; // // Guard Stopout if Max State touched ... int mOccuredconsecutiveMaxDraDownTouches; int mGuardStopoutFiredAfterTouches; // // Guard Action for Max State ... ENUM_X_GUARD_ACTIONS mMaxAction; // // How to Support Signals ... ENUM_X_GUARD_SUPPORT_METHODS mSupportMethod; // // Account Info Instance ... XCAccountInfo mAccountInfo; // // Get Volume Multiplier for Specified Guard Action ... double GetGuardActionVolumeMultiplier( ENUM_X_GUARD_ACTIONS action = X_GUARD_DO_NOTHING // Specified Action ) { // // Partial Close Max In Drawdown Trade ... double result = 0.0; if (action == X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_1) { result = 0.01; } else if (action == X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_2) { result = 0.02; } else if (action == X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_3) { result = 0.03; } else if (action == X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_5) { result = 0.05; } else if (action == X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_10) { result = 0.10; } else if (action == X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_15) { result = 0.15; } else if (action == X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_20) { result = 0.20; } else if (action == X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_25) { result = 0.25; } else if (action == X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_30) { result = 0.30; } else if (action == X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_40) { result = 0.40; } else if (action == X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_50) { result = 0.50; } else if (action == X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_60) { result = 0.60; } else if (action == X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_70) { result = 0.70; } else if (action == X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_75) { result = 0.75; } // return result; } // // Do Specified Guard Action ... bool DoGuardAction( XGuardHandlerResult &guardResult, // Hold's Result ... string &message, // Hold's Message ... XCTrade &trader, // Specified Trader Class ... ENUM_X_GUARD_ACTIONS action, // Specified Which Action to Do ... ENUM_X_GUARD_REASONS reason, // Specified Guard Reason ... ENUM_TIMEFRAMES period = NULL // Specified Time Frame for Detecting Signal Ages ... ) { // bool result = false; // message = ""; // string reasonString = reason == X_GUARDED_OLD ? "Because of Age Issue" : "Because of DD " + ( // reason == X_GUARDED_CRITICAL ? "Critical" : "Max" // ) + " Issue"; // // Validate Args ... if (action == X_GUARD_DO_NOTHING) { // message = "Max Allowed Drawdown Reached, but nothing Happens ..."; // return result; } // // Normalize Period ... if (period == NULL) { period = _Period; } // // Close All Signals ... XSignal closed[]; XSignal maxInDDSignal; // // Handle Perform Guard Action ... switch (action) { // // Close All ... case X_GUARD_CLOSE_ALL: { // trader.CloseSignals(closed); int closedCount = ArraySize(closed); result = closedCount > 0; if (!result) { break; } // message = "Closed (" + (string)closedCount + ") Trades by Guard, " + reasonString + " ..."; } break; // case X_GUARD_CLOSE_MAX_IN_DD: case X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_1: case X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_2: case X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_3: case X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_5: case X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_10: case X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_15: case X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_20: case X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_25: case X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_30: case X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_40: case X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_50: case X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_60: case X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_70: case X_GUARD_PARTIAL_CLOSE_MAX_IN_DD_75: { // // Retrieve Max In Drawdown Trade ... maxInDDSignal = trader.GetMaxInDrawdownSignal(); bool isValid = IsValid(maxInDDSignal, trader.GetMagicNumber()) && maxInDDSignal.ticket > 0; if (!isValid) { break; } // // Close Max In Drawdown Trade ... if (action == X_GUARD_CLOSE_MAX_IN_DD) { // string comment = "Signal (" + (string)maxInDDSignal.ticket + ") Closed by Guard ..."; result = trader.Close( maxInDDSignal.ticket, comment); if (result) { message = comment; } // break; } // int signalAge = 0; bool canGuard = true; bool isGuardedBefore = false; // // Do Some Additional Verifications if Guard for Olds Trades ... if (reason == X_GUARDED_OLD) { // // Retrieve Signal Age ... signalAge = trader.GetSignalAge( maxInDDSignal, period); // // Check Guarded Before Or Not ... isGuardedBefore = IsExists(maxInDDSignal.ticket); if (isGuardedBefore) { // // Now We Have to Check Signal Age growse required times to apply Guard Action again ... // First Calculate Guard Grow Step ... int ageGrowStep = mOldAge / 10; // XProtectedSignal guardItem = Get(maxInDDSignal.ticket); datetime lastGuardTime = 0; if (GetLastItem(lastGuardTime, guardItem.time)) { // int lastGuardIndex = iBarShift( maxInDDSignal.symbol, period, lastGuardTime); // canGuard = MathAbs(lastGuardIndex) >= ageGrowStep; } } else { // // Check Signal age ... canGuard = signalAge >= mOldAge; } } // // Prevent Moving Forward ... if (!canGuard) { // result = false; break; } // // Partial Close Max In Drawdown Trade ... double volumeRate = GetGuardActionVolumeMultiplier(action); // double volume = NormalizeVolume( maxInDDSignal.volume * volumeRate, maxInDDSignal.symbol); // string commentPrefix = "Signal (" + (string)maxInDDSignal.ticket + ") Partial Closed (" + (string)volumeRate + ") by Guard"; string comment = commentPrefix + " ..."; // result = trader.ClosePartial( maxInDDSignal.ticket, volume, comment); if (result) { // reasonString = reasonString + (reason == X_GUARDED_OLD ? " (" + (string)signalAge + ")" : " (" + (string)maxInDDSignal.profit + ")"); // // Update Guarded Signals ... if (isGuardedBefore) { // XSignal tSignal = trader.GetSignal(maxInDDSignal.ticket); // if (tSignal.ticket > 0 && tSignal.volume > 0) { // // Update In Guardeds ... Update(tSignal); } else { // // Remove From Guardeds ... Remove(tSignal.ticket); } } else if (reason == X_GUARDED_OLD) { // // Added to Guardeds ... Add(maxInDDSignal); } // message = commentPrefix + reasonString + " ..."; } } break; // // Nothing ... // Default ... default: message = "Max Allowed Drawdown Reached ..."; break; } // result = StringLen(message) > 0; if (!result) { return result; } // if (result) { // if (reason == X_GUARDED_OLD) { // int closedCount = ArraySize(closed); if (closedCount > 0) { // for (int i = 0; i < closedCount; i++) { AddItemToBuffer( closed[i], guardResult.olds); } } // if (maxInDDSignal.ticket > 0) { AddItemToBuffer( maxInDDSignal, guardResult.olds); } } else if (reason == X_GUARDED_CRITICAL) { // int closedCount = ArraySize(closed); if (closedCount > 0) { // for (int i = 0; i < closedCount; i++) { AddItemToBuffer( closed[i], guardResult.criticals); } } // if (maxInDDSignal.ticket > 0) { AddItemToBuffer( maxInDDSignal, guardResult.criticals); } } else if (reason == X_GUARDED_MAX) { // int closedCount = ArraySize(closed); if (closedCount > 0) { // for (int i = 0; i < closedCount; i++) { AddItemToBuffer( closed[i], guardResult.maxes); } } // if (maxInDDSignal.ticket > 0) { AddItemToBuffer( maxInDDSignal, guardResult.maxes); } } } // return result; } }; // // END Global Definitions: Variables, Properties and etc ... //