6321 lines
143 KiB
Plaintext
6321 lines
143 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";
|
|
|
|
//
|
|
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[];
|
|
};
|
|
|
|
//
|
|
// 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,
|
|
};
|
|
|
|
//
|
|
// END Model Definitions ...
|
|
//
|
|
|
|
//
|
|
// START Overrides ...
|
|
//
|
|
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 ...
|
|
//
|
|
|
|
//
|
|
// XCMD5 a library for Hashing ...
|
|
class XCMD5
|
|
{
|
|
//
|
|
// 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 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 Provided ...
|
|
public:
|
|
//
|
|
// Constructro ...
|
|
void XCReporter()
|
|
{
|
|
//
|
|
mAccountInfo = new XCAccountInfo();
|
|
|
|
//
|
|
ResetReports();
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCReporter()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Reset Specific Report ...
|
|
void ResetReport(
|
|
ENUM_XREPORT_TYPES type // Specify Report Type
|
|
)
|
|
{
|
|
CleanReport(type);
|
|
}
|
|
|
|
//
|
|
// Reset All Reports ...
|
|
void ResetReports()
|
|
{
|
|
//
|
|
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 ...
|
|
Add(
|
|
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;
|
|
}
|
|
|
|
//
|
|
// Add New SignallerInfo to List ...
|
|
void Add(
|
|
XSignallerInfo &item,
|
|
XSignallerInfo &buffer[])
|
|
{
|
|
//
|
|
ArrayResize(
|
|
buffer,
|
|
ArraySize(buffer) + 1);
|
|
|
|
//
|
|
buffer[ArraySize(buffer) - 1] = item;
|
|
}
|
|
|
|
//
|
|
// Clean Signaller Info Buffer ...
|
|
void CleanBuffer(XSignallerInfo &buffer[])
|
|
{
|
|
//
|
|
ArrayFree(buffer);
|
|
ArrayResize(buffer, 0);
|
|
}
|
|
|
|
//
|
|
// Copy Signaller Info ...
|
|
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];
|
|
|
|
//
|
|
Add(
|
|
iInfo,
|
|
dest);
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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 Managing Signals Additional Data ...
|
|
class XCSignalManager
|
|
{
|
|
//
|
|
// Public ...
|
|
public:
|
|
//
|
|
// Constructor ...
|
|
XCSignalManager(void)
|
|
{
|
|
CleanData();
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
~XCSignalManager(void) {}
|
|
|
|
//
|
|
// 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 ...
|
|
void Remove(
|
|
ulong ticket // Specified Signal Ticket
|
|
)
|
|
{
|
|
//
|
|
// Check Signal Exists ...
|
|
bool isExists = IsExists(ticket);
|
|
if (!isExists)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int signalsCount = ArraySize(mSignals);
|
|
if (signalsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
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);
|
|
}
|
|
void Remove(
|
|
XSignal &signal // Specified Signal
|
|
)
|
|
{
|
|
//
|
|
// Check Signal Exists ...
|
|
bool isExists = IsExists(signal);
|
|
if (!isExists)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int signalsCount = ArraySize(mSignals);
|
|
if (signalsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
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);
|
|
}
|
|
|
|
//
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
//
|
|
void AddItemToBuffer(
|
|
XSignal &item,
|
|
XSignal &buffer[])
|
|
{
|
|
//
|
|
ArrayResize(
|
|
buffer,
|
|
ArraySize(buffer) + 1);
|
|
|
|
//
|
|
buffer[ArraySize(buffer) - 1] = item;
|
|
}
|
|
};
|
|
|
|
//
|
|
// START Global Definitions: Variables, Properties and etc ...
|
|
//
|
|
//
|
|
// XSaherElm Trade Class ...
|
|
class XCTrade
|
|
{
|
|
//
|
|
// 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
|
|
int maxAllowedTrades, // Specify Max Allowed Trades
|
|
double minBallanceForOpenTrades, // Specify Minimum Balance for Open Trades
|
|
double minAllowedFreeMarginForOpenTrades // Specify Minimum Free Marging for Open Trades
|
|
)
|
|
{
|
|
//
|
|
mTag = tag;
|
|
mSymbol = symbol;
|
|
mSlippage = slippage;
|
|
mMagicNumber = magicNumber;
|
|
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();
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCTrade()
|
|
{
|
|
}
|
|
|
|
//
|
|
// START Configuring Class Functions ...
|
|
//
|
|
|
|
//
|
|
// Update Min Balance For Trading ...
|
|
bool SetMinBalanceForTradingPrice(
|
|
double price // Specified Price for use as Min Account Balance for Trading
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Arg ...
|
|
result = price > mMinBallanceForOpenTrades;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
mMinBallanceForOpenTrades = price;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// 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 ignoreTPSL = false, // Ignore Signal TP and SL for Virtal Handling
|
|
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,
|
|
ignoreTPSL
|
|
? 0
|
|
: signal.sl,
|
|
ignoreTPSL
|
|
? 0
|
|
: signal.tp,
|
|
signal.comment)
|
|
: signal.type == X_SIGNAL_SHORT
|
|
? Sell(
|
|
signal.volume,
|
|
signal.entry,
|
|
ignoreTPSL
|
|
? 0
|
|
: signal.sl,
|
|
ignoreTPSL
|
|
? 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 ...
|
|
void HandleSignals(
|
|
XTraderHandlerResult &result, // Holds Result
|
|
bool ignoreTPSL = true, // Ignore Signal TP and SL for Virtal Handling
|
|
bool ignoreRiskFree = false // Ignore Risk Free Trdaes
|
|
)
|
|
{
|
|
//
|
|
// Cleanup Result ...
|
|
CleanBuffer(result.sl);
|
|
CleanBuffer(result.tp);
|
|
CleanBuffer(result.rf);
|
|
|
|
//
|
|
// Reading Open Positions ...
|
|
XSignal signals[];
|
|
GetSignals(signals);
|
|
int signalsCount = ArraySize(signals);
|
|
if (signalsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
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 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;
|
|
|
|
//
|
|
// Handle SL ...
|
|
if (
|
|
//
|
|
!ignoreTPSL
|
|
//
|
|
&&
|
|
//
|
|
iSignal.sl > 0
|
|
//
|
|
&&
|
|
//
|
|
exit <= appliedSLPrice
|
|
//
|
|
)
|
|
{
|
|
//
|
|
string comment = GenerateSignalSLComment(iSignal);
|
|
|
|
//
|
|
bool isClosed = Close(
|
|
iSignal.ticket,
|
|
comment);
|
|
if (isClosed)
|
|
{
|
|
Add(
|
|
iSignal,
|
|
result.sl);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle TP ...
|
|
if (
|
|
//
|
|
!ignoreTPSL
|
|
//
|
|
&&
|
|
//
|
|
iSignal.tp > 0
|
|
//
|
|
&&
|
|
//
|
|
exit >= appliedTPPrice
|
|
//
|
|
)
|
|
{
|
|
//
|
|
string comment = GenerateSignalTPComment(iSignal);
|
|
|
|
//
|
|
bool isClosed = Close(
|
|
iSignal.ticket,
|
|
comment);
|
|
if (isClosed)
|
|
{
|
|
Add(
|
|
iSignal,
|
|
result.tp);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle Risk Free ...
|
|
if (
|
|
//
|
|
!ignoreRiskFree
|
|
//
|
|
&&
|
|
//
|
|
iSignal.riskFreeStep > 0
|
|
//
|
|
&&
|
|
//
|
|
iSignal.riskFreeRate > 0
|
|
//
|
|
)
|
|
{
|
|
//
|
|
// Base Price is ENTRY, then Last Level, in each level SL is Last Level ...
|
|
int level = 1;
|
|
double stepPrice = PipsToPrice(iSignal.riskFreeStep);
|
|
double basePrice =
|
|
isLong
|
|
? iSignal.sl != 0 && iSignal.sl > iSignal.entry ? iSignal.sl : iSignal.entry
|
|
: iSignal.sl != 0 && iSignal.sl < iSignal.entry ? iSignal.sl
|
|
: iSignal.entry;
|
|
double priceLevel = MathAbs(exit - basePrice) / stepPrice;
|
|
|
|
//
|
|
if (priceLevel > 1)
|
|
{
|
|
//
|
|
while (priceLevel > level && priceLevel > level + 1)
|
|
{
|
|
level++;
|
|
}
|
|
|
|
//
|
|
double baseRiskFreeLevelExitPrice = (level * stepPrice);
|
|
double riskFreeLevelExitPrice =
|
|
isLong
|
|
? (basePrice + baseRiskFreeLevelExitPrice) - deviation
|
|
: (basePrice - baseRiskFreeLevelExitPrice) + deviation;
|
|
|
|
//
|
|
bool canRiskFree =
|
|
isLong
|
|
? exit >= riskFreeLevelExitPrice
|
|
: exit <= riskFreeLevelExitPrice;
|
|
|
|
//
|
|
if (canRiskFree)
|
|
{
|
|
//
|
|
double volume = iSignal.volume;
|
|
double riskFreeRate = iSignal.riskFreeRate;
|
|
double riskFreeVolume = riskFreeRate * volume;
|
|
riskFreeVolume = NormalizeVolume(riskFreeVolume);
|
|
|
|
//
|
|
double entry = GetEntry(
|
|
iSignal.symbol,
|
|
iSignal.type);
|
|
double exit = GetExit(
|
|
iSignal.symbol,
|
|
iSignal.type);
|
|
double spread = GetSpread(iSignal.symbol);
|
|
long stopLevels = SymbolInfoInteger(
|
|
iSignal.symbol,
|
|
SYMBOL_TRADE_STOPS_LEVEL) +
|
|
SymbolInfoInteger(iSignal.symbol, SYMBOL_SPREAD);
|
|
double slDistance = spread * 2;
|
|
|
|
//
|
|
double sl =
|
|
isLong
|
|
? iSignal.tp - slDistance
|
|
: iSignal.tp + slDistance;
|
|
sl = NormalizePrice(sl, iSignal.symbol);
|
|
|
|
//
|
|
double tp =
|
|
isLong
|
|
? iSignal.tp + stepPrice
|
|
: iSignal.tp - stepPrice;
|
|
tp = NormalizePrice(tp, iSignal.symbol);
|
|
|
|
//
|
|
string comment = GenerateSignalRFComment(iSignal, (int)level);
|
|
|
|
//
|
|
ResetLastError();
|
|
|
|
//
|
|
bool isClosedPartial = ClosePartial(
|
|
iSignal.ticket,
|
|
riskFreeVolume,
|
|
comment);
|
|
|
|
//
|
|
if (isClosedPartial)
|
|
{
|
|
// //
|
|
// bool isModified = Modify(
|
|
// iSignal.ticket,
|
|
// 0,
|
|
// tp);
|
|
|
|
//
|
|
// if (isModified)
|
|
// {
|
|
//
|
|
Add(
|
|
iSignal,
|
|
result.rf);
|
|
|
|
//
|
|
AddOrUpdateSignalInfo(iSignal);
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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);
|
|
|
|
//
|
|
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)
|
|
{
|
|
RemoveSignal(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);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// END Actions ...
|
|
//
|
|
|
|
//
|
|
// START Account Related ...
|
|
//
|
|
|
|
//
|
|
// Check Account Has Minimum Balance For Trade ...
|
|
bool IsBalanceReadyForTrade()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = mAccountInfo.GetBalance() >= mMinBallanceForOpenTrades;
|
|
|
|
//
|
|
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 ...
|
|
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;
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
//
|
|
// 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 = GetExit(signal.symbol, signal.type);
|
|
|
|
//
|
|
result =
|
|
//
|
|
X_SIGNAL_RISKFREE_STEP + "(" + (string)signal.ticket + ")_" + (string)level + ": " + 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 = GetExit(signal.symbol, signal.type);
|
|
|
|
//
|
|
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 = GetExit(signal.symbol, signal.type);
|
|
|
|
//
|
|
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;
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
//
|
|
// Convert an string to signal ...
|
|
XSignal FromString(
|
|
string represent // String Represenation of a Signal
|
|
)
|
|
{
|
|
//
|
|
XSignal result = {};
|
|
|
|
//
|
|
// Validate Arg ...
|
|
if (StringLen(represent) == 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// TICKET ...
|
|
string ticketStr = ExtractString(
|
|
represent,
|
|
X_SIGNAL_TICKET + "(",
|
|
")");
|
|
if (StringLen(ticketStr) > 0)
|
|
{
|
|
result.ticket = (ulong)ticketStr;
|
|
}
|
|
|
|
//
|
|
// TYPE ...
|
|
string typeStr = ExtractString(
|
|
represent,
|
|
"_" + X_SIGNAL_TYPE + "(",
|
|
")");
|
|
if (StringLen(typeStr) > 0)
|
|
{
|
|
//
|
|
ENUM_X_SIGNAL_TYPE type = GetSignalType(typeStr);
|
|
result.type = type;
|
|
}
|
|
|
|
//
|
|
// TP ...
|
|
string tpStr = ExtractString(
|
|
represent,
|
|
"_" + X_SIGNAL_TP + "(",
|
|
")");
|
|
if (StringLen(tpStr) > 0)
|
|
{
|
|
//
|
|
double tp = (double)tpStr;
|
|
result.tp = tp;
|
|
}
|
|
|
|
//
|
|
// SL ...
|
|
string slStr = ExtractString(
|
|
represent,
|
|
"_" + X_SIGNAL_SL + "(",
|
|
")");
|
|
if (StringLen(slStr) > 0)
|
|
{
|
|
//
|
|
double sl = (double)slStr;
|
|
result.sl = sl;
|
|
}
|
|
|
|
//
|
|
// RFS ...
|
|
string rfsStr = ExtractString(
|
|
represent,
|
|
"_" + X_SIGNAL_RISKFREE_STEP + "(",
|
|
")");
|
|
if (StringLen(rfsStr) > 0)
|
|
{
|
|
//
|
|
double rfs = (double)rfsStr;
|
|
result.riskFreeStep = rfs;
|
|
}
|
|
|
|
//
|
|
// RFR ...
|
|
string rfrStr = ExtractString(
|
|
represent,
|
|
"_" + X_SIGNAL_RISKFREE_RATE + "(",
|
|
")");
|
|
if (StringLen(rfrStr) > 0)
|
|
{
|
|
//
|
|
double rfr = (double)rfrStr;
|
|
result.riskFreeRate = rfr;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
void FromString(
|
|
XSignal &result, // Holds Result
|
|
string represent // String Represenation of a Signal
|
|
)
|
|
{
|
|
//
|
|
// Validate Arg ...
|
|
if (StringLen(represent) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
XSignal fs = FromString(represent);
|
|
|
|
//
|
|
// Fillisg Result by Retrieved Values ...
|
|
result.tp = fs.tp;
|
|
result.sl = fs.sl;
|
|
result.type = fs.type;
|
|
result.ticket = fs.ticket;
|
|
result.riskFreeStep = fs.riskFreeStep;
|
|
result.riskFreeRate = fs.riskFreeRate;
|
|
}
|
|
|
|
//
|
|
// 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 ...
|
|
//
|
|
|
|
//
|
|
// 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;
|
|
|
|
//
|
|
// 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 Signal Private ...
|
|
//
|
|
|
|
//
|
|
// Add Or Update Signal ...
|
|
void AddOrUpdateSignalInfo(
|
|
XSignal &signal // Specified Signal
|
|
)
|
|
{
|
|
// //
|
|
// bool isExists = mSignalManager.IsExists(signal);
|
|
// if (!isExists)
|
|
// {
|
|
// //
|
|
// color longColor = clrAqua;
|
|
// color shortColor = clrFuchsia;
|
|
|
|
// //
|
|
// DrawSignalShape(
|
|
// signal,
|
|
// longColor,
|
|
// shortColor);
|
|
// }
|
|
|
|
// //
|
|
// bool isAddOrUpdated = mSignalManager.AddOrUpdate(signal);
|
|
|
|
//
|
|
string name = GenerateSignalEventObjectName(signal);
|
|
|
|
//
|
|
bool isExists = IsDrawExists(name);
|
|
if (isExists)
|
|
{
|
|
RemoveSignal(signal.ticket);
|
|
}
|
|
|
|
//
|
|
DrawSignalEvent(signal);
|
|
}
|
|
|
|
//
|
|
// Retrieve Signal String From Chart Event ...
|
|
string RetrieveSignalContent(
|
|
ulong ticket, // Specify Position Ticket
|
|
int chartId = -1, // Specify Chart ID
|
|
int subWindow = -1 // Specify SubWindow ID
|
|
)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
// Normalize Chart and SubWindow ID ...
|
|
if (chartId == -1)
|
|
{
|
|
chartId = 0;
|
|
}
|
|
if (subWindow == -1)
|
|
{
|
|
subWindow = 0;
|
|
}
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (ticket <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Signal Event Name ...
|
|
string sObjName = GenerateSignalEventObjectName(ticket);
|
|
if (StringLen(sObjName) == 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Signal Event Exists ...
|
|
bool isExists = IsDrawExists(sObjName);
|
|
if (!isExists)
|
|
{
|
|
return result;
|
|
}
|
|
//
|
|
// Loop Through Objects ...
|
|
int count = ObjectsTotal(
|
|
chartId,
|
|
subWindow);
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
// Retrieve Object Name ...
|
|
string objectName = ObjectName(chartId, i, subWindow);
|
|
|
|
//
|
|
// Find Signal Ticket Position in Object Name ...
|
|
int stPos = StringFind(
|
|
objectName,
|
|
sObjName);
|
|
if (stPos < 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Retrieve Object Type and Check it Event ...
|
|
int oType = (int)ObjectGetInteger(chartId, objectName, OBJPROP_TYPE);
|
|
if (oType != OBJ_EVENT)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Retrieve Object Text as String Representation OF Signal ...
|
|
result = ObjectGetString(chartId, objectName, OBJPROP_TEXT);
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
XSignal RetrieveSignal(
|
|
ulong ticket // Specify Position Ticket
|
|
)
|
|
{
|
|
//
|
|
XSignal result = {};
|
|
|
|
//
|
|
if (ticket <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string signalContent = RetrieveSignalContent(ticket);
|
|
result = FromString(
|
|
signalContent);
|
|
|
|
//
|
|
// 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;
|
|
|
|
//
|
|
string signalContent = RetrieveSignalContent(signal.ticket);
|
|
|
|
//
|
|
FromString(
|
|
signal,
|
|
signalContent);
|
|
}
|
|
|
|
//
|
|
// Draw a Signal on Screen ...
|
|
void DrawSignalEvent(
|
|
XSignal &signal, // Specify Draw which Signal on Screen
|
|
color longColor = clrAqua, // Long Signal Object Color
|
|
color shortColor = clrFuchsia, // Short Signal Object Color
|
|
int chartId = -1, // Specify Chart ID
|
|
int subWindow = -1 // Specify SubWindow ID
|
|
)
|
|
{
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
signal.ticket <= 0 ||
|
|
!IsValid(signal, mMagicNumber) ||
|
|
signal.type == X_SIGNAL_UNKNOWN)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Normalize Chart and SubWindow ID ...
|
|
if (chartId == -1)
|
|
{
|
|
chartId = 0;
|
|
}
|
|
if (subWindow == -1)
|
|
{
|
|
subWindow = 0;
|
|
}
|
|
|
|
//
|
|
bool isLong = signal.type == X_SIGNAL_LONG;
|
|
|
|
//
|
|
// Simply Draw an Arrow on Chart for Representing Signal Info ...
|
|
string name = GenerateSignalEventObjectName(signal);
|
|
string content = ToString(signal);
|
|
if (StringLen(content) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
color signalColor = isLong ? longColor : shortColor;
|
|
|
|
//
|
|
// Create an Event On Chart ...
|
|
bool isCreated = EventCreate(
|
|
chartId,
|
|
name,
|
|
subWindow,
|
|
content,
|
|
signal.time,
|
|
signalColor);
|
|
if (isCreated)
|
|
{
|
|
//
|
|
DrawSignalShape(
|
|
signal,
|
|
longColor,
|
|
shortColor);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Remove Signal Object from Chart ...
|
|
bool RemoveSignal(
|
|
ulong ticket, // Specify Position Ticket
|
|
int chartId = -1 // Specify Chart ID
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Arg ...
|
|
if (ticket <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Normalize Chart Id ...
|
|
if (chartId <= 0)
|
|
{
|
|
chartId = 0;
|
|
}
|
|
|
|
//
|
|
// Generate Signal Object Name ...
|
|
string signalObjectName = GenerateSignalEventObjectName(ticket);
|
|
|
|
//
|
|
// Remove Object from Chart ...
|
|
result = RemoveDraw(signalObjectName);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool RemoveSignal(
|
|
XSignal &signal, // Specify Signal
|
|
int chartId = -1 // Specify Chart ID
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = RemoveSignal(
|
|
signal.ticket,
|
|
chartId);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts a Position to Signal ...
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
//
|
|
string signalContent = RetrieveSignalContent(ticket);
|
|
if (StringLen(signalContent) > 0)
|
|
{
|
|
//
|
|
// Fill Additional Contents ...
|
|
FromString(
|
|
result,
|
|
signalContent);
|
|
}
|
|
|
|
//
|
|
// 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 ...
|
|
//
|
|
};
|
|
|
|
//
|
|
// END Global Definitions: Variables, Properties and etc ...
|
|
//
|