6551 lines
127 KiB
Plaintext
6551 lines
127 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Seriallize Library
|
|
// ---------------------------------------
|
|
// Name: XTradeLib
|
|
// Description: All models related to Trade ...
|
|
//
|
|
//
|
|
// Maintainer:
|
|
// ------------
|
|
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// Global Properties ...
|
|
#property library
|
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
|
#property link "https://www.saherelm.ir"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
//
|
|
// Imports ...
|
|
#include "../Libraries/x-saherelm.common.lib.mq5"
|
|
#include "../Libraries/x-saherelm.x-guard.lib.mq5"
|
|
#include <Trade/Trade.mqh>
|
|
|
|
//
|
|
// Definitions ...
|
|
|
|
//
|
|
// a List of Used Tokens ...
|
|
|
|
//
|
|
// Common ...
|
|
string XIDToken = "ID";
|
|
string XTicketToken = "TK";
|
|
string XModeToken = "MD";
|
|
string XTypeToken = "TY";
|
|
string XPeriodToken = "PR";
|
|
string XProviderToken = "PRV";
|
|
string XProfitToken = "PF";
|
|
|
|
//
|
|
string XTPToken = "TP";
|
|
string XSLToken = "SL";
|
|
string XTimeToken = "TM";
|
|
string XEntryToken = "EN";
|
|
string XVolumeToken = "VL";
|
|
string XSymbolToken = "SMBL";
|
|
|
|
//
|
|
string XSupportToken = "SP";
|
|
string XEQMSupportToken = "EQM";
|
|
string XEQPToken = "EQP";
|
|
|
|
//
|
|
string XSLTrailToken = "SLT";
|
|
|
|
//
|
|
string XActionToken = "A";
|
|
|
|
//
|
|
string XDirectionalToken = "D";
|
|
string XINDirectionalToken = "IND";
|
|
|
|
//
|
|
string XRecoveryToken = "XRCV";
|
|
|
|
//
|
|
// Available Order Modes ...
|
|
enum ENUM_X_ORDER_MODES
|
|
{
|
|
X_ORDER_MODE_NOTHING, // Nothing
|
|
X_ORDER_MODE_MARKET, // Market Order
|
|
X_ORDER_MODE_STOP, // Pending Stop Order
|
|
X_ORDER_MODE_LIMIT, // Pending Limit Order
|
|
X_ORDER_MODE_STOP_LIMIT, // Pending Stop Limit Order
|
|
};
|
|
|
|
//
|
|
string ToString(ENUM_X_ORDER_MODES value)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
switch (value)
|
|
{
|
|
//
|
|
case X_ORDER_MODE_MARKET:
|
|
result = "Market";
|
|
break;
|
|
|
|
//
|
|
case X_ORDER_MODE_LIMIT:
|
|
result = "Limit";
|
|
break;
|
|
|
|
//
|
|
case X_ORDER_MODE_STOP:
|
|
result = "Stop";
|
|
break;
|
|
|
|
//
|
|
case X_ORDER_MODE_STOP_LIMIT:
|
|
result = "StopLimit";
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Select Positions Type ...
|
|
enum ENUM_X_POSITION_SELECT_METHODS
|
|
{
|
|
X_POSITION_SELECT_NONE, // None
|
|
X_POSITION_SELECT_MAX, // Max
|
|
X_POSITION_SELECT_MIN, // Min
|
|
X_POSITION_SELECT_BOTH, // Min and Max
|
|
X_POSITION_SELECT_ALL, // All
|
|
};
|
|
|
|
//
|
|
// Signal Execution Result ...
|
|
// note that some of them must be handles in
|
|
// EA's ...
|
|
enum ENUM_X_SIGNAL_EXECUTION_RESULT
|
|
{
|
|
//
|
|
X_SIGNAL_EXECUTION_UNKNOWN, // Unknown
|
|
X_SIGNAL_EXECUTION_SUCCEED, // Succed
|
|
X_SIGNAL_EXECUTION_FAILED_SPREAD, // Spread more than Max Allowed
|
|
X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED, // Not Allowed Trade Type
|
|
X_SIGNAL_EXECUTION_FAILED_NO_EQUITY, // No Equity for Trade
|
|
X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR, // Price Error
|
|
X_SIGNAL_EXECUTION_FAILED_PREV_PROFIT_ERROR, // Prev Profit Error
|
|
X_SIGNAL_EXECUTION_FAILED_MAX_REACHED, // Max Allowed Positions Reached
|
|
X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED, // Same Positions Delay Not Passed
|
|
X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS, // Invalid Params
|
|
};
|
|
|
|
//
|
|
enum ENUM_X_POSITION_TYPES
|
|
{
|
|
X_POSITION_TYPE_NONE = 0,
|
|
X_POSITION_TYPE_ALL = 1,
|
|
X_POSITION_TYPE_LONG = 2,
|
|
X_POSITION_TYPE_SHORT = 3,
|
|
};
|
|
|
|
//
|
|
bool IsValid(ENUM_X_POSITION_TYPES value)
|
|
{
|
|
return value != X_POSITION_TYPE_NONE;
|
|
}
|
|
|
|
//
|
|
bool HasSpecifiedType(ENUM_X_POSITION_TYPES value)
|
|
{
|
|
//
|
|
return value == X_POSITION_TYPE_LONG ||
|
|
value == X_POSITION_TYPE_SHORT;
|
|
}
|
|
|
|
//
|
|
string ToString(ENUM_X_POSITION_TYPES value)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
switch (value)
|
|
{
|
|
//
|
|
case X_POSITION_TYPE_ALL:
|
|
result = "All";
|
|
break;
|
|
|
|
//
|
|
case X_POSITION_TYPE_NONE:
|
|
result = "NONE";
|
|
break;
|
|
|
|
//
|
|
case X_POSITION_TYPE_SHORT:
|
|
result = "Short";
|
|
break;
|
|
|
|
//
|
|
case X_POSITION_TYPE_LONG:
|
|
result = "Long";
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
string ToXString(ENUM_X_POSITION_TYPES value)
|
|
{
|
|
return ToString(value);
|
|
}
|
|
|
|
//
|
|
bool IsLong(ENUM_X_POSITION_TYPES value)
|
|
{
|
|
return value == X_POSITION_TYPE_LONG;
|
|
}
|
|
|
|
//
|
|
bool IsShort(ENUM_X_POSITION_TYPES value)
|
|
{
|
|
return value == X_POSITION_TYPE_SHORT;
|
|
}
|
|
|
|
//
|
|
bool ToPositionType(
|
|
ENUM_POSITION_TYPE &dest,
|
|
ENUM_X_POSITION_TYPES source //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = source == X_POSITION_TYPE_LONG ||
|
|
source == X_POSITION_TYPE_SHORT;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
dest =
|
|
source == X_POSITION_TYPE_LONG
|
|
? POSITION_TYPE_BUY
|
|
: POSITION_TYPE_SELL;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_X_POSITION_TYPES ToPositionType(ENUM_POSITION_TYPE value)
|
|
{
|
|
return IsLong(value)
|
|
? X_POSITION_TYPE_LONG
|
|
: X_POSITION_TYPE_SHORT;
|
|
}
|
|
|
|
//
|
|
ENUM_X_POSITION_TYPES OppositPositionType(ENUM_POSITION_TYPE type)
|
|
{
|
|
//
|
|
ENUM_X_POSITION_TYPES result = X_POSITION_TYPE_NONE;
|
|
|
|
//
|
|
bool isLong = IsLong(type);
|
|
bool isShort = IsShort(type);
|
|
|
|
//
|
|
result =
|
|
//
|
|
isLong
|
|
? X_POSITION_TYPE_SHORT
|
|
: isShort
|
|
? X_POSITION_TYPE_LONG
|
|
: X_POSITION_TYPE_NONE
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_X_DIRECTION ToDirection(ENUM_POSITION_TYPE value)
|
|
{
|
|
//
|
|
ENUM_X_DIRECTION result = X_DIRECTION_NONE;
|
|
|
|
//
|
|
result = IsLong(value)
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_X_DIRECTION ToDirection(ENUM_X_POSITION_TYPES value)
|
|
{
|
|
//
|
|
ENUM_X_DIRECTION result = X_DIRECTION_NONE;
|
|
|
|
//
|
|
result = value == X_POSITION_TYPE_ALL
|
|
? X_DIRECTION_ALL
|
|
: value == X_POSITION_TYPE_LONG
|
|
? X_DIRECTION_BULLISH
|
|
: value == X_POSITION_TYPE_SHORT
|
|
? X_DIRECTION_BEARISH
|
|
: X_DIRECTION_NONE;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// All Awailable Trade Restrictions ...
|
|
enum ENUM_XTRADE_RESTRICTION_PERIOD
|
|
{
|
|
XTRADE_RESTRICATION_NONE, // None
|
|
XTRADE_RESTRICATION_HOURLY, // Per Hour
|
|
XTRADE_RESTRICATION_DAILY, // Per Day
|
|
XTRADE_RESTRICATION_WEEKLY, // Per Week
|
|
XTRADE_RESTRICATION_MONTHLY, // Per Month
|
|
};
|
|
|
|
//
|
|
string ToXString(ENUM_XTRADE_RESTRICTION_PERIOD value)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
result = EnumToString(value);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_XTRADE_RESTRICTION_PERIOD ToXRestrictionPeriod(string value)
|
|
{
|
|
//
|
|
ENUM_XTRADE_RESTRICTION_PERIOD result = XTRADE_RESTRICATION_NONE;
|
|
|
|
//
|
|
if (!IsSpecifiedValid(value))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// None ...
|
|
if (value == ToXString(XTRADE_RESTRICATION_NONE))
|
|
{
|
|
result = XTRADE_RESTRICATION_NONE;
|
|
}
|
|
//
|
|
// Per Hour ...
|
|
else if (value == ToXString(XTRADE_RESTRICATION_HOURLY))
|
|
{
|
|
result = XTRADE_RESTRICATION_HOURLY;
|
|
}
|
|
//
|
|
// Per Day ...
|
|
else if (value == ToXString(XTRADE_RESTRICATION_DAILY))
|
|
{
|
|
result = XTRADE_RESTRICATION_DAILY;
|
|
}
|
|
//
|
|
// Per Week ...
|
|
else if (value == ToXString(XTRADE_RESTRICATION_WEEKLY))
|
|
{
|
|
result = XTRADE_RESTRICATION_WEEKLY;
|
|
}
|
|
//
|
|
// Per Month ...
|
|
else if (value == ToXString(XTRADE_RESTRICATION_MONTHLY))
|
|
{
|
|
result = XTRADE_RESTRICATION_MONTHLY;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetXRestrictionsPeriodSeconds(ENUM_XTRADE_RESTRICTION_PERIOD value)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!HasRestrictions(value))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
switch (value)
|
|
{
|
|
//
|
|
// None ...
|
|
case XTRADE_RESTRICATION_NONE:
|
|
result = 0;
|
|
break;
|
|
|
|
//
|
|
// Hour ...
|
|
case XTRADE_RESTRICATION_HOURLY:
|
|
result = PeriodSeconds(PERIOD_H1);
|
|
break;
|
|
|
|
//
|
|
// Dayly ...
|
|
case XTRADE_RESTRICATION_DAILY:
|
|
result = PeriodSeconds(PERIOD_D1);
|
|
break;
|
|
|
|
//
|
|
// Weekly ...
|
|
case XTRADE_RESTRICATION_WEEKLY:
|
|
result = PeriodSeconds(PERIOD_W1);
|
|
break;
|
|
|
|
//
|
|
// Monthly ...
|
|
case XTRADE_RESTRICATION_MONTHLY:
|
|
result = PeriodSeconds(PERIOD_M1);
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check a Value Has Trade Restrictions or not ...
|
|
*
|
|
* @param value: ENUM_XTRADE_RESTRICTION_PERIOD
|
|
* ّ
|
|
* @return ( bool )
|
|
*/
|
|
bool HasRestrictions(ENUM_XTRADE_RESTRICTION_PERIOD value)
|
|
{
|
|
return value != XTRADE_RESTRICATION_NONE;
|
|
}
|
|
|
|
//
|
|
// All Awailable Trade Finalizations ...
|
|
enum ENUM_XTRADE_FINALIZATION
|
|
{
|
|
XTRADE_FINAL_NONE, // None
|
|
XTRADE_FINAL_TP, // TP
|
|
XTRADE_FINAL_SL, // SL
|
|
XTRADE_FINAL_CLOSE_IN_PROFIT, // Profit
|
|
XTRADE_FINAL_CLOSE_IN_LOSE, // Lost
|
|
};
|
|
|
|
//
|
|
string ToXString(ENUM_XTRADE_FINALIZATION value)
|
|
{
|
|
return EnumToString(value);
|
|
}
|
|
|
|
//
|
|
// Position Selecting Methods ...
|
|
enum ENUM_XPOSITION_SELECT_TYPES
|
|
{
|
|
XPOSITION_SELECT_NONE = 0, // None
|
|
XPOSITION_SELECT_ALL = 1, // All
|
|
XPOSITION_SELECT_IN_PROFITS = 2, // In Profit Positions
|
|
XPOSITION_SELECT_IN_DRAWDOWNS = 3, // In Drawdown Positions
|
|
XPOSITION_SELECT_OLDEST = 4, // Oldest Position
|
|
XPOSITION_SELECT_YOUNGEST = 5, // Youngest Position
|
|
XPOSITION_SELECT_IN_PROFITS_OLDEST = 6, // In Profit Positions Oldest one
|
|
XPOSITION_SELECT_IN_PROFITS_YOUNGEST = 7, // In Profit Positions Youngest one
|
|
XPOSITION_SELECT_IN_PROFITS_MIN = 8, // Minimum Profitable Position
|
|
XPOSITION_SELECT_IN_PROFITS_MAX = 9, // Maximum Profitable Position
|
|
XPOSITION_SELECT_IN_DRAWDOWN_OLDEST = 10, // In Drawdown Positions Oldest one
|
|
XPOSITION_SELECT_IN_DRAWDOWN_YOUNGEST = 11, // In Drawdown Positions Youngest one
|
|
XPOSITION_SELECT_IN_DRAWDOWN_MIN = 12, // Minimum in Drawdown Position
|
|
XPOSITION_SELECT_IN_DRAWDOWN_MAX = 13, // Maximum in Drawdown Position
|
|
XPOSITION_SELECT_SAMES = 14, // Same Type Positions
|
|
XPOSITION_SELECT_SAMES_OLDEST = 15, // Same Type Positions Oldest one
|
|
XPOSITION_SELECT_SAMES_YOUNGEST = 16, // Same Type Positions Youngest one
|
|
XPOSITION_SELECT_OPPOSITS = 17, // Opposit Type Positions
|
|
XPOSITION_SELECT_OPPOSIT_OLDEST = 18, // Opposit Type Positions Oldest one
|
|
XPOSITION_SELECT_OPPOSIT_YOUNGEST = 19, // Opposit Type Positions Youngest one
|
|
XPOSITION_SELECT_SAME_IN_PROFITS = 20, // Same Type In Profit Positions
|
|
XPOSITION_SELECT_SAME_IN_PROFITS_OLDEST = 21, // Same Type In Profit Positions Oldest one
|
|
XPOSITION_SELECT_SAME_IN_PROFITS_YOUNGEST = 22, // Same Type In Profit Positions Youngest one
|
|
XPOSITION_SELECT_SAME_IN_PROFITS_MIN = 23, // Minimum Profitable of Same Type Positions
|
|
XPOSITION_SELECT_SAME_IN_PROFITS_MAX = 24, // Maximum Profitable of Same Type Positions
|
|
XPOSITION_SELECT_OPPOSIT_IN_PROFITS = 25, // Opposit Type In Profit Positions
|
|
XPOSITION_SELECT_OPPOSIT_IN_PROFITS_OLDEST = 26, // Opposit Type In Profit Positions Oldest one
|
|
XPOSITION_SELECT_OPPOSIT_IN_PROFITS_YOUNGEST = 27, // Opposit Type In Profit Positions Youngest one
|
|
XPOSITION_SELECT_OPPOSIT_IN_PROFITS_MIN = 28, // Minimum Profitable of Opposit Type Positions
|
|
XPOSITION_SELECT_OPPOSIT_IN_PROFITS_MAX = 29, // Maximum Profitable of Opposit Type Positions
|
|
XPOSITION_SELECT_SAME_IN_DRAWDOWNS = 30, // Same Type In Deawdown Positions
|
|
XPOSITION_SELECT_SAME_IN_DRAWDOWN_OLDEST = 31, // Same Type In Deawdown Positions Oldest one
|
|
XPOSITION_SELECT_SAME_IN_DRAWDOWN_YOUNGEST = 32, // Same Type In Deawdown Positions Youngest one
|
|
XPOSITION_SELECT_SAME_IN_DRAWDOWN_MIN = 33, // Minimum In Drawdown of Same Type Positions
|
|
XPOSITION_SELECT_SAME_IN_DRAWDOWN_MAX = 34, // Maximum In Drawdown of Same Type Positions
|
|
XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWNS = 35, // Opposit Type In Deawdown Positions
|
|
XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWN_OLDEST = 36, // Opposit Type In Deawdown Positions Oldest one
|
|
XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWN_YOUNGEST = 37, // Opposit Type In Deawdown Positions Youngest one
|
|
XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWN_MIN = 38, // Minimum In Drawdown of Opposit Type Positions
|
|
XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWN_MAX = 39, // Maximum In Drawdown of Opposit Type Positions
|
|
};
|
|
|
|
/**
|
|
* Validate Position Select Type ...
|
|
*
|
|
* @param value: ENUM_XPOSITION_SELECT_TYPES
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsXValid(ENUM_XPOSITION_SELECT_TYPES value)
|
|
{
|
|
return value != XPOSITION_SELECT_NONE;
|
|
}
|
|
|
|
//
|
|
string ToXString(ENUM_XPOSITION_SELECT_TYPES value)
|
|
{
|
|
return EnumToString(value);
|
|
}
|
|
|
|
//
|
|
// Structs ...
|
|
|
|
//
|
|
struct XRR
|
|
{
|
|
//
|
|
double tps[];
|
|
|
|
//
|
|
double sl;
|
|
double entry;
|
|
|
|
//
|
|
string prefix;
|
|
string symbol;
|
|
datetime time;
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
ENUM_X_POSITION_TYPES type;
|
|
|
|
//
|
|
// Constructor ...
|
|
XRR()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
void Clean()
|
|
{
|
|
//
|
|
sl = 0;
|
|
entry = 0;
|
|
|
|
//
|
|
time = NULL;
|
|
prefix = NULL;
|
|
period = NULL;
|
|
symbol = NULL;
|
|
|
|
//
|
|
type = X_POSITION_TYPE_NONE;
|
|
|
|
//
|
|
SpecifiedClean(tps);
|
|
|
|
//
|
|
ZeroMemory(this);
|
|
}
|
|
|
|
//
|
|
bool Init(
|
|
string _symbol,
|
|
ENUM_TIMEFRAMES _period,
|
|
double _sl,
|
|
double _entry,
|
|
ENUM_X_POSITION_TYPES _type,
|
|
string _prefix = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
_sl > 0 &&
|
|
_entry > 0 &&
|
|
IsSpecifiedValid(_symbol) &&
|
|
IsSpecifiedValid(_period) &&
|
|
_type != X_POSITION_TYPE_ALL &&
|
|
_type != X_POSITION_TYPE_NONE &&
|
|
(_type == X_POSITION_TYPE_LONG
|
|
? _entry > _sl
|
|
: _entry < _sl);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
Default();
|
|
|
|
//
|
|
sl = _sl;
|
|
type = _type;
|
|
entry = _entry;
|
|
symbol = _symbol;
|
|
period = _period;
|
|
prefix = _prefix;
|
|
|
|
//
|
|
time = TimeCurrent();
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
void Default()
|
|
{
|
|
//
|
|
Add(
|
|
1.0,
|
|
tps //
|
|
);
|
|
Add(
|
|
1.5,
|
|
tps //
|
|
);
|
|
Add(
|
|
2.0,
|
|
tps //
|
|
);
|
|
Add(
|
|
3.0,
|
|
tps //
|
|
);
|
|
Add(
|
|
4.0,
|
|
tps //
|
|
);
|
|
Add(
|
|
5.0,
|
|
tps //
|
|
);
|
|
Add(
|
|
6.0,
|
|
tps //
|
|
);
|
|
}
|
|
|
|
//
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
sl > 0 &&
|
|
entry > 0 &&
|
|
IsSpecifiedValid(time) &&
|
|
IsSpecifiedValid(symbol) &&
|
|
IsSpecifiedValid(period) &&
|
|
IsValidSize(ArraySize(tps)) &&
|
|
type != X_POSITION_TYPE_ALL &&
|
|
type != X_POSITION_TYPE_NONE &&
|
|
(type == X_POSITION_TYPE_LONG
|
|
? entry > 0
|
|
: entry < sl);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string GetTag()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
//
|
|
result = GetTypeName(this);
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string sep = "_";
|
|
|
|
//
|
|
result =
|
|
GetTypeName(this) + sep + (IsSpecifiedValid(prefix) ? prefix + sep : "") + symbol + sep + ToXString(period) + sep + ToFormatString(time) + sep + ToString(type);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Model a Target ...
|
|
struct XTarget
|
|
{
|
|
//
|
|
// Props ...
|
|
bool doRF; // Do RF on Target
|
|
bool doRFOnEntry; // Do RF on Entry
|
|
double actingDistance; // Acting Distances
|
|
double target; // Target Price for Actions
|
|
double volumeMultiplier; // Volume Multiplier for Partial Close
|
|
double tpValue; // TP Value Changed ...
|
|
|
|
//
|
|
// Constructor ...
|
|
XTarget()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
target = 0;
|
|
tpValue = 0;
|
|
doRF = false;
|
|
actingDistance = 0;
|
|
doRFOnEntry = false;
|
|
volumeMultiplier = 0;
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = target > 0;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Get Lowest Target index ...
|
|
int GetLowest(XTarget &targets[])
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (!HasChild(targets))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XTarget iTarget;
|
|
int count = ArraySize(targets);
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
bool canSet =
|
|
!iTarget.IsValid()
|
|
? true
|
|
: iTarget.target > targets[i].target;
|
|
if (canSet)
|
|
{
|
|
//
|
|
result = i;
|
|
iTarget = targets[i];
|
|
}
|
|
}
|
|
|
|
//
|
|
iTarget.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Highest Target index ...
|
|
int GetHighest(XTarget &targets[])
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (!HasChild(targets))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XTarget iTarget;
|
|
int count = ArraySize(targets);
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
bool canSet =
|
|
!iTarget.IsValid()
|
|
? true
|
|
: iTarget.target < targets[i].target;
|
|
if (canSet)
|
|
{
|
|
//
|
|
result = i;
|
|
iTarget = targets[i];
|
|
}
|
|
}
|
|
|
|
//
|
|
iTarget.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Apply Sorting on Targets ...
|
|
void ApplySortOnTargets(
|
|
ENUM_X_DIRECTION forDir, // Target Sorting Direction ...
|
|
XTarget &targets[] // Targets to Apply Sorting ...
|
|
)
|
|
{
|
|
//
|
|
bool has = HasChild(targets) &&
|
|
HasDirection(forDir);
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish(forDir);
|
|
bool isBearish = IsBearish(forDir);
|
|
|
|
//
|
|
XTarget tmp[];
|
|
Copy(
|
|
targets,
|
|
tmp //
|
|
);
|
|
Clean(targets);
|
|
while (HasChild(tmp))
|
|
{
|
|
//
|
|
int idx = -1;
|
|
if (isBullish)
|
|
{
|
|
idx = GetLowest(tmp);
|
|
}
|
|
else if (isBearish)
|
|
{
|
|
idx = GetHighest(tmp);
|
|
}
|
|
|
|
//
|
|
has = IsValidIndex(idx);
|
|
if (!has)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
XTarget iTarget = tmp[idx];
|
|
ArrayRemove(
|
|
tmp,
|
|
idx,
|
|
1 //
|
|
);
|
|
AddRef(
|
|
iTarget,
|
|
targets //
|
|
);
|
|
}
|
|
|
|
//
|
|
Clean(tmp);
|
|
}
|
|
|
|
//
|
|
// Model an Open Position ...
|
|
struct XPosition
|
|
{
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Magic Number ...
|
|
ulong magic;
|
|
|
|
//
|
|
// Ticket ID ...
|
|
ulong ticket;
|
|
|
|
//
|
|
// Tradinng Symbol ...
|
|
string symbol;
|
|
|
|
//
|
|
// Trading Period ...
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
// Position Type ...
|
|
ENUM_POSITION_TYPE type;
|
|
|
|
//
|
|
// Take Profit ...
|
|
double tp;
|
|
|
|
//
|
|
// Stop Loss ...
|
|
double sl;
|
|
|
|
//
|
|
// Position Current Profit ...
|
|
double profit;
|
|
|
|
//
|
|
// Position Open Price ...
|
|
double entry;
|
|
|
|
//
|
|
// Current Symbol Price ...
|
|
double price;
|
|
|
|
//
|
|
// Position Swap ...
|
|
double swap;
|
|
|
|
//
|
|
// Position Commission ...
|
|
double commission;
|
|
|
|
//
|
|
// Volume ...
|
|
double volume;
|
|
|
|
//
|
|
// Position Open Time ...
|
|
datetime openAt;
|
|
|
|
//
|
|
// Sifnal Provider ...
|
|
string provider;
|
|
|
|
//
|
|
// Position Comment ...
|
|
string comment;
|
|
|
|
//
|
|
// Constructor ...
|
|
XPosition()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Initializers ...
|
|
|
|
bool ByIndex(int index)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
static CPositionInfo mPositionInfo;
|
|
|
|
//
|
|
result = mPositionInfo.SelectByIndex(index);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ulong mTicket = mPositionInfo.Ticket();
|
|
|
|
//
|
|
result = ByTicket(mTicket);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool ByTicket(ulong mTicket)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
static CPositionInfo mPositionInfo;
|
|
|
|
//
|
|
result = mPositionInfo.SelectByTicket(mTicket);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
swap = mPositionInfo.Swap();
|
|
magic = mPositionInfo.Magic();
|
|
openAt = mPositionInfo.Time();
|
|
sl = mPositionInfo.StopLoss();
|
|
ticket = mPositionInfo.Ticket();
|
|
symbol = mPositionInfo.Symbol();
|
|
tp = mPositionInfo.TakeProfit();
|
|
profit = mPositionInfo.Profit();
|
|
volume = mPositionInfo.Volume();
|
|
comment = mPositionInfo.Comment();
|
|
entry = mPositionInfo.PriceOpen();
|
|
type = mPositionInfo.PositionType();
|
|
price = mPositionInfo.PriceCurrent();
|
|
commission = mPositionInfo.Commission();
|
|
|
|
//
|
|
period = ExtractPeriod(comment);
|
|
provider = ExtractProvider(comment);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
magic = 0;
|
|
ticket = 0;
|
|
tp = 0;
|
|
sl = 0;
|
|
swap = 0;
|
|
entry = 0;
|
|
price = 0;
|
|
profit = 0;
|
|
volume = 0;
|
|
openAt = 0;
|
|
commission = 0;
|
|
|
|
//
|
|
type = NULL;
|
|
period = NULL;
|
|
|
|
//
|
|
symbol = NULL;
|
|
comment = NULL;
|
|
provider = NULL;
|
|
|
|
//
|
|
ZeroMemory(this);
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsSpecifiedValid(symbol) &&
|
|
NotEmpty(ticket)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Entry Price ...
|
|
double GetEntry()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetXEntry(
|
|
symbol,
|
|
type
|
|
//
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Exit ...
|
|
double GetExit()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetXExit(
|
|
symbol,
|
|
type
|
|
//
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Spread by Point ...
|
|
double GetSpread()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = PriceToPoint(GetXSpread(symbol));
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double GetPointsValue()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetPoints(symbol);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double GetProfitInPoint()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); // Tick size
|
|
double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); // Tick value
|
|
double pointSize = SymbolInfoDouble(symbol, SYMBOL_POINT); // Point size
|
|
double pointValue = tickValue * pointSize / tickSize; // Point value
|
|
|
|
//
|
|
result = profit / (volume * tickValue);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Risk ...
|
|
double GetRisk()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
result = MathAbs(entry - sl);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double GetRiskInPoint()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
result = GetRisk() / GetPoints();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Reward ...
|
|
double GetReward()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = MathAbs(tp - entry);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double GetRewardInPoint()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
result = GetReward() / GetPoints();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Risk Reward Ratio ...
|
|
double GetRiskRewardRatio()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetReward() / GetRisk();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate TP Levels ...
|
|
int CalculateTPLevels(double &tps[])
|
|
{
|
|
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
SpecifiedClean(tps);
|
|
|
|
//
|
|
bool isValid = IsValid();
|
|
if (!isValid)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double risk = GetRisk();
|
|
int r2r = (int)GetRiskRewardRatio();
|
|
bool isLong = IsLong(type);
|
|
for (int i = 0; i < r2r; i++)
|
|
{
|
|
//
|
|
double iValue =
|
|
isLong
|
|
? entry + risk + (i * risk)
|
|
: entry - risk - (i * risk);
|
|
//
|
|
Add(
|
|
iValue,
|
|
tps //
|
|
);
|
|
}
|
|
|
|
//
|
|
result = ArraySize(tps);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Reached TP Levels ...
|
|
void CalculateReahedTP(
|
|
double &reachedLevel,
|
|
double &reachedPrice //
|
|
)
|
|
{
|
|
//
|
|
reachedLevel = -1;
|
|
reachedPrice = 0;
|
|
double tps[];
|
|
bool isLong = IsLong(type);
|
|
double exitPrice = GetExit();
|
|
int tpLevels = CalculateTPLevels(tps);
|
|
if (!IsValidSize(tpLevels) || exitPrice <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < tpLevels - 1; i++)
|
|
{
|
|
//
|
|
double cTP = tps[i];
|
|
double nTP = tps[i + 1];
|
|
|
|
//
|
|
bool isReached =
|
|
isLong
|
|
? exitPrice > cTP &&
|
|
exitPrice < nTP
|
|
: exitPrice < cTP &&
|
|
exitPrice > nTP;
|
|
if (isReached)
|
|
{
|
|
//
|
|
reachedLevel = i + 1;
|
|
reachedPrice = cTP;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Calculate Touched Reward ...
|
|
double CalculateTouchedReward()
|
|
{
|
|
//
|
|
double result = 0.0;
|
|
|
|
//
|
|
bool has = IsValid() &&
|
|
profit > 0;
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double risk = MathAbs(entry - sl);
|
|
double currentReward = MathAbs(price - entry);
|
|
|
|
//
|
|
result = currentReward / risk;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Age ...
|
|
int GetAge(
|
|
ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period
|
|
)
|
|
{
|
|
return GetXAge(this, mPeriod);
|
|
}
|
|
|
|
//
|
|
// Check this instance is Same os Given instance or not ...
|
|
bool IsSameAs(
|
|
const XPosition &value // instance for Compare
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
type == value.type &&
|
|
magic == value.magic &&
|
|
entry == value.entry &&
|
|
ticket == value.ticket &&
|
|
volume == value.volume &&
|
|
symbol == value.symbol &&
|
|
provider == value.provider
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find index in a Collection ...
|
|
int FindIndex(
|
|
XPosition &values[] // Collection to Find
|
|
)
|
|
{
|
|
//
|
|
return FindXIndex(
|
|
this,
|
|
values
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Check Items Passed Specific Filters or not ...
|
|
bool IsFiltersPassed(
|
|
string mSymbol = NULL, // Trading Symbol
|
|
string mProvider = NULL, // Signal Provider
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe
|
|
ENUM_X_POSITION_TYPES mType = NULL, // Long (Buy), Short (Sell)
|
|
ulong mMagic = NULL, // Magic Number
|
|
bool mFilterByMagic = true // Get Only Self Open Positions
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
// Magic Filter ...
|
|
IsMagicFilterPassed(
|
|
mMagic,
|
|
mFilterByMagic,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Symbol Filter ...
|
|
IsSymbolFilterPassed(
|
|
mSymbol,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Provider Filter ...
|
|
IsProviderFilterPassed(
|
|
mProvider,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Period Filter ...
|
|
IsPeriodFilterPassed(
|
|
mPeriod,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Type Filter ...
|
|
IsTypeFilterPassed(
|
|
mType,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Model a Signal ...
|
|
struct XSignal
|
|
{
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
ulong positionId; // if Executed this filled ...
|
|
|
|
//
|
|
datetime time; // Issue Time ...
|
|
|
|
//
|
|
double tp; // Take Profit ...
|
|
double sl; // Stop Loss ...
|
|
double entry; // Exntry or Execution Price ...
|
|
double volume; // Position Volume ...
|
|
|
|
//
|
|
string symbol; // Trading Symbol ...
|
|
string comment; // Comment ...
|
|
string provider; // Signaller ...
|
|
|
|
//
|
|
ENUM_TIMEFRAMES period; // Trading TimeFrame ...
|
|
ENUM_POSITION_TYPE type; // Long (Buy) or Short (Sell) ...
|
|
ENUM_X_ORDER_MODES mode; // Execution Mode ...
|
|
|
|
//
|
|
string conditions; // Signal Conditions ...
|
|
|
|
//
|
|
// Additional ...
|
|
|
|
//
|
|
// Traget ...
|
|
XTarget targets[]; // Provided Targets ...
|
|
int appliedTargetIDX; // Last Applied Target Index ...
|
|
bool ignoreEAVolume; // Ignore EA Volume ...
|
|
bool isTargetApplied; // Check if Target Applied or not ...
|
|
|
|
//
|
|
// Constructor ...
|
|
XSignal()
|
|
{
|
|
Default();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
entry = 0;
|
|
volume = 0;
|
|
positionId = 0;
|
|
|
|
//
|
|
time = NULL;
|
|
type = NULL;
|
|
mode = NULL;
|
|
symbol = NULL;
|
|
period = NULL;
|
|
comment = NULL;
|
|
provider = NULL;
|
|
conditions = NULL;
|
|
|
|
//
|
|
SpecifiedClean(targets);
|
|
appliedTargetIDX = -1;
|
|
ignoreEAVolume = false;
|
|
isTargetApplied = false;
|
|
|
|
//
|
|
ZeroMemory(this);
|
|
}
|
|
|
|
//
|
|
// Default Values ...
|
|
void Default()
|
|
{
|
|
//
|
|
entry = 0;
|
|
volume = 0;
|
|
positionId = 0;
|
|
|
|
//
|
|
time = NULL;
|
|
type = NULL;
|
|
mode = NULL;
|
|
symbol = NULL;
|
|
period = NULL;
|
|
comment = NULL;
|
|
provider = NULL;
|
|
conditions = NULL;
|
|
|
|
//
|
|
SpecifiedClean(targets);
|
|
appliedTargetIDX = -1;
|
|
ignoreEAVolume = false;
|
|
isTargetApplied = false;
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsSpecifiedValid(period) &&
|
|
IsSpecifiedValid(symbol) &&
|
|
NotEmpty(volume) &&
|
|
NotEmpty(entry)
|
|
//
|
|
;
|
|
|
|
//
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// DO All Calculations and Normalizations ...
|
|
bool Normalize()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalizations ...
|
|
symbol = NormalizeSymbol(symbol);
|
|
period = NormalizePeriod(period);
|
|
|
|
//
|
|
time = NormalizeTime(time);
|
|
|
|
//
|
|
sl = NormalizePrice(sl, symbol);
|
|
tp = NormalizePrice(tp, symbol);
|
|
entry = NormalizePrice(entry, symbol);
|
|
volume = NormalizeVolume(volume, symbol);
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Signal Executed or not ...
|
|
bool IsExecuted()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid() &&
|
|
NotEmpty(positionId)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Generate Comment for Signal ...
|
|
string GenerateComment()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (IsSpecifiedValid(provider))
|
|
{
|
|
//
|
|
// Generate Provider Tag ...
|
|
result += GenerateProviderTag(provider);
|
|
}
|
|
|
|
//
|
|
if (IsSpecifiedValid(period))
|
|
{
|
|
//
|
|
// Generate Period Tag ...
|
|
result += GeneratePeriodTag(period);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetAge()
|
|
{
|
|
//
|
|
return GetXAge(
|
|
this,
|
|
this.period //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Find Risk ...
|
|
double GetRisk()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
result = MathAbs(entry - sl);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Reward ...
|
|
double GetReward()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = MathAbs(tp - entry);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Risk Reward Ratio ...
|
|
double GetRiskRewardRatio()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetReward() / GetRisk();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string GetTag()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
result = "XSignal_" +
|
|
symbol + "_" +
|
|
ToXString(period) + "_" +
|
|
ToXString(type) + "_" +
|
|
ToXString(sl) + "_" +
|
|
ToXString(tp) + "_" +
|
|
ToXString(entry);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string GetObjectID()
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = "XSignal_" +
|
|
symbol + "_" +
|
|
ToXString(period) + "_" +
|
|
ToXString(type) + "_" +
|
|
ToXString(TimeToSeconds(time));
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve String Representation of Signal ...
|
|
string ToString()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
result =
|
|
//
|
|
ToXString("Symbol", symbol) +
|
|
ToXString("Period", period) +
|
|
ToXString("Provider", provider) +
|
|
ToXString("Type", type) +
|
|
ToXString("Mode", mode) +
|
|
ToXString("Volume", volume) +
|
|
ToXString("Entry", entry) +
|
|
ToXString("TP", tp) +
|
|
ToXString("SL", sl) +
|
|
ToXString("Time", time) +
|
|
ToXString("Comment", comment) +
|
|
//
|
|
""
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool IsSameAs(XSignal &item)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid() &&
|
|
item.IsValid() &&
|
|
//
|
|
tp == item.tp &&
|
|
sl == item.sl &&
|
|
mode == item.mode &&
|
|
time == item.time &&
|
|
type == item.type &&
|
|
entry == item.entry &&
|
|
symbol == item.symbol &&
|
|
period == item.period &&
|
|
provider == item.provider
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string GetMessage(string action = NULL)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ToXString(type) +
|
|
" Signal" +
|
|
(!IsSpecifiedValid(action)
|
|
? ""
|
|
: " " + action) +
|
|
" by: " + provider +
|
|
" on (" + symbol + ")" +
|
|
" in: " + ToXString(period);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string GetFileName()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
symbol + "\\" +
|
|
ToXString(type) + "\\" +
|
|
ToXString(period) + "_" +
|
|
ToFormatString(time)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Model an Order ...
|
|
struct XOrder
|
|
{
|
|
//
|
|
// Time of order placement ...
|
|
datetime setupAt;
|
|
|
|
//
|
|
// Time of order expiration ...
|
|
datetime expiredAt;
|
|
|
|
//
|
|
// Time of order execution or cancellation ...
|
|
datetime executedAt;
|
|
|
|
//
|
|
// Order type ...
|
|
ENUM_ORDER_TYPE type;
|
|
|
|
//
|
|
// Order state ...
|
|
ENUM_ORDER_STATE state;
|
|
|
|
//
|
|
// Type of execution by remainder ...
|
|
ENUM_ORDER_TYPE_FILLING filling;
|
|
|
|
//
|
|
// Order lifetime ...
|
|
ENUM_ORDER_TYPE_TIME lifetime;
|
|
|
|
//
|
|
// Order ticket ...
|
|
ulong ticket;
|
|
|
|
//
|
|
// Magic Number ...
|
|
long magic;
|
|
|
|
//
|
|
// Position id, that is placed on order,
|
|
// when it is executed. Each executed order invokes a
|
|
// deal, that opens new or changes existing
|
|
// position. Id of that position is placed on
|
|
// executed order in this moment.
|
|
long positionId;
|
|
|
|
//
|
|
// Initial volume on order placement ...
|
|
double initialVolume;
|
|
|
|
//
|
|
// Unfilled volume ...
|
|
double currentVolume;
|
|
|
|
//
|
|
// Price, specified in the order ...
|
|
double openPrice;
|
|
|
|
//
|
|
// Current price by order symbol ...
|
|
double currentPrice;
|
|
|
|
//
|
|
// Price of placing Limit order when StopLimit order is triggered ...
|
|
double stopLimitPrice;
|
|
|
|
//
|
|
// Take Profit level ...
|
|
double tp;
|
|
|
|
//
|
|
// Stop Loss level ...
|
|
double sl;
|
|
|
|
//
|
|
// Trading Symbol ...
|
|
string symbol;
|
|
|
|
//
|
|
// Signal Provider ...
|
|
string provider;
|
|
|
|
//
|
|
// Order Comment ...
|
|
string comment;
|
|
|
|
//
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
// Constructor ...
|
|
XOrder()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Initializers ...
|
|
bool ByIndex(
|
|
int index // Fill By Index ...
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int ordersCount = OrdersTotal();
|
|
if (ordersCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
static COrderInfo mOrderInfo;
|
|
|
|
//
|
|
result = mOrderInfo.SelectByIndex(index);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Reading Order Info ...
|
|
magic = mOrderInfo.Magic();
|
|
sl = mOrderInfo.StopLoss();
|
|
tp = mOrderInfo.TakeProfit();
|
|
ticket = mOrderInfo.Ticket();
|
|
openPrice = mOrderInfo.PriceOpen();
|
|
positionId = mOrderInfo.PositionId();
|
|
currentPrice = mOrderInfo.PriceCurrent();
|
|
initialVolume = mOrderInfo.VolumeInitial();
|
|
currentVolume = mOrderInfo.VolumeCurrent();
|
|
stopLimitPrice = mOrderInfo.PriceStopLimit();
|
|
|
|
//
|
|
symbol = mOrderInfo.Symbol();
|
|
comment = mOrderInfo.Comment();
|
|
|
|
//
|
|
state = mOrderInfo.State();
|
|
type = mOrderInfo.OrderType();
|
|
lifetime = mOrderInfo.TypeTime();
|
|
filling = mOrderInfo.TypeFilling();
|
|
|
|
//
|
|
setupAt = mOrderInfo.TimeSetup();
|
|
executedAt = mOrderInfo.TimeDone();
|
|
expiredAt = mOrderInfo.TimeExpiration();
|
|
|
|
//
|
|
period = ExtractPeriod(comment);
|
|
provider = ExtractProvider(comment);
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Specific History Order ...
|
|
bool HistoryByIndex(
|
|
int index // Fill By Index ...
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int ordersCount = HistoryOrdersTotal();
|
|
if (ordersCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
static CHistoryOrderInfo mOrderInfo;
|
|
|
|
//
|
|
result = mOrderInfo.SelectByIndex(index);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Reading Order Info ...
|
|
magic = mOrderInfo.Magic();
|
|
sl = mOrderInfo.StopLoss();
|
|
tp = mOrderInfo.TakeProfit();
|
|
ticket = mOrderInfo.Ticket();
|
|
openPrice = mOrderInfo.PriceOpen();
|
|
positionId = mOrderInfo.PositionId();
|
|
currentPrice = mOrderInfo.PriceCurrent();
|
|
initialVolume = mOrderInfo.VolumeInitial();
|
|
currentVolume = mOrderInfo.VolumeCurrent();
|
|
stopLimitPrice = mOrderInfo.PriceStopLimit();
|
|
|
|
//
|
|
symbol = mOrderInfo.Symbol();
|
|
comment = mOrderInfo.Comment();
|
|
|
|
//
|
|
state = mOrderInfo.State();
|
|
type = mOrderInfo.OrderType();
|
|
lifetime = mOrderInfo.TypeTime();
|
|
filling = mOrderInfo.TypeFilling();
|
|
|
|
//
|
|
setupAt = mOrderInfo.TimeSetup();
|
|
executedAt = mOrderInfo.TimeDone();
|
|
expiredAt = mOrderInfo.TimeExpiration();
|
|
|
|
//
|
|
period = ExtractPeriod(comment);
|
|
provider = ExtractProvider(comment);
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
tp = 0;
|
|
sl = 0;
|
|
magic = 0;
|
|
ticket = 0;
|
|
positionId = 0;
|
|
openPrice = 0;
|
|
currentPrice = 0;
|
|
initialVolume = 0;
|
|
currentVolume = 0;
|
|
stopLimitPrice = 0;
|
|
|
|
//
|
|
setupAt = NULL;
|
|
expiredAt = NULL;
|
|
executedAt = NULL;
|
|
|
|
//
|
|
symbol = NULL;
|
|
comment = NULL;
|
|
provider = NULL;
|
|
|
|
//
|
|
type = NULL;
|
|
state = NULL;
|
|
period = NULL;
|
|
filling = NULL;
|
|
lifetime = NULL;
|
|
|
|
//
|
|
ZeroMemory(this);
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsSpecifiedValid(symbol) &&
|
|
NotEmpty(ticket) &&
|
|
NotEmpty(positionId)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Age ...
|
|
int GetAge(
|
|
ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period
|
|
)
|
|
{
|
|
return GetXAge(this, mPeriod);
|
|
}
|
|
|
|
//
|
|
// Check this instance is Same os Given instance or not ...
|
|
bool IsSameAs(
|
|
const XOrder &value // instance for Compare
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
type == value.type &&
|
|
state == value.state &&
|
|
magic == value.magic &&
|
|
ticket == value.ticket &&
|
|
symbol == value.symbol &&
|
|
provider == value.provider &&
|
|
positionId == value.positionId
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find index in a Collection ...
|
|
int FindIndex(
|
|
XOrder &values[] // Collection to Find
|
|
)
|
|
{
|
|
//
|
|
return FindXIndex(
|
|
this,
|
|
values
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Check Items Passed Specific Filters or not ...
|
|
bool IsFiltersPassed(
|
|
string mSymbol = NULL, // Trading Symbol
|
|
string mProvider = NULL, // Signal Provider
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe
|
|
ENUM_X_POSITION_TYPES mType = NULL, // Long (Buy), Short (Sell)
|
|
ENUM_ORDER_STATE mState = NULL, // Order State
|
|
ulong mMagic = NULL, // Magic Number
|
|
bool mFilterByMagic = true // Get Only Self Open Positions
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
// Magic Filter ...
|
|
IsMagicFilterPassed(
|
|
mMagic,
|
|
mFilterByMagic,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Symbol Filter ...
|
|
IsSymbolFilterPassed(
|
|
mSymbol,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Provider Filter ...
|
|
IsProviderFilterPassed(
|
|
mProvider,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Period Filter ...
|
|
IsPeriodFilterPassed(
|
|
mPeriod,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Type Filter ...
|
|
IsTypeFilterPassed(
|
|
mType,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// State Filter ...
|
|
IsStateFilterPassed(
|
|
mState,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Model a Deal ...
|
|
struct XDeal
|
|
{
|
|
//
|
|
// the ID of the Expert Advisor, that executed the deal ...
|
|
ulong magic;
|
|
|
|
//
|
|
// the ID of position, in which the deal was involved ...
|
|
ulong positionId;
|
|
|
|
//
|
|
// Ticket ...
|
|
ulong ticket;
|
|
|
|
//
|
|
// the name of the deal symbol ...
|
|
string symbol;
|
|
|
|
//
|
|
// order by which the deal is executed ...
|
|
ulong order;
|
|
|
|
//
|
|
// the time of deal execution ...
|
|
datetime time;
|
|
|
|
//
|
|
// Deal price ...
|
|
double price;
|
|
|
|
//
|
|
// the financial result of the deal (in deposit currency) ...
|
|
double profit;
|
|
|
|
//
|
|
// the amount of swap when position is closed ...
|
|
double swap;
|
|
|
|
//
|
|
// the amount of commission of the deal ...
|
|
double commission;
|
|
|
|
//
|
|
// the volume of deal ...
|
|
double volume;
|
|
|
|
//
|
|
// the deal comment ...
|
|
string comment;
|
|
|
|
//
|
|
string provider;
|
|
|
|
//
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
// the deal type ...
|
|
// ------------------------------------------------------------------
|
|
// DEAL_TYPE_BUY => Buy ...
|
|
// DEAL_TYPE_SELL => Sell ...
|
|
// DEAL_TYPE_BUY_CANCELED => Canceled buy deal ...
|
|
// There can be a situation when a previously executed buy deal is canceled. In this case,
|
|
// the type of the previously executed deal (DEAL_TYPE_BUY) is changed to DEAL_TYPE_BUY_CANCELED,
|
|
// and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation ...
|
|
//
|
|
// DEAL_TYPE_SELL_CANCELED => Canceled sell deal ...
|
|
// There can be a situation when a previously executed sell deal is canceled. In this case,
|
|
// the type of the previously executed deal (DEAL_TYPE_SELL) is changed to DEAL_TYPE_SELL_CANCELED,
|
|
// and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation
|
|
//
|
|
// DEAL_TYPE_BALANCE => Balance ...
|
|
// DEAL_TYPE_CREDIT => Credit ...
|
|
// DEAL_TYPE_CHARGE => Additional charge ...
|
|
// DEAL_TYPE_CORRECTION => Correction ...
|
|
// DEAL_TAX => Tax charges ...
|
|
// DEAL_TYPE_BONUS => Bonus ...
|
|
// DEAL_TYPE_INTEREST => Interest rate ...
|
|
// DEAL_DIVIDEND => Dividend operations...
|
|
// DEAL_DIVIDEND_FRANKED => Franked (non-taxable) dividend operations ...
|
|
// DEAL_TYPE_COMMISSION => Additional commission ...
|
|
// DEAL_TYPE_COMMISSION_DAILY => Daily commission ...
|
|
// DEAL_TYPE_COMMISSION_MONTHLY => Monthly commission ...
|
|
// DEAL_TYPE_COMMISSION_AGENT_DAILY => Daily agent commission ...
|
|
// DEAL_TYPE_COMMISSION_AGENT_MONTHLY => Monthly agent commission
|
|
ENUM_DEAL_TYPE type;
|
|
|
|
//
|
|
// the deal direction ...
|
|
// ----------------------------------
|
|
// DEAL_ENTRY_IN => Entry in ...
|
|
// DEAL_ENTRY_OUT => Entry out ...
|
|
// DEAL_ENTRY_INOUT => Reverse ...
|
|
// DEAL_ENTRY_OUT_BY => Close a position by an opposite one ...
|
|
ENUM_DEAL_ENTRY entry;
|
|
|
|
//
|
|
// deal reson ...
|
|
// ---------------------
|
|
// DEAL_REASON_SL => The deal was executed as a result of Stop Loss activation ...
|
|
// DEAL_REASON_TP => The deal was executed as a result of Take Profit activation ...
|
|
// DEAL_REASON_SO => The deal was executed as a result of the Stop Out event ...
|
|
// DEAL_REASON_WEB => The deal was executed as a result of activation of an order placed from the web platform ...
|
|
// DEAL_REASON_SPLIT => The deal was executed after the split (price reduction) of an instrument, which had an open position during split announcement ...
|
|
// DEAL_REASON_CLIENT => The deal was executed as a result of activation of an order placed from a desktop terminal ...
|
|
// DEAL_REASON_MOBILE => The deal was executed as a result of activation of an order placed from a mobile application ...
|
|
// DEAL_REASON_EXPERT => The deal was executed as a result of activation of an order placed from an MQL5 program, i.e. an Expert Advisor or a script ...
|
|
// DEAL_REASON_VMARGIN => The deal was executed after charging the variation margin ...
|
|
// DEAL_REASON_ROLLOVER => The deal was executed due to a rollover ...
|
|
ENUM_DEAL_REASON reason;
|
|
|
|
//
|
|
// Constructor ...
|
|
XDeal()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Initializers ...
|
|
bool ByIndex(
|
|
int index // Deal Index
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int dealsCount = HistoryDealsTotal();
|
|
result = dealsCount > 0;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
static CDealInfo mDealInfo;
|
|
|
|
//
|
|
result = mDealInfo.SelectByIndex(index);
|
|
if (!result)
|
|
{
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Reading Order Info ...
|
|
swap = mDealInfo.Swap();
|
|
magic = mDealInfo.Magic();
|
|
order = mDealInfo.Order();
|
|
ticket = mDealInfo.Ticket();
|
|
time = mDealInfo.Time();
|
|
price = mDealInfo.Price();
|
|
symbol = mDealInfo.Symbol();
|
|
profit = mDealInfo.Profit();
|
|
volume = mDealInfo.Volume();
|
|
comment = mDealInfo.Comment();
|
|
positionId = mDealInfo.PositionId();
|
|
entry = mDealInfo.Entry();
|
|
commission = mDealInfo.Commission();
|
|
type = mDealInfo.DealType();
|
|
reason = (ENUM_DEAL_REASON)HistoryDealGetInteger(
|
|
ticket,
|
|
DEAL_REASON);
|
|
|
|
//
|
|
period = ExtractPeriod(comment);
|
|
provider = ExtractProvider(comment);
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
magic = 0;
|
|
positionId = 0;
|
|
ticket = 0;
|
|
order = 0;
|
|
time = 0;
|
|
price = 0;
|
|
profit = 0;
|
|
swap = 0;
|
|
commission = 0;
|
|
volume = 0;
|
|
|
|
//
|
|
symbol = NULL;
|
|
comment = NULL;
|
|
provider = NULL;
|
|
|
|
//
|
|
type = NULL;
|
|
entry = NULL;
|
|
period = NULL;
|
|
reason = NULL;
|
|
|
|
//
|
|
ZeroMemory(this);
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsSpecifiedValid(symbol) &&
|
|
NotEmpty(ticket) &&
|
|
NotEmpty(positionId)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Age ...
|
|
int GetAge(
|
|
ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period
|
|
)
|
|
{
|
|
return GetXAge(this, mPeriod);
|
|
}
|
|
|
|
//
|
|
// Check this instance is Same os Given instance or not ...
|
|
bool IsSameAs(
|
|
const XDeal &value // instance for Compare
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
type == value.type &&
|
|
magic == value.magic &&
|
|
entry == value.entry &&
|
|
reason == value.reason &&
|
|
ticket == value.ticket &&
|
|
volume == value.volume &&
|
|
symbol == value.symbol &&
|
|
provider == value.provider &&
|
|
positionId == value.positionId
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find index in a Collection ...
|
|
int FindIndex(
|
|
XDeal &values[] // Collection to Find
|
|
)
|
|
{
|
|
//
|
|
return FindXIndex(
|
|
this,
|
|
values
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Check Items Passed Specific Filters or not ...
|
|
bool IsFiltersPassed(
|
|
string mSymbol = NULL, // Trading Symbol
|
|
string mProvider = NULL, // Signal Provider
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe
|
|
ENUM_DEAL_TYPE mType = NULL, // Deal Type
|
|
ENUM_DEAL_ENTRY mEntry = NULL, // Deal Entry
|
|
ENUM_DEAL_REASON mReason = NULL, // Deal Reason
|
|
ulong mMagic = NULL, // Magic Number
|
|
bool mFilterByMagic = true // Get Only Self Open Positions
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
// Magic Filter ...
|
|
IsMagicFilterPassed(
|
|
mMagic,
|
|
mFilterByMagic,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Symbol Filter ...
|
|
IsSymbolFilterPassed(
|
|
mSymbol,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Provider Filter ...
|
|
IsProviderFilterPassed(
|
|
mProvider,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Period Filter ...
|
|
IsPeriodFilterPassed(
|
|
mPeriod,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Type Filter ...
|
|
IsTypeFilterPassed(
|
|
mType,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Entry Filter ...
|
|
IsEntryFilterPassed(
|
|
mEntry,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Reason Filter ...
|
|
IsReasonFilterPassed(
|
|
mReason,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Model OnTrade Event Handler Result on XCTrade Class ...
|
|
struct XOnTradeHandlerState
|
|
{
|
|
//
|
|
bool hasNewDeal;
|
|
int newDeals;
|
|
|
|
//
|
|
bool hasNewOrder;
|
|
int newOrders;
|
|
|
|
//
|
|
bool hasNewPosition;
|
|
int newPositions;
|
|
|
|
//
|
|
bool hasNewHistoryOrder;
|
|
int newHistoryOrders;
|
|
|
|
//
|
|
// Constructor ...
|
|
XOnTradeHandlerState()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
hasNewDeal = false;
|
|
hasNewOrder = false;
|
|
hasNewPosition = false;
|
|
hasNewHistoryOrder = false;
|
|
|
|
//
|
|
newDeals = 0;
|
|
newOrders = 0;
|
|
newPositions = 0;
|
|
newHistoryOrders = 0;
|
|
|
|
//
|
|
ZeroMemory(this);
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
(
|
|
//
|
|
hasNewDeal
|
|
? newDeals > 0
|
|
: true
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
(
|
|
//
|
|
hasNewOrder
|
|
? newOrders > 0
|
|
: true
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
(
|
|
//
|
|
hasNewPosition
|
|
? newPositions > 0
|
|
: true
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
(
|
|
//
|
|
hasNewHistoryOrder
|
|
? newHistoryOrders > 0
|
|
: true
|
|
//
|
|
)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// an Structure for Describe aTrading Session ...
|
|
struct XTradeSession
|
|
{
|
|
//
|
|
// Properties ...
|
|
string start; // Session Start Time (hh:mm)
|
|
string end; // Session End Time (hh:mm)
|
|
string name; // Session Name
|
|
|
|
//
|
|
// Constructor ...
|
|
XTradeSession()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
end = NULL;
|
|
name = NULL;
|
|
start = NULL;
|
|
|
|
//
|
|
ZeroMemory(this);
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsSpecifiedValid(start) &&
|
|
IsSpecifiedValid(end);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Session is Active or Not ...
|
|
bool IsActive(datetime time = NULL)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
time = NormalizeTime(time);
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = IsTimeInRange(
|
|
time,
|
|
start,
|
|
end //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// an Structure for Describe an Specified Symbols
|
|
// Trading Sessions ...
|
|
struct XSymbolTradeConfig
|
|
{
|
|
//
|
|
// Propeties ...
|
|
|
|
//
|
|
int longs; // All Long Trades
|
|
int shorts; // All Short Trades
|
|
int trades; // All Trades
|
|
int losses; // All Loosing Trades
|
|
int profits; // All Winning Trades
|
|
string name; // Provider Name
|
|
string symbol; // Trading Symbol
|
|
int managedSLs; // Managed SL(s)
|
|
int managedTPs; // Managed TP(s)
|
|
int managedTrades; // Managed Trades
|
|
int maxAllowedTPs; // Max Allowed TP(s) in Restrictions Period
|
|
int maxAllowedSLs; // Max Allowed SL(s) in Restrictions Period
|
|
int maxAllowedTrades; // Max Allowed Trades in Restrictions Period
|
|
datetime managedStart; // Managed Start Time
|
|
double managedBalance; // Managed Start Balance
|
|
double managedProfits; // Managed Profit(s)
|
|
ENUM_TIMEFRAMES period; // Trading Period
|
|
int maxAllowedPositions; // Max Allowed Same Time Trades
|
|
double maxAllowedSpread; // Max Allowed Spread For Trade
|
|
bool isForceCloseAtTime; // a Flag for Determines Force Closed or not
|
|
XTradeSession sessions[]; // Trading Sessions
|
|
string closeAllOpenTradesAt; // Close All Open Trades per Day At Specified Time
|
|
int restrictionsPeriodMultiplier; // Specified Restrictions Period Multiplier
|
|
ENUM_XTRADE_RESTRICTION_PERIOD restrictionsPeriod; // Trade Restrictions Period
|
|
|
|
//
|
|
// Constructor ...
|
|
XSymbolTradeConfig()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
name = NULL;
|
|
symbol = NULL;
|
|
period = NULL;
|
|
SpecifiedClean(sessions);
|
|
|
|
//
|
|
longs = 0;
|
|
shorts = 0;
|
|
trades = 0;
|
|
losses = 0;
|
|
profits = 0;
|
|
|
|
//
|
|
managedStart = NULL;
|
|
|
|
//
|
|
managedSLs = 0;
|
|
managedTPs = 0;
|
|
managedTrades = 0;
|
|
|
|
//
|
|
managedBalance = 0;
|
|
managedProfits = 0;
|
|
|
|
//
|
|
maxAllowedTPs = 0;
|
|
maxAllowedSLs = 0;
|
|
maxAllowedTrades = 0;
|
|
maxAllowedSpread = 25;
|
|
maxAllowedPositions = 5;
|
|
closeAllOpenTradesAt = "";
|
|
isForceCloseAtTime = false;
|
|
restrictionsPeriod = XTRADE_RESTRICATION_NONE;
|
|
|
|
//
|
|
ZeroMemory(this);
|
|
}
|
|
|
|
/**
|
|
* Initial ...
|
|
*
|
|
* @param _symbol: Trading Symbol
|
|
* @param _period: Trading Period
|
|
* @param _sessionsDescriptor: Sessions Description
|
|
* @param _maxAllowedSpread: Max Allowed Spread for Open Trade
|
|
* @param _maxAllowedPositions: Max Allowed Same Time Position
|
|
* @param _restrictionsDescriptor: Restrictions Descriptor
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Init(
|
|
string _name,
|
|
string _symbol = NULL,
|
|
ENUM_TIMEFRAMES _period = NULL,
|
|
string _sessionsDescriptor = NULL,
|
|
double _maxAllowedSpread = 25,
|
|
int _maxAllowedPositions = 5,
|
|
string _restrictionsDescriptor = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize Symbol ...
|
|
_symbol = NormalizeSymbol(_symbol);
|
|
_period = NormalizePeriod(_period);
|
|
|
|
//
|
|
name = _name;
|
|
symbol = _symbol;
|
|
period = _period;
|
|
maxAllowedSpread = _maxAllowedSpread;
|
|
maxAllowedPositions = _maxAllowedPositions;
|
|
|
|
//
|
|
// Parse Sessions ...
|
|
ParseSessions(_sessionsDescriptor);
|
|
|
|
//
|
|
// Parse Restrictions ...
|
|
ParseRestrictions(_restrictionsDescriptor);
|
|
|
|
//
|
|
// Check Validation ...
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Same ...
|
|
bool IsSame(XSymbolTradeConfig &dest)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate ...
|
|
result = IsValid() &&
|
|
dest.IsValid() &&
|
|
name == dest.name &&
|
|
symbol == dest.symbol &&
|
|
period == dest.period;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
IsSpecifiedValid(name) &&
|
|
IsSpecifiedValid(symbol) &&
|
|
IsSpecifiedValid(period);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Allow Trade in Active Sessions ...
|
|
bool CanTrade(datetime time = NULL)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize Args ...
|
|
time = NormalizeTime(time);
|
|
|
|
//
|
|
// Validating ...
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// if there is not any defined sessions for Symbol ...
|
|
// it's allow Trading in all times ...
|
|
result = !HasChild(sessions);
|
|
if (result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Detect an Active Session ...
|
|
int count = ArraySize(sessions);
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
result = sessions[i].IsActive(time);
|
|
if (result)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Checking Restrictions ...
|
|
bool IsRestricted(datetime time = NULL)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize Time ...
|
|
time = NormalizeTime(time);
|
|
|
|
//
|
|
// Check Has Restrictions ...
|
|
bool has = HasRestrictions(restrictionsPeriod);
|
|
result = !has;
|
|
if (result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Restrictions Time ...
|
|
has = IsSpecifiedValid(managedStart) &&
|
|
time <= managedStart;
|
|
result = !has;
|
|
if (result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Restrictions Timing ...
|
|
// Check Restrictions ...
|
|
|
|
//
|
|
bool isTPAllowed = maxAllowedTPs == 0
|
|
? true
|
|
: managedTPs < maxAllowedTPs;
|
|
bool isSLAllowed = maxAllowedSLs == 0
|
|
? true
|
|
: managedSLs < maxAllowedSLs;
|
|
bool isTradeAllowed = maxAllowedTrades == 0
|
|
? true
|
|
: managedTrades < maxAllowedTrades;
|
|
|
|
//
|
|
result = isTPAllowed &&
|
|
isSLAllowed &&
|
|
isTradeAllowed;
|
|
if (result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Restrictions Reset ...
|
|
HandleRestrictions();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Parse Sessions ...
|
|
void ParseSessions(string descriptor)
|
|
{
|
|
//
|
|
// Validate ...
|
|
if (!IsSpecifiedValid(descriptor))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
bool has = false;
|
|
string _sessions[];
|
|
int sessionsCount = 0;
|
|
|
|
//
|
|
// Extract Per Symbol Sessions ...
|
|
sessionsCount = SplitContent(
|
|
_sessions,
|
|
descriptor,
|
|
"," //
|
|
);
|
|
|
|
//
|
|
// Try to Extract Start and End Times Series ...
|
|
has = IsValidSize(sessionsCount);
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Iterate Sessions ...
|
|
for (int i = 0; i < sessionsCount; i++)
|
|
{
|
|
//
|
|
// Ignore unused Cases and Extracts only Content ...
|
|
string iSessionDescriptorStr = ExtractString(_sessions[i]);
|
|
has = IsSpecifiedValid(iSessionDescriptorStr);
|
|
if (has)
|
|
{
|
|
//
|
|
// Extract Session Descriptor Data ...
|
|
string parts[];
|
|
int partsCount = SplitContent(
|
|
parts,
|
|
iSessionDescriptorStr,
|
|
"_" //
|
|
);
|
|
has = IsValidSize(partsCount) && partsCount == 3;
|
|
if (has)
|
|
{
|
|
//
|
|
string iName = parts[0];
|
|
string iStart = parts[1];
|
|
string iEnd = parts[2];
|
|
has = IsSpecifiedValid(iName) &&
|
|
IsSpecifiedValid(iStart) &&
|
|
IsSpecifiedValid(iEnd);
|
|
if (has)
|
|
{
|
|
//
|
|
// Set Active Session Per Symbols ...
|
|
XTradeSession session;
|
|
|
|
//
|
|
session.end = iEnd;
|
|
session.name = iName;
|
|
session.start = iStart;
|
|
|
|
//
|
|
AddRef(
|
|
session,
|
|
sessions //
|
|
);
|
|
|
|
//
|
|
session.Clean();
|
|
}
|
|
}
|
|
|
|
//
|
|
SpecifiedClean(parts);
|
|
}
|
|
}
|
|
|
|
//
|
|
SpecifiedClean(_sessions);
|
|
}
|
|
|
|
//
|
|
// Parse Restrictions ...
|
|
void ParseRestrictions(string descriptor)
|
|
{
|
|
//
|
|
// Validate ...
|
|
if (!IsSpecifiedValid(descriptor))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Extract Content ...
|
|
descriptor = ExtractString(descriptor);
|
|
if (!IsSpecifiedValid(descriptor))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int count = 0;
|
|
bool has = false;
|
|
string iRestrictionsParts[];
|
|
|
|
//
|
|
// Extract Parts ...
|
|
count = SplitContent(
|
|
iRestrictionsParts,
|
|
descriptor,
|
|
"," //
|
|
);
|
|
has = IsValidSize(count);
|
|
if (!has)
|
|
{
|
|
//
|
|
// Default Restrictions ...
|
|
ApplyDefaultRestrictions();
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Try To Extract Required Parts ...
|
|
bool hasRestrictionsPeriod = count >= 1;
|
|
bool hasRestrictionsPeriodMultiplier = count >= 2;
|
|
bool hasMaxAllowedTPs = count >= 3;
|
|
bool hasMaxAllowedSLs = count >= 4;
|
|
bool hasMaxAllowedTrades = count >= 5;
|
|
bool hasCloseAllOpenTradesAt = count >= 6;
|
|
|
|
//
|
|
// Restrictions Period ...
|
|
restrictionsPeriod =
|
|
hasRestrictionsPeriod
|
|
? ToXRestrictionPeriod(Trim(iRestrictionsParts[0]))
|
|
: XTRADE_RESTRICATION_NONE;
|
|
|
|
//
|
|
// Restrictions Period Multiplier ...
|
|
restrictionsPeriodMultiplier =
|
|
hasRestrictionsPeriodMultiplier
|
|
? (int)(Trim(iRestrictionsParts[1]))
|
|
: 1;
|
|
|
|
//
|
|
// Max Allowed TPs ...
|
|
maxAllowedTPs =
|
|
hasMaxAllowedTPs
|
|
? (int)(Trim(iRestrictionsParts[2]))
|
|
: 0;
|
|
|
|
//
|
|
// Max Allowed SLs ...
|
|
maxAllowedSLs =
|
|
hasMaxAllowedSLs
|
|
? (int)(Trim(iRestrictionsParts[3]))
|
|
: 0;
|
|
|
|
//
|
|
// Max Allowed Trades ...
|
|
maxAllowedTrades =
|
|
hasMaxAllowedTrades
|
|
? (int)(Trim(iRestrictionsParts[4]))
|
|
: 0;
|
|
|
|
//
|
|
// Close All Open Trades At ...
|
|
closeAllOpenTradesAt =
|
|
hasCloseAllOpenTradesAt
|
|
? Trim(iRestrictionsParts[5])
|
|
: NULL;
|
|
}
|
|
|
|
//
|
|
// Apply Default Restrictions ...
|
|
void ApplyDefaultRestrictions()
|
|
{
|
|
//
|
|
maxAllowedTPs = 0;
|
|
maxAllowedSLs = 0;
|
|
maxAllowedTrades = 0;
|
|
closeAllOpenTradesAt = NULL;
|
|
restrictionsPeriod = XTRADE_RESTRICATION_NONE;
|
|
}
|
|
|
|
//
|
|
// Handle Restrictions ...
|
|
void HandleRestrictions(datetime time = NULL)
|
|
{
|
|
//
|
|
// Normalize Time ...
|
|
time = NormalizeTime(time);
|
|
|
|
//
|
|
// Check Restrictions Requirements ...
|
|
bool has = HasRestrictions(restrictionsPeriod) &&
|
|
restrictionsPeriodMultiplier >= 1;
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check Restrictions Start ...
|
|
has = IsSpecifiedValid(managedStart);
|
|
if (!has)
|
|
{
|
|
managedStart = time;
|
|
}
|
|
|
|
//
|
|
// Calculating Expiration Date based on Config ...
|
|
int expiredDelay = restrictionsPeriodMultiplier * GetXRestrictionsPeriodSeconds(restrictionsPeriod);
|
|
datetime expiredDate = (datetime)(TimeToSeconds(managedStart) + expiredDelay);
|
|
|
|
//
|
|
// Check Expiration ...
|
|
has = time >= expiredDate;
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
ResetRestrictions();
|
|
}
|
|
|
|
//
|
|
// Reset Restrictions ...
|
|
void ResetRestrictions()
|
|
{
|
|
//
|
|
managedSLs = 0;
|
|
managedTPs = 0;
|
|
managedTrades = 0;
|
|
managedBalance = 0;
|
|
managedProfits = 0;
|
|
managedStart = TimeCurrent();
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// an Structure to Describe a Trade ...
|
|
struct XTradeInfo
|
|
{
|
|
//
|
|
// Props ...
|
|
double swap;
|
|
double profit;
|
|
XSignal signal;
|
|
ulong positionID;
|
|
double commission;
|
|
string conditions;
|
|
double bullishScore;
|
|
double bearishScore;
|
|
ENUM_XTRADE_FINALIZATION finalize;
|
|
|
|
//
|
|
datetime signaledAt;
|
|
datetime executedAt;
|
|
datetime finalizedAt;
|
|
|
|
//
|
|
// Constructor ...
|
|
XTradeInfo()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Cleanup Model ...
|
|
*/
|
|
void Clean()
|
|
{
|
|
//
|
|
swap = 0;
|
|
profit = 0;
|
|
signal.Clean();
|
|
commission = 0;
|
|
positionID = 0;
|
|
conditions = NULL;
|
|
bullishScore = 0;
|
|
bearishScore = 0;
|
|
finalize = XTRADE_FINAL_NONE;
|
|
|
|
//
|
|
signaledAt = NULL;
|
|
executedAt = NULL;
|
|
finalizedAt = NULL;
|
|
|
|
//
|
|
ZeroMemory(this);
|
|
}
|
|
|
|
/**
|
|
* Check Has Signal ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasSignal()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = signal.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Signal Executed or Not ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsExecuted()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = positionID > 0;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check a Trade is Finalized or not ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsFinalized()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = HasSignal() &&
|
|
IsExecuted() &&
|
|
finalize != XTRADE_FINAL_NONE;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Generate Summary Info ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string Summary()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
result =
|
|
//
|
|
ToXString("Swap", swap) +
|
|
ToXString("Profit", profit) +
|
|
ToXString("Commission", commission) +
|
|
ToXString("Finalize", ToXString(finalize)) +
|
|
ToXString("PositionID", positionID) +
|
|
ToXString("----------------") + "\n" +
|
|
ToXString("Signaled At", ToFormatString(signaledAt)) +
|
|
ToXString("Executed At", ToFormatString(executedAt)) +
|
|
ToXString("Finalized At", ToFormatString(finalizedAt))
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get Data Collection File Name ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string GetFileName()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
bool hasSignal = HasSignal();
|
|
bool isExecuted = IsExecuted();
|
|
bool isFinalized = IsFinalized();
|
|
if (!hasSignal && !isExecuted && !isFinalized)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
signal.symbol + "\\" +
|
|
ToString(signal.type) + "\\" +
|
|
(profit >= 0 ? "Profit" : "Loss") + "\\" +
|
|
ToString(positionID) + "_" +
|
|
ToString(signal.period) + "_" +
|
|
ToFormatString(signaledAt)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Converts Model to String Representation ...
|
|
*
|
|
* @param onlySignals: Boolean, Specified Represent Only Signal or not ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string ToString(
|
|
bool includeSummary = true,
|
|
bool includeSignal = true,
|
|
bool includeConditions = true //
|
|
)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
// Generating Model Summary ...
|
|
string summary = Summary();
|
|
|
|
//
|
|
// Generating Signal Summary ...
|
|
string signalSummary = signal.ToString();
|
|
|
|
//
|
|
if (includeSummary)
|
|
{
|
|
//
|
|
result +=
|
|
ToXString("----------------") + "\n" +
|
|
ToXString("Summary: ") + "\n" +
|
|
ToXString("----------------") + "\n" +
|
|
summary + "\n";
|
|
}
|
|
|
|
//
|
|
if (includeSignal)
|
|
{
|
|
//
|
|
result +=
|
|
ToXString("----------------") + "\n" +
|
|
ToXString("Signal: ") + "\n" +
|
|
ToXString("----------------") + "\n" +
|
|
signalSummary + "\n";
|
|
}
|
|
|
|
//
|
|
if (includeConditions)
|
|
{
|
|
//
|
|
result +=
|
|
ToXString("----------------") + "\n" +
|
|
ToXString("Conditions: ") + "\n" +
|
|
ToXString("----------------") + "\n" +
|
|
conditions + "\n";
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
string GetConditionsString()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
string conditionsStr =
|
|
conditions;
|
|
string condParts[];
|
|
int condPartsCount = SplitContent(
|
|
condParts,
|
|
conditionsStr,
|
|
"\n" //
|
|
);
|
|
if (IsValidSize(condPartsCount))
|
|
{
|
|
//
|
|
conditionsStr = NULL;
|
|
while (HasChild(condParts))
|
|
{
|
|
//
|
|
string iStr = condParts[0];
|
|
ArrayRemove(
|
|
condParts,
|
|
0,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
bool isLast = !HasChild(condParts);
|
|
|
|
//
|
|
bool isCond = Contains(
|
|
"is",
|
|
iStr,
|
|
false //
|
|
);
|
|
if (isCond)
|
|
{
|
|
//
|
|
string iParts[];
|
|
int iPartsCount = SplitContent(
|
|
iParts,
|
|
iStr,
|
|
":" //
|
|
);
|
|
if (iPartsCount == 2)
|
|
{
|
|
//
|
|
string iVal = iParts[1];
|
|
StringTrimLeft(iVal);
|
|
StringTrimRight(iVal);
|
|
bool isPassed = ToBoolean(iVal);
|
|
conditionsStr += (isPassed ? "" : "!") + "conditions." + iParts[0] + (!isLast ? " &&" : "") + "\n";
|
|
}
|
|
}
|
|
}
|
|
SpecifiedClean(condParts);
|
|
}
|
|
else
|
|
{
|
|
conditionsStr = NULL;
|
|
}
|
|
|
|
//
|
|
result =
|
|
"(" + "\n" +
|
|
"\\" + "\\" + " " + ToXString("Type", ToXString(signal.type)) +
|
|
"\\" + "\\" + " " + ToXString("Profit", profit) +
|
|
"\\" + "\\" + " " + ToXString("Finalize", ToXString(finalize)) +
|
|
"\\" + "\\" + " " + ToXString("PositionID", positionID) +
|
|
"\\" + "\\" + " " + ToXString("----------------") + "\n" +
|
|
"\\" + "\\" + " " + ToXString("Signaled At", ToFormatString(signaledAt)) +
|
|
"\\" + "\\" + " " + ToXString("Executed At", ToFormatString(executedAt)) +
|
|
"\\" + "\\" + " " + ToXString("Finalized At", ToFormatString(finalizedAt)) +
|
|
"\\" + "\\" + " " + ToXString("----------------") + "\n" +
|
|
"\\" + "\\" + " " + ToXString("Scores:") + "\n" +
|
|
"\\" + "\\" + " " + ToXString("Bullish", bullishScore) +
|
|
"\\" + "\\" + " " + ToXString("Bearish", bearishScore) +
|
|
"\\" + "\\" + " " + ToXString("----------------") + "\n" +
|
|
conditionsStr +
|
|
(IsValid(conditionsStr) ? "" : "") +
|
|
") && ";
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// TypeDefs ...
|
|
|
|
//
|
|
typedef void (*TOnSignal)(XSignal &signal);
|
|
|
|
//
|
|
typedef bool (*TCanAnalyse)(
|
|
string _symbol,
|
|
ENUM_TIMEFRAMES _period,
|
|
datetime _time //
|
|
);
|
|
|
|
//
|
|
// an Event Type for Notify Guard Triggered ...
|
|
typedef void (*TOnGuarded)(
|
|
ENUM_X_GUARD_ACTIONS guard,
|
|
XPosition &positions[]);
|
|
|
|
//
|
|
typedef int (*TCheckForGuard)(
|
|
XGuard &guards[],
|
|
XPosition &positions[],
|
|
int barIndex = 0 //
|
|
);
|
|
|
|
//
|
|
typedef void (*TOnDealsChanged)(int count);
|
|
|
|
//
|
|
typedef void (*TOnOrdersChanged)(int count);
|
|
|
|
//
|
|
typedef void (*TOnPositionsChanged)(int count);
|
|
|
|
//
|
|
typedef void (*TOnStopLoss)(const XDeal &deal);
|
|
typedef void (*TOnTakeProfit)(const XDeal &deal);
|
|
|
|
//
|
|
typedef void (*TOnTradeStateChanged)(const XOnTradeHandlerState &state);
|
|
|
|
//
|
|
typedef void (*TOnForceClose)(
|
|
const ulong ticket,
|
|
const XPosition &position,
|
|
const string comment //
|
|
);
|
|
|
|
//
|
|
typedef void (*TOnPartialClose)(
|
|
const ulong ticket,
|
|
const double profit,
|
|
const string comment //
|
|
);
|
|
|
|
//
|
|
typedef void (*TOnModify)(
|
|
const ulong ticket,
|
|
const double profit,
|
|
const string comment //
|
|
);
|
|
|
|
//
|
|
// Classes ...
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
bool IsValid(ENUM_X_ORDER_MODES value)
|
|
{
|
|
return value != X_ORDER_MODE_NOTHING;
|
|
}
|
|
|
|
//
|
|
// Ages ...
|
|
|
|
//
|
|
// Retrieve a Position Age ...
|
|
int GetAge(
|
|
XSignal &signal, // Selected Signal ...
|
|
ENUM_TIMEFRAMES period = NULL // Dest Time Frame ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (period == NULL)
|
|
{
|
|
period = _Period;
|
|
}
|
|
|
|
//
|
|
result = iBarShift(
|
|
signal.symbol,
|
|
period,
|
|
signal.time);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
int GetXAge(
|
|
XSignal &signal, // Selected Signal ...
|
|
ENUM_TIMEFRAMES period = NULL // Dest Time Frame ...
|
|
)
|
|
{
|
|
return GetAge(signal, period);
|
|
}
|
|
|
|
//
|
|
// Retrieve a Position Age ...
|
|
int GetAge(
|
|
XPosition &position, // Selected Position ...
|
|
ENUM_TIMEFRAMES period = NULL // Dest Time Frame ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (period == NULL)
|
|
{
|
|
period = _Period;
|
|
}
|
|
|
|
//
|
|
result = iBarShift(
|
|
position.symbol,
|
|
period,
|
|
position.openAt);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
int GetXAge(
|
|
XPosition &position, // Selected Position ...
|
|
ENUM_TIMEFRAMES period = NULL // Dest Time Frame ...
|
|
)
|
|
{
|
|
return GetAge(position, period);
|
|
}
|
|
|
|
//
|
|
// Retrieve an Order Age ...
|
|
int GetAge(
|
|
XOrder &order, // Selected Order ...
|
|
ENUM_TIMEFRAMES period = NULL // Dest Time Frame ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (period == NULL)
|
|
{
|
|
period = _Period;
|
|
}
|
|
|
|
//
|
|
result = iBarShift(
|
|
order.symbol,
|
|
period,
|
|
order.setupAt);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
int GetXAge(
|
|
XOrder &order, // Selected Order ...
|
|
ENUM_TIMEFRAMES period = NULL // Dest Time Frame ...
|
|
)
|
|
{
|
|
return GetAge(order, period);
|
|
}
|
|
|
|
//
|
|
// Retrieve a Deal Age ...
|
|
int GetAge(
|
|
XDeal &deal, // Selected Deal ...
|
|
ENUM_TIMEFRAMES period = NULL // Dest Time Frame ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (period == NULL)
|
|
{
|
|
period = _Period;
|
|
}
|
|
|
|
//
|
|
result = iBarShift(
|
|
deal.symbol,
|
|
period,
|
|
deal.time);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
int GetXAge(
|
|
XDeal &deal, // Selected Deal ...
|
|
ENUM_TIMEFRAMES period = NULL // Dest Time Frame ...
|
|
)
|
|
{
|
|
return GetAge(deal, period);
|
|
}
|
|
|
|
//
|
|
// Get Oldest Deal ...
|
|
int GetOldest(
|
|
XDeal &item, // Hold Result ...
|
|
XDeal &items[] // Source Array ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int itemsCount = ArraySize(items);
|
|
if (itemsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int tmpAge = 0;
|
|
XDeal tmpItem;
|
|
for (int i = 0; i < itemsCount; i++)
|
|
{
|
|
//
|
|
XDeal iItem = items[i];
|
|
|
|
//
|
|
int iAge = GetAge(iItem);
|
|
if (iAge > 0 &&
|
|
(tmpAge == 0 || tmpAge < iAge))
|
|
{
|
|
//
|
|
tmpAge = iAge;
|
|
tmpItem = iItem;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (tmpAge > 0)
|
|
{
|
|
//
|
|
result = tmpAge;
|
|
item = tmpItem;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
int GetXOldest(
|
|
XDeal &item, // Hold Result ...
|
|
XDeal &items[] // Source Array ...
|
|
)
|
|
{
|
|
return GetOldest(item, items);
|
|
}
|
|
|
|
//
|
|
// Get Youngest Deal ...
|
|
int GetYoungest(
|
|
XDeal &item, // Hold Result ...
|
|
XDeal &items[] // Source Array ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int itemsCount = ArraySize(items);
|
|
if (itemsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int tmpAge = 0;
|
|
XDeal tmpItem;
|
|
for (int i = 0; i < itemsCount; i++)
|
|
{
|
|
//
|
|
XDeal iItem = items[i];
|
|
|
|
//
|
|
int iAge = GetAge(iItem);
|
|
if (iAge > 0 &&
|
|
(tmpAge == 0 || tmpAge > iAge))
|
|
{
|
|
//
|
|
tmpAge = iAge;
|
|
tmpItem = iItem;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (tmpAge > 0)
|
|
{
|
|
//
|
|
result = tmpAge;
|
|
item = tmpItem;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
int GetXYoungest(
|
|
XDeal &item, // Hold Result ...
|
|
XDeal &items[] // Source Array ...
|
|
)
|
|
{
|
|
return GetYoungest(item, items);
|
|
}
|
|
|
|
//
|
|
// Get Oldest Order ...
|
|
int GetOldest(
|
|
XOrder &item, // Hold Result ...
|
|
XOrder &items[] // Source Array ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int itemsCount = ArraySize(items);
|
|
if (itemsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int tmpAge = 0;
|
|
XOrder tmpItem;
|
|
for (int i = 0; i < itemsCount; i++)
|
|
{
|
|
//
|
|
XOrder iItem = items[i];
|
|
|
|
//
|
|
int iAge = GetAge(iItem);
|
|
if (iAge > 0 &&
|
|
(tmpAge == 0 || tmpAge < iAge))
|
|
{
|
|
//
|
|
tmpAge = iAge;
|
|
tmpItem = iItem;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (tmpAge > 0)
|
|
{
|
|
//
|
|
result = tmpAge;
|
|
item = tmpItem;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
int GetXOldest(
|
|
XOrder &item, // Hold Result ...
|
|
XOrder &items[] // Source Array ...
|
|
)
|
|
{
|
|
return GetOldest(item, items);
|
|
}
|
|
|
|
//
|
|
// Get Youngest Order ...
|
|
int GetYoungest(
|
|
XOrder &item, // Hold Result ...
|
|
XOrder &items[] // Source Array ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int itemsCount = ArraySize(items);
|
|
if (itemsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int tmpAge = 0;
|
|
XOrder tmpItem;
|
|
for (int i = 0; i < itemsCount; i++)
|
|
{
|
|
//
|
|
XOrder iItem = items[i];
|
|
|
|
//
|
|
int iAge = GetAge(iItem);
|
|
if (iAge > 0 &&
|
|
(tmpAge == 0 || tmpAge > iAge))
|
|
{
|
|
//
|
|
tmpAge = iAge;
|
|
tmpItem = iItem;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (tmpAge > 0)
|
|
{
|
|
//
|
|
result = tmpAge;
|
|
item = tmpItem;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
int GetXYoungest(
|
|
XOrder &item, // Hold Result ...
|
|
XOrder &items[] // Source Array ...
|
|
)
|
|
{
|
|
return GetYoungest(item, items);
|
|
}
|
|
|
|
//
|
|
// Get Oldes Position ...
|
|
int GetOldest(
|
|
XPosition &item, // Hold Result ...
|
|
XPosition &items[] // Source Array ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int itemsCount = ArraySize(items);
|
|
if (itemsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int tmpAge = 0;
|
|
XPosition tmpItem;
|
|
for (int i = 0; i < itemsCount; i++)
|
|
{
|
|
//
|
|
XPosition iItem = items[i];
|
|
|
|
//
|
|
int iAge = GetAge(iItem);
|
|
if (iAge > 0 &&
|
|
(tmpAge == 0 || tmpAge < iAge))
|
|
{
|
|
//
|
|
tmpAge = iAge;
|
|
tmpItem = iItem;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (tmpAge > 0)
|
|
{
|
|
//
|
|
result = tmpAge;
|
|
item = tmpItem;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
int GetXOldest(
|
|
XPosition &item, // Hold Result ...
|
|
XPosition &items[] // Source Array ...
|
|
)
|
|
{
|
|
return GetOldest(item, items);
|
|
}
|
|
|
|
//
|
|
// Get Youngest Position ...
|
|
int GetYoungest(
|
|
XPosition &item, // Hold Result ...
|
|
XPosition &items[] // Source Array ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int itemsCount = ArraySize(items);
|
|
if (itemsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int tmpAge = 0;
|
|
XPosition tmpItem;
|
|
for (int i = 0; i < itemsCount; i++)
|
|
{
|
|
//
|
|
XPosition iItem = items[i];
|
|
|
|
//
|
|
int iAge = GetAge(iItem);
|
|
if (iAge >= 0 &&
|
|
(tmpAge == 0 || tmpAge > iAge))
|
|
{
|
|
//
|
|
tmpAge = iAge;
|
|
tmpItem = iItem;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (tmpAge >= 0)
|
|
{
|
|
//
|
|
result = tmpAge;
|
|
item = tmpItem;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
int GetXYoungest(
|
|
XPosition &item, // Hold Result ...
|
|
XPosition &items[] // Source Array ...
|
|
)
|
|
{
|
|
return GetYoungest(item, items);
|
|
}
|
|
|
|
//
|
|
int FindMaxProfitIndex(
|
|
XPosition &positions[] // Position Collection
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double max = 0;
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
if (iPosition.profit <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
if (max == 0 ||
|
|
max < iPosition.profit)
|
|
{
|
|
//
|
|
result = i;
|
|
max = iPosition.profit;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int FindMinProfitIndex(
|
|
XPosition &positions[] // Position Collection
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double min = 0;
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
if (iPosition.profit <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
if (min == 0 ||
|
|
min > iPosition.profit)
|
|
{
|
|
//
|
|
result = i;
|
|
min = iPosition.profit;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int ExtractInProfitPositions(
|
|
XPosition &positions[], // Position Collection
|
|
XPosition &inProfits[] // Result
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(inProfits);
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
if (iPosition.profit > 0)
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
inProfits //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(inProfits);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int FindMaxDrawdownIndex(
|
|
XPosition &positions[] // Position Collection
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double max = 0;
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
if (iPosition.profit >= 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
if (max == 0 ||
|
|
MathAbs(max) < MathAbs(iPosition.profit))
|
|
{
|
|
//
|
|
result = i;
|
|
max = iPosition.profit;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int FindMinDrawdownIndex(
|
|
XPosition &positions[] // Position Collection
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double min = 0;
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
if (iPosition.profit >= 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
if (min == 0 ||
|
|
min > iPosition.profit)
|
|
{
|
|
//
|
|
result = i;
|
|
min = iPosition.profit;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int ExtractInDrawdownPositions(
|
|
XPosition &positions[], // Position Collection
|
|
XPosition &inDradowns[] // Result
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(inDradowns);
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
if (iPosition.profit < 0)
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
inDradowns //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(inDradowns);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Filters ...
|
|
|
|
//
|
|
// Magic Filter ...
|
|
template <typename T>
|
|
bool IsMagicFilterPassed(
|
|
ulong magic,
|
|
bool filterByMagic,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return !filterByMagic
|
|
? true
|
|
: !NotEmpty(magic)
|
|
? false
|
|
: magic == item.magic;
|
|
}
|
|
|
|
//
|
|
// Symbol Filter ...
|
|
template <typename T>
|
|
bool IsSymbolFilterPassed(
|
|
string symbol,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return !IsValid(symbol)
|
|
? true
|
|
: symbol == item.symbol;
|
|
}
|
|
|
|
//
|
|
// Provider Filter ...
|
|
template <typename T>
|
|
bool IsProviderFilterPassed(
|
|
string provider,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return !IsValid(provider)
|
|
? true
|
|
: provider == item.provider;
|
|
}
|
|
|
|
//
|
|
// Period Filter ...
|
|
template <typename T>
|
|
bool IsPeriodFilterPassed(
|
|
ENUM_TIMEFRAMES period,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return !IsValid(period)
|
|
? true
|
|
: period == item.period;
|
|
}
|
|
|
|
//
|
|
// Type Filter ...
|
|
template <typename T>
|
|
bool IsTypeFilterPassed(
|
|
ENUM_POSITION_TYPE type,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
bool result = type == item.type;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
template <typename T>
|
|
bool IsTypeFilterPassed(
|
|
ENUM_X_POSITION_TYPES type,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
bool result = type == NULL || type == X_POSITION_TYPE_ALL
|
|
? true
|
|
: ((type == X_POSITION_TYPE_LONG && ((int)item.type == (int)POSITION_TYPE_BUY || (int)item.type == (int)ORDER_TYPE_BUY)) ||
|
|
(type == X_POSITION_TYPE_SHORT && ((int)item.type == (int)POSITION_TYPE_SELL || (int)item.type == (int)ORDER_TYPE_SELL)));
|
|
|
|
//
|
|
return result;
|
|
}
|
|
template <typename T>
|
|
bool IsTypeFilterPassed(
|
|
ENUM_ORDER_TYPE type,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return type == NULL
|
|
? true
|
|
: type == item.type;
|
|
}
|
|
template <typename T>
|
|
bool IsTypeFilterPassed(
|
|
ENUM_DEAL_TYPE type,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return type == NULL
|
|
? true
|
|
: type == item.type;
|
|
}
|
|
|
|
//
|
|
// Mode Filter ...
|
|
template <typename T>
|
|
bool IsModeFilterPassed(
|
|
ENUM_X_ORDER_MODES mode,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return mode == NULL
|
|
? true
|
|
: mode == item.mode;
|
|
}
|
|
|
|
//
|
|
// Entry Filter ...
|
|
template <typename T>
|
|
bool IsEntryFilterPassed(
|
|
ENUM_DEAL_ENTRY entry,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return entry == NULL
|
|
? true
|
|
: entry == item.entry;
|
|
}
|
|
|
|
//
|
|
// Reason Filter ...
|
|
template <typename T>
|
|
bool IsReasonFilterPassed(
|
|
ENUM_DEAL_REASON reason,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return reason == NULL
|
|
? true
|
|
: reason == item.reason;
|
|
}
|
|
|
|
//
|
|
// State Filter ...
|
|
template <typename T>
|
|
bool IsStateFilterPassed(
|
|
ENUM_ORDER_STATE state,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return state == NULL
|
|
? true
|
|
: state == item.state;
|
|
}
|
|
|
|
//
|
|
|
|
//
|
|
//
|
|
// Calculate Positions Profit Summary ...
|
|
double SpecifiedCalculatePositionsProfit(
|
|
XPosition &positions[] // Source
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (positionsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
result += iPosition.profit;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Required Profit for Hedging ...
|
|
double SpecifiedCalculateRequiredProfitForHedge(
|
|
XPosition &positions[], // Source
|
|
double mMinProfitPerTrade,
|
|
double mMinProfitPerVolumeFactor //
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (positionsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isHedgingEnable = mMinProfitPerTrade > 0 && mMinProfitPerVolumeFactor > 0;
|
|
if (!isHedgingEnable)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
if (mMinProfitPerTrade > 0 && mMinProfitPerVolumeFactor > 0)
|
|
{
|
|
//
|
|
result +=
|
|
((iPosition.volume / mMinProfitPerVolumeFactor) *
|
|
mMinProfitPerTrade) +
|
|
(-1 * iPosition.swap);
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool SpecifiedIsPositionsReadyForHedge(
|
|
XPosition &positions[], // Source
|
|
double mMinProfitPerTrade,
|
|
double mMinProfitPerVolumeFactor //
|
|
)
|
|
{
|
|
//
|
|
double profit = SpecifiedCalculatePositionsProfit(positions);
|
|
double requiredProfit = SpecifiedCalculateRequiredProfitForHedge(
|
|
positions,
|
|
mMinProfitPerTrade,
|
|
mMinProfitPerVolumeFactor //
|
|
);
|
|
|
|
//
|
|
bool result = requiredProfit > 0
|
|
? profit >= requiredProfit
|
|
: profit > requiredProfit;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int FindCoverageDrawdownPosition(
|
|
XPosition &position, // In Drawdown Position
|
|
XPosition &inProfits[], // In Profit Positions
|
|
XPosition &coverage[], // Coverage Positons
|
|
double mMinProfitPerTrade,
|
|
double mMinProfitPerVolumeFactor //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(coverage);
|
|
|
|
//
|
|
if (!position.IsValid() || position.profit >= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int inProfitsCount = ArraySize(inProfits);
|
|
if (!IsValidSize(inProfitsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Copy in Profits to TMP ...
|
|
XPosition tmp[];
|
|
Copy(
|
|
inProfits,
|
|
tmp //
|
|
);
|
|
|
|
//
|
|
bool isCoverPassed = false;
|
|
while (!isCoverPassed || ArraySize(tmp) > 0)
|
|
{
|
|
//
|
|
XPosition max;
|
|
int idx = FindMaxProfitIndex(tmp);
|
|
if (idx >= 0)
|
|
{
|
|
//
|
|
if (tmp[idx].profit > 0)
|
|
{
|
|
AddRef(
|
|
tmp[idx],
|
|
coverage //
|
|
);
|
|
|
|
//
|
|
ArrayRemove(
|
|
tmp,
|
|
idx,
|
|
1 //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check Cover Passed ...
|
|
XPosition tmpPositions[];
|
|
Copy(
|
|
coverage,
|
|
tmpPositions //
|
|
);
|
|
AddRef(
|
|
position,
|
|
tmpPositions //
|
|
);
|
|
|
|
//
|
|
double profits = SpecifiedCalculatePositionsProfit(tmpPositions);
|
|
double requiredProfit = SpecifiedCalculateRequiredProfitForHedge(
|
|
tmpPositions,
|
|
mMinProfitPerTrade,
|
|
mMinProfitPerVolumeFactor //
|
|
);
|
|
isCoverPassed = profits >= requiredProfit;
|
|
if (isCoverPassed)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
if (!isCoverPassed && ArraySize(tmp) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(coverage);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Extract a Collection of Positions SL ...
|
|
int ExtractSLs(
|
|
XPosition &positions[],
|
|
double &sls[] //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(sls);
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
if (iPosition.sl > 0)
|
|
{
|
|
//
|
|
Add(
|
|
iPosition.sl,
|
|
sls //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(sls);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Extract a Colletion of Positions TP ...
|
|
int ExtractTPs(
|
|
XPosition &positions[],
|
|
double &tps[] //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(tps);
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
if (iPosition.tp > 0)
|
|
{
|
|
//
|
|
Add(
|
|
iPosition.tp,
|
|
tps //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(tps);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve String Representation ...
|
|
string ToString(ENUM_X_SIGNAL_EXECUTION_RESULT value)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
switch (value)
|
|
{
|
|
//
|
|
case X_SIGNAL_EXECUTION_UNKNOWN:
|
|
result = "Unknown";
|
|
break;
|
|
|
|
//
|
|
case X_SIGNAL_EXECUTION_SUCCEED:
|
|
result = "Succed";
|
|
break;
|
|
|
|
//
|
|
case X_SIGNAL_EXECUTION_FAILED_SPREAD:
|
|
result = "Spread more than Max Allowed";
|
|
break;
|
|
|
|
//
|
|
case X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED:
|
|
result = "not Allowed";
|
|
break;
|
|
|
|
//
|
|
case X_SIGNAL_EXECUTION_FAILED_NO_EQUITY:
|
|
result = "No Equity for Trade";
|
|
break;
|
|
|
|
//
|
|
case X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR:
|
|
result = "Price Error";
|
|
break;
|
|
|
|
//
|
|
case X_SIGNAL_EXECUTION_FAILED_PREV_PROFIT_ERROR:
|
|
result = "Previous Position Profit not Passed for Accept Next";
|
|
break;
|
|
|
|
//
|
|
case X_SIGNAL_EXECUTION_FAILED_MAX_REACHED:
|
|
result = "Max Allowed Positions Reached";
|
|
break;
|
|
|
|
//
|
|
case X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED:
|
|
result = "Min Delay Between to Signal not Passed";
|
|
break;
|
|
|
|
//
|
|
case X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS:
|
|
result = "Invalid Params";
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts Position Type to Order Type ...
|
|
ENUM_ORDER_TYPE ToOrderType(ENUM_POSITION_TYPE value)
|
|
{
|
|
//
|
|
bool isLong = IsLong(value);
|
|
|
|
//
|
|
ENUM_ORDER_TYPE result =
|
|
isLong
|
|
? ORDER_TYPE_BUY
|
|
: ORDER_TYPE_SELL;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
ENUM_ORDER_TYPE ToOrderType(ENUM_X_POSITION_TYPES value)
|
|
{
|
|
//
|
|
ENUM_POSITION_TYPE mType =
|
|
value == X_POSITION_TYPE_SHORT
|
|
? POSITION_TYPE_SELL
|
|
: POSITION_TYPE_BUY;
|
|
|
|
//
|
|
bool isLong = IsLong(mType);
|
|
|
|
//
|
|
ENUM_ORDER_TYPE result =
|
|
isLong
|
|
? ORDER_TYPE_BUY
|
|
: ORDER_TYPE_SELL;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tagging ...
|
|
|
|
//
|
|
// Generate Specified Tag for Using in Comments ...
|
|
string GeneratePeriodTag(ENUM_TIMEFRAMES period)
|
|
{
|
|
//
|
|
string strPeriod = ToXString(period);
|
|
return Surround(
|
|
XPeriodToken,
|
|
strPeriod
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Extract Period from a Tagged string ...
|
|
ENUM_TIMEFRAMES ExtractPeriod(string value)
|
|
{
|
|
//
|
|
ENUM_TIMEFRAMES result = NULL;
|
|
|
|
//
|
|
string pStr = ParseStringSurrounded(
|
|
value,
|
|
XPeriodToken
|
|
//
|
|
);
|
|
if (!IsValid(pStr))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ToPeriod(pStr);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
// Generate Specified Tag for Using in Comments ...
|
|
string GenerateProviderTag(string provider)
|
|
{
|
|
//
|
|
return Surround(
|
|
XProviderToken,
|
|
provider
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Extract Provider from a Tagged string ...
|
|
string ExtractProvider(string value)
|
|
{
|
|
//
|
|
return ParseStringSurrounded(
|
|
value,
|
|
XProviderToken
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Generate Support Comment Tag ...
|
|
string GenerateSupportTag(ulong ticket)
|
|
{
|
|
//
|
|
return Surround(
|
|
XSupportToken,
|
|
ticket
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Extract Support Positions from a Tagged string ...
|
|
ulong ExtractSupportedTicket(string value)
|
|
{
|
|
//
|
|
return ParseLongSurrounded(
|
|
value,
|
|
XSupportToken
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Extract Support ...
|
|
template <typename T>
|
|
int ExtractSupports(
|
|
T &source[],
|
|
T &dest[] // Result ...
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(dest);
|
|
|
|
//
|
|
int sourceCount = ArraySize(source);
|
|
if (!IsValidSize(sourceCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < sourceCount; i++)
|
|
{
|
|
//
|
|
T iSource = source[i];
|
|
|
|
//
|
|
ulong isSupport = ExtractSupportedTicket(iSource.comment) > 0;
|
|
ulong iEQMSupport = ExtractEQMSupportedTicket(iSource.comment) > 0;
|
|
if (isSupport || iEQMSupport)
|
|
{
|
|
//
|
|
AddRef(
|
|
iSource,
|
|
dest //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(dest);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Generate EQM Support Comment Tag ...
|
|
string GenerateEQMSupportTag(ulong ticket)
|
|
{
|
|
//
|
|
return Surround(
|
|
XEQMSupportToken,
|
|
ticket
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Extract EQM Support Positions from a Tagged string ...
|
|
ulong ExtractEQMSupportedTicket(string value)
|
|
{
|
|
//
|
|
return ParseLongSurrounded(
|
|
value,
|
|
XEQMSupportToken
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
bool IsSupport(string value)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bool isSupport = ExtractSupportedTicket(value) > 0;
|
|
bool isEQMSupport = ExtractEQMSupportedTicket(value) > 0;
|
|
|
|
//
|
|
result =
|
|
//
|
|
isSupport
|
|
//
|
|
||
|
|
//
|
|
isEQMSupport
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ulong ExtractParentTicket(string value)
|
|
{
|
|
//
|
|
ulong result = 0;
|
|
|
|
//
|
|
if (!IsSupport(value))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ExtractSupportedTicket(value);
|
|
if (result > 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ExtractEQMSupportedTicket(value);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// XRecovery ...
|
|
|
|
//
|
|
string GenerateRecoveryTag(ulong ticket)
|
|
{
|
|
//
|
|
return Surround(
|
|
XRecoveryToken,
|
|
ticket //
|
|
);
|
|
}
|
|
|
|
//
|
|
ulong ExtractRecoveredTicket(string value)
|
|
{
|
|
//
|
|
return ParseLongSurrounded(
|
|
value,
|
|
XRecoveryToken //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Extract Recoveries ...
|
|
template <typename T>
|
|
int ExtractRecoveries(
|
|
T &source[],
|
|
T &dest[] // Result ...
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(dest);
|
|
|
|
//
|
|
int sourceCount = ArraySize(source);
|
|
if (!IsValidSize(sourceCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < sourceCount; i++)
|
|
{
|
|
//
|
|
T iSource = source[i];
|
|
|
|
//
|
|
ulong isRecovery = ExtractRecoveredTicket(iSource.comment) > 0;
|
|
if (isRecovery)
|
|
{
|
|
//
|
|
AddRef(
|
|
iSource,
|
|
dest //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(dest);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Extract Specified Position's Recoveries ...
|
|
int ExtractRecoveries(
|
|
ulong ticket,
|
|
XPosition &source[],
|
|
XPosition &dest[] // Result ...
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(dest);
|
|
|
|
//
|
|
int sourceCount = ArraySize(source);
|
|
if (!IsValidSize(sourceCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < sourceCount; i++)
|
|
{
|
|
//
|
|
XPosition iSource = source[i];
|
|
|
|
//
|
|
ulong parentTicket = ExtractRecoveredTicket(iSource.comment);
|
|
bool isRecovery = parentTicket > 0;
|
|
if (isRecovery && parentTicket == ticket)
|
|
{
|
|
//
|
|
AddRef(
|
|
iSource,
|
|
dest //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(dest);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// SL Trails ...
|
|
|
|
//
|
|
// Extract SL Trail Level ...
|
|
int ExtractSLTrailLevel(string comment)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid(comment))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ParseIntSurrounded(
|
|
comment,
|
|
XSLTrailToken
|
|
//
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Generate SL Trail Comment Tag ...
|
|
string GenerateSLTrailTag(int level)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (level <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = Surround(
|
|
XSLTrailToken,
|
|
level
|
|
//
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Prepare SL Trail Comment ...
|
|
string PrepareSLTrailTag(
|
|
const string comment // Original Position Comment ...
|
|
)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
int level = 0;
|
|
result = comment;
|
|
|
|
//
|
|
// Check Comment Contains SL Trailing or not ...
|
|
int lastTrailLevel = ExtractSLTrailLevel(comment);
|
|
if (lastTrailLevel <= 0)
|
|
{
|
|
level++;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
level = lastTrailLevel + 1;
|
|
string lastLevelStr = GenerateSLTrailTag(lastTrailLevel);
|
|
StringReplace(
|
|
result,
|
|
lastLevelStr,
|
|
""
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Generate level Comment ...
|
|
string levelStr = GenerateSLTrailTag(level);
|
|
result += levelStr;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Count Positions from a Collection ...
|
|
void CountPositions(
|
|
const XPosition &positions[],
|
|
int &longs,
|
|
double &longProfits,
|
|
double &longVolumes, //
|
|
//
|
|
int &shorts,
|
|
double &shortProfits,
|
|
double &shortVolumes //
|
|
)
|
|
{
|
|
//
|
|
longs = 0;
|
|
longProfits = 0;
|
|
longVolumes = 0;
|
|
|
|
//
|
|
shorts = 0;
|
|
shortProfits = 0;
|
|
shortVolumes = 0;
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
bool isLong = IsLong(iPosition.type);
|
|
if (isLong)
|
|
{
|
|
//
|
|
longs++;
|
|
longProfits += iPosition.profit;
|
|
longVolumes += iPosition.volume;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
shorts++;
|
|
shortProfits += iPosition.profit;
|
|
shortVolumes += iPosition.volume;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Extract Positions based On Type ...
|
|
void ExtractPositions(
|
|
XPosition &positions[],
|
|
XPosition &longs[],
|
|
XPosition &shorts[] //
|
|
)
|
|
{
|
|
//
|
|
int count = ArraySize(positions);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
Clean(longs);
|
|
Clean(shorts);
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
bool isLong = IsLong(iPosition.type);
|
|
if (isLong)
|
|
{
|
|
AddRef(
|
|
iPosition,
|
|
longs //
|
|
);
|
|
}
|
|
else
|
|
{
|
|
AddRef(
|
|
iPosition,
|
|
shorts //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Apply a Collection of Targets
|
|
// on Specified Signal ...
|
|
void ApplyTargetsOnSignal(
|
|
ENUM_X_DIRECTION sortingDir, // Target Sorting Direction ...
|
|
XTarget &targets[], // Required Targets ...
|
|
XSignal &signal // Destination Signal ...
|
|
)
|
|
{
|
|
//
|
|
bool has =
|
|
HasChild(targets) &&
|
|
HasDirection(sortingDir);
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Sort Targets ...
|
|
ApplySortOnTargets(
|
|
sortingDir,
|
|
targets //
|
|
);
|
|
|
|
//
|
|
// Compare TP with Targets ...
|
|
int idx = IsLong(signal.type)
|
|
? GetHighest(targets)
|
|
: GetLowest(targets);
|
|
has = IsValidIndex(idx);
|
|
if (has)
|
|
{
|
|
//
|
|
// Compare TP ...
|
|
has = IsLong(signal.type)
|
|
? targets[idx].target > signal.tp
|
|
: targets[idx].target < signal.tp;
|
|
if (has)
|
|
{
|
|
//
|
|
XTarget tpTarget;
|
|
tpTarget = targets[idx];
|
|
tpTarget.actingDistance = 0;
|
|
tpTarget.target = signal.tp;
|
|
|
|
//
|
|
signal.tp = targets[idx].target;
|
|
targets[idx].actingDistance = 0;
|
|
|
|
//
|
|
ArrayRemove(
|
|
targets,
|
|
idx,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
AddRef(
|
|
tpTarget,
|
|
targets //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Sort Targets ...
|
|
ApplySortOnTargets(
|
|
sortingDir,
|
|
targets //
|
|
);
|
|
}
|
|
|
|
//
|
|
Copy(
|
|
targets,
|
|
signal.targets //
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Select Specified Position's Related Position(s)
|
|
* for Protecting ...
|
|
*
|
|
* @param selecteds: XPosition instance reference Collection, for Holding Selected Positions ...
|
|
* @param positions: XPosition instance reference Collection, All available source Positions ...
|
|
* @param forType: ENUM_X_POSITION_TYPES member, Spcified Position Type to Select for it ...
|
|
* @param selectType: ENUM_XPOSITION_SELECT_TYPES member, Specified Positions Selecting Senario ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool SelectPosition(
|
|
XPosition &selecteds[],
|
|
XPosition &positions[],
|
|
ENUM_X_POSITION_TYPES forType,
|
|
ENUM_XPOSITION_SELECT_TYPES selectType //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalize Args ...
|
|
Clean(selecteds);
|
|
|
|
//
|
|
// Validate Args ...
|
|
result =
|
|
IsValid(forType) &&
|
|
HasChild(positions) &&
|
|
IsXValid(selectType);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Extract Separate Type of Positions ...
|
|
|
|
//
|
|
int idx = -1;
|
|
bool has = false;
|
|
XPosition iPosition;
|
|
|
|
//
|
|
bool isLong = IsLong(forType);
|
|
bool isShort = IsShort(forType);
|
|
int count = ArraySize(positions);
|
|
|
|
//
|
|
XPosition samePositions[];
|
|
XPosition oppositPositions[];
|
|
XPosition inProfitPositions[];
|
|
XPosition inDrawdownPositions[];
|
|
XPosition sameInProfitPositions[];
|
|
XPosition sameInDrawdownPositions[];
|
|
XPosition oppositInProfitPositions[];
|
|
XPosition oppositInDrawdownPositions[];
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
// Select Indexed Position ...
|
|
iPosition = positions[i];
|
|
|
|
//
|
|
bool isIPosLong = IsLong(iPosition.type);
|
|
bool isIPosShort = IsShort(iPosition.type);
|
|
|
|
//
|
|
// Select if Same Type ...
|
|
bool isSame =
|
|
(isLong && isIPosLong) ||
|
|
(isShort && isIPosShort);
|
|
if (isSame)
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
samePositions //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Select if Opposit Type ...
|
|
bool isOpposit =
|
|
(isLong && isIPosShort) ||
|
|
(isShort && isIPosLong);
|
|
if (isOpposit)
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
oppositPositions //
|
|
);
|
|
}
|
|
|
|
//
|
|
iPosition.Clean();
|
|
}
|
|
|
|
//
|
|
// Filling Other Requirement Collections ...
|
|
|
|
//
|
|
ExtractInProfitPositions(
|
|
positions,
|
|
inProfitPositions //
|
|
);
|
|
|
|
//
|
|
ExtractInProfitPositions(
|
|
samePositions,
|
|
sameInProfitPositions //
|
|
);
|
|
|
|
//
|
|
ExtractInProfitPositions(
|
|
oppositPositions,
|
|
oppositInProfitPositions //
|
|
);
|
|
|
|
//
|
|
ExtractInDrawdownPositions(
|
|
positions,
|
|
inDrawdownPositions //
|
|
);
|
|
|
|
//
|
|
ExtractInDrawdownPositions(
|
|
samePositions,
|
|
sameInDrawdownPositions //
|
|
);
|
|
|
|
//
|
|
ExtractInDrawdownPositions(
|
|
oppositPositions,
|
|
oppositInDrawdownPositions //
|
|
);
|
|
|
|
//
|
|
// Implement Selection Senario ...
|
|
switch (selectType)
|
|
{
|
|
//
|
|
case XPOSITION_SELECT_ALL:
|
|
//
|
|
Copy(
|
|
positions,
|
|
selecteds //
|
|
);
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_IN_PROFITS:
|
|
//
|
|
Copy(
|
|
inProfitPositions,
|
|
selecteds //
|
|
);
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_IN_DRAWDOWNS:
|
|
//
|
|
Copy(
|
|
inDrawdownPositions,
|
|
selecteds //
|
|
);
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_OLDEST:
|
|
//
|
|
GetOldest(
|
|
iPosition,
|
|
positions //
|
|
);
|
|
if (iPosition.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_YOUNGEST:
|
|
//
|
|
GetYoungest(
|
|
iPosition,
|
|
positions //
|
|
);
|
|
if (iPosition.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_IN_PROFITS_OLDEST:
|
|
//
|
|
GetOldest(
|
|
iPosition,
|
|
inProfitPositions //
|
|
);
|
|
if (iPosition.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_IN_PROFITS_YOUNGEST:
|
|
//
|
|
GetYoungest(
|
|
iPosition,
|
|
inProfitPositions //
|
|
);
|
|
if (iPosition.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_IN_PROFITS_MIN:
|
|
//
|
|
idx = FindMinProfitIndex(inProfitPositions);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
//
|
|
iPosition = inProfitPositions[idx];
|
|
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_IN_PROFITS_MAX:
|
|
//
|
|
idx = FindMaxProfitIndex(inProfitPositions);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
//
|
|
iPosition = inProfitPositions[idx];
|
|
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_IN_DRAWDOWN_OLDEST:
|
|
//
|
|
GetOldest(
|
|
iPosition,
|
|
inDrawdownPositions //
|
|
);
|
|
if (iPosition.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_IN_DRAWDOWN_YOUNGEST:
|
|
//
|
|
GetYoungest(
|
|
iPosition,
|
|
inDrawdownPositions //
|
|
);
|
|
if (iPosition.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_IN_DRAWDOWN_MIN:
|
|
//
|
|
idx = FindMinDrawdownIndex(inDrawdownPositions);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
//
|
|
iPosition = inDrawdownPositions[idx];
|
|
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_IN_DRAWDOWN_MAX:
|
|
//
|
|
idx = FindMaxDrawdownIndex(inDrawdownPositions);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
//
|
|
iPosition = inDrawdownPositions[idx];
|
|
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_SAMES:
|
|
//
|
|
Copy(
|
|
samePositions,
|
|
selecteds //
|
|
);
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_SAMES_OLDEST:
|
|
//
|
|
GetOldest(
|
|
iPosition,
|
|
samePositions //
|
|
);
|
|
if (iPosition.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_SAMES_YOUNGEST:
|
|
//
|
|
GetYoungest(
|
|
iPosition,
|
|
samePositions //
|
|
);
|
|
if (iPosition.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_OPPOSITS:
|
|
//
|
|
Copy(
|
|
oppositPositions,
|
|
selecteds //
|
|
);
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_OPPOSIT_OLDEST:
|
|
//
|
|
GetOldest(
|
|
iPosition,
|
|
oppositPositions //
|
|
);
|
|
if (iPosition.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_OPPOSIT_YOUNGEST:
|
|
//
|
|
GetYoungest(
|
|
iPosition,
|
|
oppositPositions //
|
|
);
|
|
if (iPosition.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_SAME_IN_PROFITS:
|
|
//
|
|
Copy(
|
|
sameInProfitPositions,
|
|
selecteds //
|
|
);
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_SAME_IN_PROFITS_OLDEST:
|
|
//
|
|
GetOldest(
|
|
iPosition,
|
|
sameInProfitPositions //
|
|
);
|
|
if (iPosition.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_SAME_IN_PROFITS_YOUNGEST:
|
|
//
|
|
GetYoungest(
|
|
iPosition,
|
|
sameInProfitPositions //
|
|
);
|
|
if (iPosition.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_SAME_IN_PROFITS_MIN:
|
|
//
|
|
idx = FindMinProfitIndex(sameInProfitPositions);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
//
|
|
iPosition = sameInProfitPositions[idx];
|
|
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_SAME_IN_PROFITS_MAX:
|
|
//
|
|
idx = FindMaxProfitIndex(sameInProfitPositions);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
//
|
|
iPosition = sameInProfitPositions[idx];
|
|
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_OPPOSIT_IN_PROFITS:
|
|
//
|
|
Copy(
|
|
oppositInProfitPositions,
|
|
selecteds //
|
|
);
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_OPPOSIT_IN_PROFITS_OLDEST:
|
|
//
|
|
GetOldest(
|
|
iPosition,
|
|
oppositInProfitPositions //
|
|
);
|
|
if (iPosition.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_OPPOSIT_IN_PROFITS_YOUNGEST:
|
|
//
|
|
GetYoungest(
|
|
iPosition,
|
|
oppositInProfitPositions //
|
|
);
|
|
if (iPosition.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_OPPOSIT_IN_PROFITS_MIN:
|
|
//
|
|
idx = FindMinProfitIndex(oppositInProfitPositions);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
//
|
|
iPosition = oppositInProfitPositions[idx];
|
|
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_OPPOSIT_IN_PROFITS_MAX:
|
|
//
|
|
idx = FindMaxProfitIndex(oppositInProfitPositions);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
//
|
|
iPosition = oppositInProfitPositions[idx];
|
|
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_SAME_IN_DRAWDOWNS:
|
|
//
|
|
Copy(
|
|
sameInDrawdownPositions,
|
|
selecteds //
|
|
);
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_SAME_IN_DRAWDOWN_OLDEST:
|
|
//
|
|
GetOldest(
|
|
iPosition,
|
|
sameInDrawdownPositions //
|
|
);
|
|
if (iPosition.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_SAME_IN_DRAWDOWN_YOUNGEST:
|
|
//
|
|
GetYoungest(
|
|
iPosition,
|
|
sameInDrawdownPositions //
|
|
);
|
|
if (iPosition.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_SAME_IN_DRAWDOWN_MIN:
|
|
//
|
|
idx = FindMinDrawdownIndex(sameInDrawdownPositions);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
//
|
|
iPosition = sameInDrawdownPositions[idx];
|
|
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_SAME_IN_DRAWDOWN_MAX:
|
|
//
|
|
idx = FindMaxDrawdownIndex(sameInDrawdownPositions);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
//
|
|
iPosition = sameInDrawdownPositions[idx];
|
|
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWNS:
|
|
//
|
|
Copy(
|
|
oppositInDrawdownPositions,
|
|
selecteds //
|
|
);
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWN_OLDEST:
|
|
//
|
|
GetOldest(
|
|
iPosition,
|
|
oppositInDrawdownPositions //
|
|
);
|
|
if (iPosition.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWN_YOUNGEST:
|
|
//
|
|
GetYoungest(
|
|
iPosition,
|
|
oppositInDrawdownPositions //
|
|
);
|
|
if (iPosition.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWN_MIN:
|
|
//
|
|
idx = FindMinDrawdownIndex(oppositInDrawdownPositions);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
//
|
|
iPosition = oppositInDrawdownPositions[idx];
|
|
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
case XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWN_MAX:
|
|
//
|
|
idx = FindMaxDrawdownIndex(oppositInDrawdownPositions);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
//
|
|
iPosition = oppositInDrawdownPositions[idx];
|
|
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
selecteds //
|
|
);
|
|
}
|
|
iPosition.Clean();
|
|
break;
|
|
|
|
//
|
|
}
|
|
|
|
//
|
|
// Validate Result ...
|
|
result = HasChild(selecteds);
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
|
|
//
|
|
if (!result)
|
|
{
|
|
Clean(selecteds);
|
|
}
|
|
|
|
//
|
|
Clean(samePositions);
|
|
Clean(oppositPositions);
|
|
Clean(inProfitPositions);
|
|
Clean(inDrawdownPositions);
|
|
Clean(sameInProfitPositions);
|
|
Clean(sameInDrawdownPositions);
|
|
Clean(oppositInProfitPositions);
|
|
Clean(oppositInDrawdownPositions);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
// |