Files
MQL5Data/BKP/Main/Classes/x-saherelm.class.lib.mq5
T
2024-02-02 01:32:20 +03:30

10317 lines
230 KiB
Plaintext

///////////////////////////////////////////////////////
//
// 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 <Trade/Trade.mqh>
#include <Trade/DealInfo.mqh>
#include <Trade/OrderInfo.mqh>
#include <Trade/AccountInfo.mqh>
#include <Trade/PositionInfo.mqh>
#include <Trade/HistoryOrderInfo.mqh>
//
#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 ...
//