3565 lines
74 KiB
Plaintext
3565 lines
74 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Class Library
|
|
// --------------------------------------
|
|
// Name: XCX121SMCTradeHandler
|
|
// Description: provides all based classes for use ...
|
|
//
|
|
//
|
|
// Maintainer:
|
|
// ------------
|
|
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// Global Properties ...
|
|
#property library
|
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
|
#property link "https://www.saherelm.ir"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
//
|
|
// Imports ...
|
|
|
|
//
|
|
#include "../../Classes/x-saherelm.x-alert.class.mq5"
|
|
#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5"
|
|
#include "../../Classes/x-saherelm.x-trade.class.mq5"
|
|
|
|
//
|
|
// Definitions ...
|
|
|
|
//
|
|
// Model a Trade Data ...
|
|
struct X121SMCTradeData
|
|
{
|
|
//
|
|
double ask; // Ask Price on Start Time
|
|
double bid; // bid Price on Start Time
|
|
ulong ticket; // Position Ticket
|
|
double swap; // Swap
|
|
double profit; // Profit on Close
|
|
XSignal signal; // Signal Object
|
|
string message; // Message
|
|
datetime endTime; // End Time
|
|
datetime startTime; // Start Time
|
|
double commission; // Commission
|
|
string conditions; // Signal Conditions
|
|
double maxDrawdown; // Max Position Drawdown
|
|
|
|
//
|
|
// Constructor ...
|
|
X121SMCTradeData()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
/**
|
|
* Initialize Item ...
|
|
*
|
|
* @param _signal: XSignal instance Reference, Provides Source For Initializaion ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Init(XSignal &_signal)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
Clean();
|
|
|
|
//
|
|
result = _signal.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
signal = _signal;
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Cleaning Up Model ...
|
|
*/
|
|
void Clean()
|
|
{
|
|
//
|
|
ask = 0;
|
|
bid = 0;
|
|
swap = 0;
|
|
profit = 0;
|
|
ticket = 0;
|
|
commission = 0;
|
|
maxDrawdown = 0;
|
|
|
|
//
|
|
endTime = NULL;
|
|
message = NULL;
|
|
startTime = NULL;
|
|
conditions = NULL;
|
|
|
|
//
|
|
signal.Clean();
|
|
}
|
|
|
|
/**
|
|
* Validate Model ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
signal.IsValid()
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate Model Age ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int GetAge()
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int startIndex = iBarShift(
|
|
GetSymbol(),
|
|
GetPeriod(),
|
|
startTime,
|
|
false //
|
|
);
|
|
|
|
//
|
|
datetime mEndTime = IsValid(endTime)
|
|
? endTime
|
|
: TimeCurrent();
|
|
int endIndex = iBarShift(
|
|
GetSymbol(),
|
|
GetPeriod(),
|
|
mEndTime,
|
|
false //
|
|
);
|
|
|
|
//
|
|
result = MathAbs(startIndex - endIndex);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Owner Functions ...
|
|
|
|
/**
|
|
* Check a Ticket is Own to Model or not ...
|
|
*
|
|
* @param _ticket: ULONG, Position Ticket ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsOwn(
|
|
ulong _ticket //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
_ticket == ticket;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Conditions is Own to Model or not ...
|
|
*
|
|
* @param _symbol: String, Specified Symbol ...
|
|
* @param _provider: String, Specified Provider ...
|
|
* @param _period: ENUM_TIMEFRAMES member, Specified Signal Period ...
|
|
* @param _type: ENUM_X_POSITION_TYPES member, Specified Signal Type ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsOwn(
|
|
string _symbol,
|
|
string _provider,
|
|
ENUM_TIMEFRAMES _period,
|
|
ENUM_X_POSITION_TYPES _type //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid(_symbol) &&
|
|
IsValid(_period) &&
|
|
XType() == _type &&
|
|
IsValid(_provider) &&
|
|
GetPeriod() == _period &&
|
|
GetSymbol() == _symbol &&
|
|
Provider() == _provider &&
|
|
XType() != X_POSITION_TYPE_ALL &&
|
|
XType() != X_POSITION_TYPE_NONE
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Signal is Own to Model or not ...
|
|
*
|
|
* @param _signal: XSignal instance Reference ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsOwn(XSignal &_signal)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid() &&
|
|
_signal.IsValid() &&
|
|
IsOwn(
|
|
_signal.symbol,
|
|
_signal.provider,
|
|
_signal.period,
|
|
ToPositionType(_signal.type))
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Specified Position is Own to Model or not ...
|
|
*
|
|
* @param _position: XPosition instance Reference ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsOwn(XPosition &_position)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid() &&
|
|
_position.IsValid() &&
|
|
IsOwn(
|
|
_position.symbol,
|
|
_position.provider,
|
|
_position.period,
|
|
ToPositionType(_position.type))
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Update Model Data by Providing Specified Signal ...
|
|
*
|
|
* @param _signal: XSignal instance Reference ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Update(XSignal &_signal)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid() &&
|
|
_signal.IsValid() &&
|
|
IsOwn(_signal)
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
signal = _signal;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Update Model Data by Providing Specified Position ...
|
|
*
|
|
* @param _position: XPosition instance Reference ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Update(XPosition &_position)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid() &&
|
|
_position.IsValid() &&
|
|
IsOwn(_position)
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
swap = _position.swap;
|
|
ticket = _position.ticket;
|
|
profit = _position.profit;
|
|
message = _position.comment;
|
|
startTime = _position.openAt;
|
|
|
|
//
|
|
// Set Once ...
|
|
if (commission == 0 &&
|
|
_position.commission != 0)
|
|
{
|
|
commission = _position.commission;
|
|
}
|
|
|
|
//
|
|
// Set Once ...
|
|
if (ask == 0)
|
|
{
|
|
ask = GetAsk(_position.symbol);
|
|
}
|
|
|
|
//
|
|
// Set Once ...
|
|
if (bid == 0)
|
|
{
|
|
bid = GetBid(_position.symbol);
|
|
}
|
|
|
|
//
|
|
if (profit < 0 && profit < maxDrawdown)
|
|
{
|
|
maxDrawdown = profit;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools Extensions ...
|
|
|
|
/**
|
|
* Get Model Symbol ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string GetSymbol()
|
|
{
|
|
return signal.symbol;
|
|
}
|
|
|
|
/**
|
|
* Get Model Period ...
|
|
*
|
|
* @return ( ENUM_TIMEFRAMES )
|
|
*/
|
|
ENUM_TIMEFRAMES GetPeriod()
|
|
{
|
|
return signal.period;
|
|
}
|
|
|
|
/**
|
|
* Get Model Provider ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string Provider()
|
|
{
|
|
return signal.provider;
|
|
}
|
|
|
|
/**
|
|
* Get Model Entry ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double Entry()
|
|
{
|
|
return signal.entry;
|
|
}
|
|
|
|
/**
|
|
* Get Model Stop Loss ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double SL()
|
|
{
|
|
return signal.sl;
|
|
}
|
|
|
|
/**
|
|
* Get Model Take Profit ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double TP()
|
|
{
|
|
return signal.tp;
|
|
}
|
|
|
|
/**
|
|
* Get Position Spread on Open Time ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double Spread()
|
|
{
|
|
return MathAbs(ask - bid);
|
|
}
|
|
|
|
/**
|
|
* Get Model Volume ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double Volume()
|
|
{
|
|
return signal.volume;
|
|
}
|
|
|
|
/**
|
|
* Get Model Point Value ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double Points()
|
|
{
|
|
return GetPoints(GetSymbol());
|
|
}
|
|
|
|
/**
|
|
* Get Model Type ...
|
|
*
|
|
* @return ( ENUM_POSITION_TYPE )
|
|
*/
|
|
ENUM_POSITION_TYPE Type()
|
|
{
|
|
return signal.type;
|
|
}
|
|
|
|
/**
|
|
* Get Model Type ...
|
|
*
|
|
* @return ( ENUM_X_POSITION_TYPES )
|
|
*/
|
|
ENUM_X_POSITION_TYPES XType()
|
|
{
|
|
//
|
|
ENUM_X_POSITION_TYPES result = X_POSITION_TYPE_NONE;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
IsLong(Type())
|
|
? X_POSITION_TYPE_LONG
|
|
: X_POSITION_TYPE_SHORT;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get Model Signal Mode ...
|
|
*
|
|
* @return ( ENUM_X_ORDER_MODES )
|
|
*/
|
|
ENUM_X_ORDER_MODES Mode()
|
|
{
|
|
return signal.mode;
|
|
}
|
|
|
|
//
|
|
// Additional Helpers Extensions ...
|
|
|
|
/**
|
|
* Get Signal Full TP Level ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double FullTPLevel()
|
|
{
|
|
return signal.fullTPLevel;
|
|
}
|
|
|
|
/**
|
|
* Check Can Partial Close Position or not ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool CanPartialClose()
|
|
{
|
|
return signal.CanPartialClose();
|
|
}
|
|
|
|
/**
|
|
* Retrieve Partial Close Volume Multiplier ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double PartialCloseMultiplier()
|
|
{
|
|
return signal.partialCloseMultiplier;
|
|
}
|
|
|
|
/**
|
|
* Get Partial Close On TP Level ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double PartialCloseOnTPLevel()
|
|
{
|
|
return signal.partialCloseOnTPLevel;
|
|
}
|
|
|
|
/**
|
|
* Check Can Risk Free Position on Break Even Point or not ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool CanRiskFreeOnBreakEvenPoint()
|
|
{
|
|
return signal.CanRiskFreeOnBreakEvenPoint();
|
|
}
|
|
|
|
/**
|
|
* Get Minimum Required Profit after Break Even Point for Risk Free ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double TPLevelForBreakEven()
|
|
{
|
|
return signal.tpLevelForBreakEven;
|
|
}
|
|
|
|
/**
|
|
* Calculate Break Even Point ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double CalculateBreakEvenPoint()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
bool isValid =
|
|
//
|
|
ask > 0 &&
|
|
bid > 0 &&
|
|
IsValid() &&
|
|
ticket > 0 &&
|
|
signal.IsValid()
|
|
//
|
|
;
|
|
if (!isValid)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Spread ...
|
|
double spread = Spread();
|
|
if (spread <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate BEP ...
|
|
result =
|
|
//
|
|
spread + (-1 * swap) + MathAbs(commission)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Can Trail Position Stop Loss or not ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool CanTrailSL()
|
|
{
|
|
return signal.CanTrailSL();
|
|
}
|
|
|
|
/**
|
|
* Get Start Position SL Trailling on TP Level ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double TrailSLStartOnReachTPLevel()
|
|
{
|
|
return signal.trailSLStartOnReachTPLevel;
|
|
}
|
|
|
|
//
|
|
// Data Collector Extensions ...
|
|
|
|
/**
|
|
* Get Data Collection File Name ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string GetFileName()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
GetSymbol() + "\\" +
|
|
ToString(XType()) + "\\" +
|
|
(profit >= 0 ? "Profit" : "Loss") + "\\" +
|
|
ToString(ticket) + "_" +
|
|
ToString(GetPeriod()) + "_" +
|
|
ToFormatString(startTime)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get Signal Collectiong File Name ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string GetSignalFileName()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
result =
|
|
//
|
|
GetSymbol() + "\\" +
|
|
ToString(XType()) + "\\" +
|
|
Provider() + "_" +
|
|
ToFormatString(startTime)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Converts Model to String Representation ...
|
|
*
|
|
* @param onlySignals: Boolean, Specified Represent Only Signal or not ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string ToString(
|
|
bool onlySignals = false //
|
|
)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
int age = GetAge();
|
|
|
|
//
|
|
result =
|
|
//
|
|
(onlySignals ? "" : ToString("Ticket", ticket)) +
|
|
ToString("Symbol", GetSymbol()) +
|
|
ToString("Period", GetPeriod()) +
|
|
ToString("Entry", Entry()) +
|
|
ToString("Provider", Provider()) +
|
|
ToString("Type", ToString(XType())) +
|
|
ToString("Time", startTime) +
|
|
//
|
|
// Attach Trade Info ...
|
|
(onlySignals ? "" :
|
|
//
|
|
"-------------" + "\n" +
|
|
ToString("Volume", Volume()) +
|
|
ToString("Profit", profit) +
|
|
ToString("Commission", commission) +
|
|
ToString("Swap", swap) +
|
|
ToString("Max Drawdown", maxDrawdown) +
|
|
ToString("End Time", endTime) +
|
|
ToString("Age", age) +
|
|
ToString("Message", message) +
|
|
""
|
|
//
|
|
) +
|
|
//
|
|
// Attach Conditions to Signals ...
|
|
(!onlySignals ? "" :
|
|
//
|
|
"-------------" + "\n" +
|
|
ToString("Pushers", signal.pushers) +
|
|
"Conditions:" + "\n" +
|
|
"-------------" + "\n" +
|
|
conditions +
|
|
""
|
|
//
|
|
) +
|
|
//
|
|
""
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// End Of X121SMCTradeData Model ...
|
|
};
|
|
|
|
//
|
|
// Model Specified Symbol's Positions States ...
|
|
struct X121SMCSymbolPositionInfo
|
|
{
|
|
//
|
|
string symbol;
|
|
|
|
//
|
|
datetime enableAt;
|
|
|
|
//
|
|
int longSLs;
|
|
int longTPs;
|
|
|
|
//
|
|
int shortSLs;
|
|
int shortTPs;
|
|
|
|
//
|
|
int countedSLs;
|
|
|
|
//
|
|
// Constructor ...
|
|
X121SMCSymbolPositionInfo()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Cleanup ...
|
|
*/
|
|
void Clean()
|
|
{
|
|
//
|
|
longSLs = 0;
|
|
longTPs = 0;
|
|
|
|
//
|
|
shortSLs = 0;
|
|
shortTPs = 0;
|
|
|
|
//
|
|
countedSLs = 0;
|
|
|
|
//
|
|
enableAt = NULL;
|
|
}
|
|
|
|
/**
|
|
* Check is own Symbol Info ...
|
|
*
|
|
* @param _symbol: String ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsOwn(string _symbol)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid(symbol) &&
|
|
_symbol == symbol
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Symbol Trading is Enable or not ...
|
|
*
|
|
* @param time: DateTime ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsEnable(datetime time = NULL)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
time = NormalizeTime(time);
|
|
|
|
//
|
|
bool isEnableAtValid = IsValid(enableAt);
|
|
|
|
//
|
|
result =
|
|
!isEnableAtValid
|
|
? true
|
|
: time > enableAt;
|
|
if (result &&
|
|
isEnableAtValid)
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Pause Symbol Trading ...
|
|
*
|
|
* @param seconds: Integer ...
|
|
*/
|
|
void Pause(int seconds)
|
|
{
|
|
//
|
|
if (seconds <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
datetime _enableAt = ((datetime)((int)TimeCurrent() + seconds));
|
|
enableAt = _enableAt;
|
|
}
|
|
|
|
/**
|
|
* Handle Stop Loss ...
|
|
*
|
|
* @param _type: ENUM_POSITION_TYPE member ...
|
|
*/
|
|
void HandleSL(ENUM_POSITION_TYPE _type)
|
|
{
|
|
//
|
|
bool isLong = IsLong(_type);
|
|
if (isLong)
|
|
{
|
|
longSLs++;
|
|
}
|
|
else
|
|
{
|
|
shortSLs++;
|
|
}
|
|
|
|
//
|
|
countedSLs++;
|
|
}
|
|
|
|
/**
|
|
* Handle Take Profit ...
|
|
*
|
|
* @param _type: ENUM_POSITION_TYPE member ...
|
|
*/
|
|
void HandleTP(ENUM_POSITION_TYPE _type)
|
|
{
|
|
//
|
|
bool isLong = IsLong(_type);
|
|
if (isLong)
|
|
{
|
|
longTPs++;
|
|
}
|
|
else
|
|
{
|
|
shortTPs++;
|
|
}
|
|
|
|
//
|
|
countedSLs--;
|
|
if (countedSLs < 0)
|
|
{
|
|
countedSLs = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reset Counter ...
|
|
*/
|
|
void Reset()
|
|
{
|
|
//
|
|
countedSLs = 0;
|
|
enableAt = NULL;
|
|
}
|
|
|
|
//
|
|
// End of X121SMCSymbolPositionInfo Model ...
|
|
};
|
|
|
|
//
|
|
// Implementations ...
|
|
|
|
//
|
|
// a Class For Read and Write Trade Info Data in Files ...
|
|
class X121SMCTradeCollector
|
|
{
|
|
//
|
|
// Public ...
|
|
public:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Constructor(s) ...
|
|
X121SMCTradeCollector(
|
|
string _path = NULL // Base Path
|
|
)
|
|
{
|
|
//
|
|
mAccount = new XCAccount();
|
|
|
|
//
|
|
if (IsValid(_path))
|
|
{
|
|
mPath = _path;
|
|
}
|
|
else
|
|
{
|
|
mPath = "X121SMCTradeData" + "\\" + mAccount.GetCompany();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
~X121SMCTradeCollector()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Check Specified Model is Exists or not ...
|
|
*
|
|
* @param item: X121SMCTradeData instance Reference, Provides Source Model ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsExists(X121SMCTradeData &item)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int mHandler = GetFileHandlerForRead(item);
|
|
result = mHandler != INVALID_HANDLE;
|
|
FileClose(mHandler);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Save Specified Model as Data ...
|
|
*
|
|
* @param item: X121SMCTradeData instance Reference, Provides Source Model ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Save(X121SMCTradeData &item)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Check info is Valid ...
|
|
result = item.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string content = item.ToString();
|
|
content += "\n" + "-----------" + "\n" + "Signal: " + "\n" + "-----------" + "\n" + item.ToString(true);
|
|
|
|
//
|
|
result = IsValid(content);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int mHandler = GetFileHandlerForWrite(item);
|
|
result = mHandler != INVALID_HANDLE;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
FileWrite(mHandler, content);
|
|
FileFlush(mHandler);
|
|
FileClose(mHandler);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Save Specified Model as Signal ...
|
|
*
|
|
* @param item: X121SMCTradeData instance Reference, Provides Source Model ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool SaveSignal(X121SMCTradeData &item)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
string content = item.ToString(true);
|
|
result = IsValid(content);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int mHandler = GetSignalFileHandlerForWrite(item);
|
|
result = mHandler != INVALID_HANDLE;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
FileWrite(mHandler, content);
|
|
FileFlush(mHandler);
|
|
FileClose(mHandler);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Save Specified Model Conditions ...
|
|
* Conditions only save for Loss Signals ...
|
|
* this means the profit must be Lower than Zero ...
|
|
* ans also message Contains SL ...
|
|
*
|
|
* @param item: X121SMCTradeData instance Reference, Provides Source Model ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool SaveConditions(X121SMCTradeData &item)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Item ...
|
|
result =
|
|
//
|
|
item.profit < 0 &&
|
|
Contains("SL", item.message)
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string content = item.signal.conditions;
|
|
result = IsValid(content);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int mHandler = GetConditionsFileHandlerForWrite(item);
|
|
result = mHandler != INVALID_HANDLE;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
FileSeek(mHandler, 0, SEEK_END);
|
|
FileWrite(mHandler, content);
|
|
FileFlush(mHandler);
|
|
FileClose(mHandler);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Protected ...
|
|
protected:
|
|
//
|
|
// Private ...
|
|
private:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
string mPath; // Base Path ...
|
|
|
|
//
|
|
XCAccount *mAccount;
|
|
|
|
//
|
|
string GetFilePath(X121SMCTradeData &item)
|
|
{
|
|
//
|
|
string fileName = item.GetFileName();
|
|
|
|
//
|
|
return GetFilePath(fileName);
|
|
}
|
|
string GetFilePath(string fileName)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
result =
|
|
//
|
|
mPath + "\\" + "Trades" + "\\" + fileName + ".x121.log"
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string GetSignalFilePath(X121SMCTradeData &item)
|
|
{
|
|
//
|
|
string fileName = item.GetSignalFileName();
|
|
|
|
//
|
|
return GetSignalFilePath(fileName);
|
|
}
|
|
string GetSignalFilePath(string fileName)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
result =
|
|
//
|
|
mPath + "\\" + "Signals" + "\\" + fileName + ".x121.log"
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string GetConditionsFilePath(X121SMCTradeData &item)
|
|
{
|
|
//
|
|
bool isLong = IsLong(item.Type());
|
|
|
|
//
|
|
string fileName =
|
|
item.GetSymbol() + "\\" +
|
|
(isLong ? "Longs" : "Shorts");
|
|
|
|
//
|
|
return GetConditionsFilePath(fileName);
|
|
}
|
|
string GetConditionsFilePath(string fileName)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
result =
|
|
//
|
|
mPath + "\\" + "Conditions" + "\\" + fileName + ".x121.log"
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetFileHandlerForRead(X121SMCTradeData &item)
|
|
{
|
|
//
|
|
int result = INVALID_HANDLE;
|
|
|
|
//
|
|
string filePath = GetFilePath(item);
|
|
if (!IsValid(filePath))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = FileOpen(
|
|
filePath,
|
|
FILE_READ | FILE_TXT //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
int GetFileHandlerForWrite(X121SMCTradeData &item)
|
|
{
|
|
//
|
|
int result = INVALID_HANDLE;
|
|
|
|
//
|
|
string filePath = GetFilePath(item);
|
|
if (!IsValid(filePath))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = FileOpen(
|
|
filePath,
|
|
FILE_READ | FILE_WRITE | FILE_TXT //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetSignalFileHandlerForRead(X121SMCTradeData &item)
|
|
{
|
|
//
|
|
int result = INVALID_HANDLE;
|
|
|
|
//
|
|
string filePath = GetSignalFilePath(item);
|
|
if (!IsValid(filePath))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = FileOpen(
|
|
filePath,
|
|
FILE_READ | FILE_TXT //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
int GetSignalFileHandlerForWrite(X121SMCTradeData &item)
|
|
{
|
|
//
|
|
int result = INVALID_HANDLE;
|
|
|
|
//
|
|
string filePath = GetSignalFilePath(item);
|
|
if (!IsValid(filePath))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = FileOpen(
|
|
filePath,
|
|
FILE_READ | FILE_WRITE | FILE_TXT //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetConditionsFileHandlerForRead(X121SMCTradeData &item)
|
|
{
|
|
//
|
|
int result = INVALID_HANDLE;
|
|
|
|
//
|
|
string filePath = GetConditionsFilePath(item);
|
|
if (!IsValid(filePath))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = FileOpen(
|
|
filePath,
|
|
FILE_READ | FILE_TXT //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
int GetConditionsFileHandlerForWrite(X121SMCTradeData &item)
|
|
{
|
|
//
|
|
int result = INVALID_HANDLE;
|
|
|
|
//
|
|
string filePath = GetConditionsFilePath(item);
|
|
if (!IsValid(filePath))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = FileOpen(
|
|
filePath,
|
|
FILE_READ | FILE_WRITE | FILE_TXT //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// End of X121SMCTradeCollector Class ...
|
|
};
|
|
|
|
//
|
|
// Trade Handler Class ...
|
|
// a Class For Handling All Trade Requirements ...
|
|
class XC121SMCTradeHandler : public XCBaseAlert
|
|
{
|
|
//
|
|
// Public ...
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor(s) ...
|
|
XC121SMCTradeHandler(XCTrade *trader)
|
|
{
|
|
//
|
|
mTrader = trader;
|
|
mAdditionalVolume = 0;
|
|
mCollector = new X121SMCTradeCollector();
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
~XC121SMCTradeHandler()
|
|
{
|
|
//
|
|
delete mTrader;
|
|
delete mCollector;
|
|
}
|
|
|
|
//
|
|
// ReadOnly Props ...
|
|
|
|
/**
|
|
* Get Max Same Time Trades ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double GetMaxSameTimeTrades()
|
|
{
|
|
return maxSameTimeTrades;
|
|
}
|
|
|
|
/**
|
|
* Get Max Drawdown Happens ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double GetMaxDrawdown()
|
|
{
|
|
return maxDrawdown;
|
|
}
|
|
|
|
/**
|
|
* Get Currently Drawdown of Account ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double GetCurrentDrawdown()
|
|
{
|
|
return currentDrawdown;
|
|
}
|
|
|
|
/**
|
|
* Get Account Current Drawdown Percent ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double GetDrawdownPercent()
|
|
{
|
|
return drawdownPercent;
|
|
}
|
|
|
|
//
|
|
// Properties Getter(s) / Setter(s) ...
|
|
|
|
//
|
|
// Saving Properties ...
|
|
|
|
/**
|
|
* Get Save Signals State ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool SaveSignals()
|
|
{
|
|
return mSaveSignals;
|
|
}
|
|
|
|
/**
|
|
* Set Save Signals State ...
|
|
*
|
|
* @param value: Boolean ...
|
|
*/
|
|
void SaveSignals(bool value)
|
|
{
|
|
mSaveSignals = value;
|
|
}
|
|
|
|
/**
|
|
* Get Save Trades State ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool SaveTrades()
|
|
{
|
|
return mSaveTrades;
|
|
}
|
|
|
|
/**
|
|
* Set Save Trades State ...
|
|
*
|
|
* @param value: Boolean ...
|
|
*/
|
|
void SaveTrades(bool value)
|
|
{
|
|
mSaveTrades = value;
|
|
}
|
|
|
|
/**
|
|
* Get Save Conditions State ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool SaveConditions()
|
|
{
|
|
return mSaveConditions;
|
|
}
|
|
|
|
/**
|
|
* Set Save Conditions State ...
|
|
*
|
|
* @param value: Boolean ...
|
|
*/
|
|
void SaveConditions(bool value)
|
|
{
|
|
mSaveConditions = value;
|
|
}
|
|
|
|
//
|
|
// Signalling Properties ...
|
|
|
|
/**
|
|
* Get Allow Long Signals State ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool AllowLong()
|
|
{
|
|
return mAllowLong;
|
|
}
|
|
|
|
/**
|
|
* Set Allow Long Signals State ...
|
|
*
|
|
* @param value: Boolean ...
|
|
*/
|
|
void AllowLong(bool value)
|
|
{
|
|
mAllowLong = value;
|
|
}
|
|
|
|
/**
|
|
* Get Allow Short Signals State ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool AllowShort()
|
|
{
|
|
return mAllowShort;
|
|
}
|
|
|
|
/**
|
|
* Set Allow Short Signals State ...
|
|
*
|
|
* @param value: Boolean ...
|
|
*/
|
|
void AllowShort(bool value)
|
|
{
|
|
mAllowShort = value;
|
|
}
|
|
|
|
/**
|
|
* Get Max Allowed Long Signals ...
|
|
* = 0 => Unlimited ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int MaxAllowedLongs()
|
|
{
|
|
return mMaxAllowedLongs;
|
|
}
|
|
|
|
/**
|
|
* Set Max Allowed Long Signals ...
|
|
* = 0 => Unlimited ...
|
|
*
|
|
* @param value: Integer ...
|
|
*/
|
|
void MaxAllowedLongs(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mMaxAllowedLongs = value;
|
|
}
|
|
|
|
/**
|
|
* Get Max Allowed Short Signals ...
|
|
* = 0 => Unlimited ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int MaxAllowedShorts()
|
|
{
|
|
return mMaxAllowedShorts;
|
|
}
|
|
|
|
/**
|
|
* Set Max Allowed Short Signals ...
|
|
* = 0 => Unlimited ...
|
|
*
|
|
* @param value: Integer ...
|
|
*/
|
|
void MaxAllowedShorts(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mMaxAllowedShorts = value;
|
|
}
|
|
|
|
/**
|
|
* Get Use Max Allowed Signals Per Symbol or at All State ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool UseMaxAllowedTradesPerSymbol()
|
|
{
|
|
return mUseMaxAllowedTradesPerSymbol;
|
|
}
|
|
|
|
/**
|
|
* Set Use Max Allowed Signals Per Symbol or at All State ...
|
|
*
|
|
* @param value: Boolean ...
|
|
*/
|
|
void UseMaxAllowedTradesPerSymbol(bool value)
|
|
{
|
|
mUseMaxAllowedTradesPerSymbol = value;
|
|
}
|
|
|
|
/**
|
|
* Get Additional Signal Volume ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double AdditionalVolume()
|
|
{
|
|
return mAdditionalVolume;
|
|
}
|
|
|
|
/**
|
|
* Set Additional Signal Volume ...
|
|
*
|
|
* @param value: Double ...
|
|
* min = 0.01
|
|
*/
|
|
void AdditionalVolume(double value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
if (value > 0 && value < 0.01)
|
|
{
|
|
value = 0.01;
|
|
}
|
|
|
|
//
|
|
mAdditionalVolume = value;
|
|
}
|
|
|
|
/**
|
|
* Get How Many Bars Must Passed after a Signal for Accept Next ...
|
|
* 0 => Unlimited ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int DelayBarBetweenTwoSignal()
|
|
{
|
|
return mDelayBarBetweenTwoSignal;
|
|
}
|
|
|
|
/**
|
|
* Set How Many Bars Must Passed after a Signal for Accept Next ...
|
|
*
|
|
* @param value: Integer ...
|
|
* 0 => Unlimited ...
|
|
*/
|
|
void DelayBarBetweenTwoSignal(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mDelayBarBetweenTwoSignal = value;
|
|
}
|
|
|
|
/**
|
|
* Get Max Allowed Drawdown Percent for Open New Positions ...
|
|
* 0 => Unlimited ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double MaxDrawdownPercentForOpenTrades()
|
|
{
|
|
return mMaxDrawdownPercentForOpenTrades;
|
|
}
|
|
|
|
/**
|
|
* Set Max Allowed Drawdown Percent for Open New Positions ...
|
|
*
|
|
* @param value: Double ...
|
|
* 0 => Unlimited ...
|
|
*/
|
|
void MaxDrawdownPercentForOpenTrades(double value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mMaxDrawdownPercentForOpenTrades = value;
|
|
}
|
|
|
|
/**
|
|
* Get Accept Next Same Type Signal only When last Issued Signal is InProfit by Points ...
|
|
*
|
|
* @return ( double )
|
|
* 0 => Accept All ...
|
|
*/
|
|
double AcceptNextSameTypeSignalWhenLastInProfit()
|
|
{
|
|
return mAcceptNextSameTypeSignalWhenLastInProfit;
|
|
}
|
|
|
|
/**
|
|
* Set Accept Next Same Type Signal only When last Issued Signal is InProfit by Points ...
|
|
*
|
|
* @param value: Double ...
|
|
* 0 => Accept All ...
|
|
*/
|
|
void AcceptNextSameTypeSignalWhenLastInProfit(double value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mAcceptNextSameTypeSignalWhenLastInProfit = value;
|
|
}
|
|
|
|
//
|
|
// Protecting Properties ...
|
|
|
|
/**
|
|
* Get Max Allower SL Per Symbol before Pausing ...
|
|
* 0 => Unlimited ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int MaxAllowedSLToPause()
|
|
{
|
|
return mMaxAllowedSLToPause;
|
|
}
|
|
|
|
/**
|
|
* Set Max Allower SL Per Symbol before Pausing ...
|
|
*
|
|
* @param value: Integer ...
|
|
* 0 => Unlimited ...
|
|
*/
|
|
void MaxAllowedSLToPause(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mMaxAllowedSLToPause = value;
|
|
}
|
|
|
|
/**
|
|
* Get Specified Delay For Pause Symbol Trade if Reached Max Allowed SL in Seconds ...
|
|
* 0 => Ignored ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int MaxAllowedSLReachedPauseDelay()
|
|
{
|
|
return mMaxAllowedSLReachedPauseDelay;
|
|
}
|
|
|
|
/**
|
|
* Set Specified Delay For Pause Symbol Trade if Reached Max Allowed SL in Seconds ...
|
|
*
|
|
* @param value: Integer ...
|
|
* 0 => Ignored ...
|
|
*/
|
|
void MaxAllowedSLReachedPauseDelay(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mMaxAllowedSLReachedPauseDelay = value;
|
|
}
|
|
|
|
//
|
|
// Hedge Props ...
|
|
|
|
/**
|
|
* Get Allow Hedge Position State ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool AllowHedge()
|
|
{
|
|
return mAllowHedge;
|
|
}
|
|
|
|
/**
|
|
* Set Allow Hedge Position State ...
|
|
*
|
|
* @param value: Boolean ...
|
|
*/
|
|
void AllowHedge(bool value)
|
|
{
|
|
mAllowHedge = value;
|
|
}
|
|
|
|
/**
|
|
* Get Minimum Volume Steps for Hedge Requirement Calculation ...
|
|
* 0 => Ignore Hedging ...
|
|
* min => 0.01 ...
|
|
* max => 0.1 ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double HedgeMinVolumeStep()
|
|
{
|
|
return mHedgeMinVolumeStep;
|
|
}
|
|
|
|
/**
|
|
* Set Minimum Volume Steps for Hedge Requirement Calculation ...
|
|
*
|
|
* @param value: Double ...
|
|
* 0 => Ignore Hedging ...
|
|
* min => 0.01 ...
|
|
* max => 0.1 ...
|
|
*/
|
|
void HedgeMinVolumeStep(double value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
if (value > 0 && value < 0.01)
|
|
{
|
|
value = 0.01;
|
|
}
|
|
|
|
//
|
|
if (value > 0 && value > 0.1)
|
|
{
|
|
value = 0.1;
|
|
}
|
|
|
|
//
|
|
mHedgeMinVolumeStep = value;
|
|
}
|
|
|
|
/**
|
|
* Get Minimum Requirement Open Positions for Hedging ...
|
|
* 0 => Ignore Hedging ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int MinimumOpenPositionsForHedge()
|
|
{
|
|
return mMinimumOpenPositionsForHedge;
|
|
}
|
|
|
|
/**
|
|
* Set Minimum Requirement Open Positions for Hedging ...
|
|
*
|
|
* @param value: Integer ...
|
|
* 0 => Ignore Hedging ...
|
|
*/
|
|
void MinimumOpenPositionsForHedge(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mMinimumOpenPositionsForHedge = value;
|
|
}
|
|
|
|
/**
|
|
* Get Minimum Required Profit Per Volume Step for Hedging ...
|
|
* 0 => Ignore Hedging ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double HedgeMinProfitPerVolumeStep()
|
|
{
|
|
return mHedgeMinProfitPerVolumeStep;
|
|
}
|
|
|
|
/**
|
|
* Set Minimum Required Profit Per Volume Step for Hedging ...
|
|
*
|
|
* @param value: Double ...
|
|
* 0 => Ignore Hedging ...
|
|
* min => 0.01 ...
|
|
*/
|
|
void HedgeMinProfitPerVolumeStep(double value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
if (value > 0 && value < 0.01)
|
|
{
|
|
value = 0.01;
|
|
}
|
|
|
|
//
|
|
mHedgeMinProfitPerVolumeStep = value;
|
|
}
|
|
|
|
//
|
|
// Actions ...
|
|
|
|
//
|
|
// Data Collection Actions ...
|
|
|
|
/**
|
|
* Add Executed Signal Data Model to Trade Datas ...
|
|
*
|
|
* @param signal: XSignal instance Reference, Issued Signal ...
|
|
*/
|
|
void Add(XSignal &signal)
|
|
{
|
|
//
|
|
// Check Signal is Valid and also not Exists
|
|
// in Datas ...
|
|
int idx = -1;
|
|
bool hasItem = HasItem(
|
|
signal,
|
|
idx //
|
|
);
|
|
if (hasItem)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Initialize Data Item and Add it to Collection of Datas
|
|
// if Everythings OK ...
|
|
X121SMCTradeData data;
|
|
bool isInited = data.Init(signal);
|
|
if (isInited)
|
|
{
|
|
//
|
|
Add(data);
|
|
SaveSignal(data);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update a Registered Data Model by Providing Specified Signal ...
|
|
* usually used When a signal Modified after Executed for Conditionally Signals ...
|
|
*
|
|
* @param signal: XSignal instance Reference, Issued Signal ...
|
|
*/
|
|
void Update(XSignal &signal)
|
|
{
|
|
//
|
|
// Validate Signal ...
|
|
if (!signal.IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check Signal Registered Before ...
|
|
int idx = -1;
|
|
bool hasItem = HasItem(
|
|
signal,
|
|
idx //
|
|
);
|
|
bool isUpdated = false;
|
|
if (!hasItem)
|
|
{
|
|
//
|
|
// Add New Item if not Exists ...
|
|
Add(signal);
|
|
isUpdated = true;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Update Data Model in Datas Collection ...
|
|
isUpdated = mData[idx].Update(signal);
|
|
}
|
|
|
|
//
|
|
if (isUpdated)
|
|
{
|
|
SaveSignal(mData[idx]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update a Registered Data Model by Providing Specified Position ...
|
|
* used for Updating Positions Data or When a Conditional Order Executed as Position ...
|
|
*
|
|
* @param position: XPosition instance Referece ...
|
|
*/
|
|
void Update(XPosition &position)
|
|
{
|
|
//
|
|
// Validate Position ...
|
|
if (!position.IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check Position Registered Before ...
|
|
int idx = -1;
|
|
bool hasItem = HasItem(
|
|
position,
|
|
idx //
|
|
);
|
|
if (!hasItem)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Update Data Model in Datas Collection ...
|
|
mData[idx].Update(position);
|
|
}
|
|
|
|
/**
|
|
* Remove Specified Registered Signal from Data Collection ...
|
|
*
|
|
* @param signal: XSignal instance Reference ...
|
|
*/
|
|
void Remove(XSignal &signal)
|
|
{
|
|
//
|
|
// Validate Signal ...
|
|
if (!signal.IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check Signal is Registered or not ...
|
|
int idx = -1;
|
|
bool hasItem = HasItem(
|
|
signal,
|
|
idx //
|
|
);
|
|
if (!hasItem)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Remove Data From Collection ...
|
|
ArrayRemove(
|
|
mData,
|
|
idx,
|
|
1 //
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Handle Position Execution Finished by Providing a Deal ...
|
|
* usually used when a Position TP/SL Triggered ...
|
|
*
|
|
* @param deal: XDeal instance Reference ...
|
|
*/
|
|
void Finish(const XDeal &deal)
|
|
{
|
|
//
|
|
// Validate Deal ...
|
|
// Check Specified Data Registered or not ...
|
|
int idx = -1;
|
|
bool hasItem = HasItem(
|
|
deal.positionId,
|
|
idx //
|
|
);
|
|
if (!hasItem)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Update Data Info ...
|
|
mData[idx].swap = deal.swap;
|
|
mData[idx].endTime = deal.time;
|
|
mData[idx].profit = deal.profit;
|
|
|
|
//
|
|
// Check Deal Reason ...
|
|
bool isTP = deal.reason == DEAL_REASON_TP;
|
|
bool isSL = deal.reason == DEAL_REASON_SL;
|
|
|
|
//
|
|
// Prepare Specified Message Based on Deal Reason ...
|
|
mData[idx].message =
|
|
isTP
|
|
? "TP"
|
|
: isSL
|
|
? "SL"
|
|
: "";
|
|
|
|
//
|
|
// Handle Symbol Positions TP or SL Actions ...
|
|
if (isTP || isSL)
|
|
{
|
|
//
|
|
// Check Symbol Position Info Model Exists ...
|
|
int symbolIDX = -1;
|
|
bool hasInfo = HasSymbol(
|
|
mData[idx].GetSymbol(),
|
|
symbolIDX //
|
|
);
|
|
|
|
//
|
|
// Try to Update or Add Symbol Position Info ...
|
|
X121SMCSymbolPositionInfo info;
|
|
if (!hasInfo)
|
|
{
|
|
//
|
|
// Add New One ...
|
|
info.symbol = mData[idx].GetSymbol();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Update Exists ...
|
|
info = mSymbolInfos[symbolIDX];
|
|
|
|
//
|
|
// Remove Exists ...
|
|
ArrayRemove(
|
|
mSymbolInfos,
|
|
symbolIDX,
|
|
1 //
|
|
);
|
|
}
|
|
|
|
//
|
|
ENUM_POSITION_TYPE xType = IsLong(mData[idx].Type())
|
|
? POSITION_TYPE_BUY
|
|
: POSITION_TYPE_SELL;
|
|
|
|
//
|
|
// Call Propper TP / SL Handlers on Symbol Position Info Model ...
|
|
if (isTP)
|
|
{
|
|
info.HandleTP(xType);
|
|
}
|
|
else if (isSL)
|
|
{
|
|
info.HandleSL(xType);
|
|
}
|
|
|
|
//
|
|
// Add Model to Symbol Positions Collection ...
|
|
AddRef(
|
|
info,
|
|
mSymbolInfos //
|
|
);
|
|
|
|
//
|
|
// Try to Check Symbol Positions Info Collection for Pause Specified Symbol ...
|
|
HandlePauseSymbol(mData[idx].GetSymbol());
|
|
}
|
|
|
|
//
|
|
// Save Collector Calss Data Model ...
|
|
Save(idx);
|
|
}
|
|
|
|
/**
|
|
* Handle Position Execution Finished by Providing some Data ...
|
|
* usually used when a Position Force Closed Triggered ...
|
|
*
|
|
* @param ticket: ULong, Position ticket ...
|
|
* @param position: XPosition instance Reference ...
|
|
* @param comment: String, Force Closing Comment ...
|
|
*/
|
|
void Finish(
|
|
const ulong ticket,
|
|
const XPosition &position,
|
|
const string comment //
|
|
)
|
|
{
|
|
//
|
|
// Validate and Check Data Registered or not ...
|
|
int idx = -1;
|
|
bool hasItem = HasItem(
|
|
ticket,
|
|
idx //
|
|
);
|
|
if (!hasItem)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Update Data Info ...
|
|
mData[idx].swap = position.swap;
|
|
mData[idx].endTime = TimeCurrent();
|
|
mData[idx].profit = position.profit;
|
|
|
|
//
|
|
mData[idx].message = comment;
|
|
|
|
//
|
|
// Handle Force Closes as TP/SL for Updating
|
|
// Symbol Info Positions ...
|
|
bool handleForceClose = true;
|
|
if (handleForceClose)
|
|
{
|
|
//
|
|
// Simulate TP/SL based on Closing Profit ...
|
|
bool isTP = position.profit > 0;
|
|
bool isSL = position.profit < 0;
|
|
|
|
//
|
|
if (isTP || isSL)
|
|
{
|
|
//
|
|
// Check Symbol Position Info Model Exists ...
|
|
int symbolIDX = -1;
|
|
bool hasInfo = HasSymbol(
|
|
mData[idx].GetSymbol(),
|
|
symbolIDX //
|
|
);
|
|
|
|
//
|
|
// Try to Update or Add Symbol Position Info ...
|
|
X121SMCSymbolPositionInfo info;
|
|
if (!hasInfo)
|
|
{
|
|
//
|
|
// Add New One ...
|
|
info.symbol = mData[idx].GetSymbol();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Update Exists ...
|
|
info = mSymbolInfos[symbolIDX];
|
|
|
|
//
|
|
// Remove Exists ...
|
|
ArrayRemove(
|
|
mSymbolInfos,
|
|
symbolIDX,
|
|
1 //
|
|
);
|
|
}
|
|
|
|
//
|
|
ENUM_POSITION_TYPE xType = IsLong(mData[idx].Type())
|
|
? POSITION_TYPE_BUY
|
|
: POSITION_TYPE_SELL;
|
|
|
|
//
|
|
// Call Propper TP / SL Handlers on Symbol Position Info Model ...
|
|
if (isTP)
|
|
{
|
|
info.HandleTP(xType);
|
|
}
|
|
else if (isSL)
|
|
{
|
|
info.HandleSL(xType);
|
|
}
|
|
|
|
//
|
|
// Add Model to Symbol Positions Collection ...
|
|
AddRef(
|
|
info,
|
|
mSymbolInfos //
|
|
);
|
|
|
|
//
|
|
// Try to Check Symbol Positions Info Collection for Pause Specified Symbol ...
|
|
HandlePauseSymbol(mData[idx].GetSymbol());
|
|
}
|
|
|
|
//
|
|
// Save Collector Calss Data Model ...
|
|
Save(idx);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update New Open Positions Data on Collection ...
|
|
*/
|
|
void HandleNewPosition()
|
|
{
|
|
//
|
|
// Retrieve Last Open Position ...
|
|
ulong lastOpenPositionTicket = mTrader.GetLastOpenPositionTicket();
|
|
if (lastOpenPositionTicket == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
XPosition position;
|
|
bool hasPosition = mTrader.GetPosition(
|
|
lastOpenPositionTicket,
|
|
position //
|
|
);
|
|
if (!hasPosition)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Calculate Position Commission ...
|
|
double commission = mTrader.GetPositionCommission(position.ticket);
|
|
position.commission = commission;
|
|
|
|
//
|
|
// Apply Updates on Data Collection ...
|
|
Update(position);
|
|
}
|
|
|
|
//
|
|
// Symbol Position Info Actions ...
|
|
|
|
/**
|
|
* Retrieve Specified Symbols Info ...
|
|
*
|
|
* @param symbol: String ...
|
|
* @param info: X121SMCSymbolPositionInfo instance ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool GetSymbolInfo(
|
|
string symbol,
|
|
X121SMCSymbolPositionInfo &info //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
info.Clean();
|
|
|
|
//
|
|
int symbolIDX = -1;
|
|
result = HasSymbol(
|
|
symbol,
|
|
symbolIDX //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
info = mSymbolInfos[symbolIDX];
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Pause Specified Symbol Trading ...
|
|
*
|
|
* @param symbol: String ...
|
|
*/
|
|
void HandlePauseSymbol(string symbol)
|
|
{
|
|
//
|
|
if (!IsValid(symbol))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int idx = -1;
|
|
bool hasItem = HasSymbol(
|
|
symbol,
|
|
idx //
|
|
);
|
|
if (!hasItem)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int maxAllowedSLToPause = MaxAllowedSLToPause();
|
|
int pauseDelay = MaxAllowedSLReachedPauseDelay();
|
|
if (maxAllowedSLToPause <= 0 || pauseDelay <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
bool canPauseSymbol =
|
|
mSymbolInfos[idx].IsEnable() &&
|
|
mSymbolInfos[idx].countedSLs >= maxAllowedSLToPause;
|
|
if (!canPauseSymbol)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
mSymbolInfos[idx].Pause(pauseDelay);
|
|
|
|
//
|
|
string message = "Pause (" + symbol + ") until: (" + ToString(mSymbolInfos[idx].enableAt) + ") ...";
|
|
Alert(message);
|
|
|
|
//
|
|
}
|
|
|
|
/**
|
|
* Reset Specified Symbol Info ...
|
|
*
|
|
* @param symbol: String ...
|
|
*/
|
|
void ResetSymbolInfo(string symbol)
|
|
{
|
|
//
|
|
if (!IsValid(symbol))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int symbolIDX = -1;
|
|
bool hasSymbol = HasSymbol(
|
|
symbol,
|
|
symbolIDX //
|
|
);
|
|
if (!hasSymbol)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
mSymbolInfos[symbolIDX].Reset();
|
|
|
|
//
|
|
string message = "Reset " + symbol + ", Pause State ...";
|
|
Alert(message);
|
|
}
|
|
|
|
/**
|
|
* Reset All Paused Symbols ...
|
|
*/
|
|
void ResumePausedSymbols()
|
|
{
|
|
//
|
|
int count = ArraySize(mSymbolInfos);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
mSymbolInfos[i].Reset();
|
|
}
|
|
|
|
//
|
|
string message = "Force Resume Paused Symbols ...";
|
|
Alert(message);
|
|
}
|
|
|
|
//
|
|
// Signal Execution Actions ...
|
|
|
|
/**
|
|
* Validate Signal For Execution ...
|
|
*
|
|
* @param signal: XSignal instance Reference ...
|
|
* @param state: ENUM_X_SIGNAL_EXECUTION_RESULT Reference for olding Signal Execution Result Reason ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool CanExecute(
|
|
XSignal &signal,
|
|
ENUM_X_SIGNAL_EXECUTION_RESULT &state // Execution State
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
state = X_SIGNAL_EXECUTION_UNKNOWN;
|
|
|
|
//
|
|
// Validate Signal ...
|
|
result = signal.IsValid();
|
|
if (!result)
|
|
{
|
|
//
|
|
state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS;
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int symbolIDX = -1;
|
|
bool hasSymbolInfo = HasSymbol(
|
|
signal.symbol,
|
|
symbolIDX //
|
|
);
|
|
|
|
//
|
|
// Check rading Not Paused ...
|
|
result =
|
|
!hasSymbolInfo ||
|
|
mSymbolInfos[symbolIDX].IsEnable();
|
|
if (!result)
|
|
{
|
|
//
|
|
state = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED;
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isLong = IsLong(signal.type);
|
|
|
|
//
|
|
// Chekc Signalling Enable or not ...
|
|
result =
|
|
isLong
|
|
? mAllowLong
|
|
: mAllowShort;
|
|
if (!result)
|
|
{
|
|
//
|
|
state = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED;
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Signal is Support or not ...
|
|
bool isSupport = IsSupport(signal.comment);
|
|
result = !isSupport;
|
|
if (!result)
|
|
{
|
|
//
|
|
state = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED;
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_X_POSITION_TYPES pType = ToPositionType(signal.type);
|
|
double requiredProfitForAcceptNext = AcceptNextSameTypeSignalWhenLastInProfit();
|
|
|
|
//
|
|
// Implement Same Signal Conditions ...
|
|
XPosition smaeSymbolPositions[];
|
|
int sameSymbolPositionsCount = mTrader.GetPositions(
|
|
smaeSymbolPositions,
|
|
signal.symbol,
|
|
signal.provider,
|
|
signal.period,
|
|
pType,
|
|
true, // Filter By Magic ...
|
|
true // Force Clean ...
|
|
);
|
|
XPosition youngestSame;
|
|
int youngestSameAge = GetYoungest(
|
|
youngestSame,
|
|
smaeSymbolPositions //
|
|
);
|
|
|
|
//
|
|
double youngestSameProfitInPoint = youngestSame.GetProfitInPoint();
|
|
|
|
//
|
|
result =
|
|
sameSymbolPositionsCount == 0 ||
|
|
(sameSymbolPositionsCount <= 0
|
|
? true
|
|
: requiredProfitForAcceptNext <= 0
|
|
? true
|
|
: youngestSameAge >= 0 &&
|
|
youngestSameProfitInPoint >= requiredProfitForAcceptNext);
|
|
if (!result)
|
|
{
|
|
//
|
|
state = X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR;
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Longs and Shorts ...
|
|
XPosition longs[];
|
|
XPosition shorts[];
|
|
bool useMaxAllowedPositionsPerSymbol = UseMaxAllowedTradesPerSymbol();
|
|
|
|
//
|
|
// Retrieve Positions ...
|
|
if (useMaxAllowedPositionsPerSymbol)
|
|
{
|
|
//
|
|
mTrader.GetPositions(
|
|
longs,
|
|
shorts,
|
|
signal.symbol //
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
mTrader.GetPositions(
|
|
longs,
|
|
shorts,
|
|
NULL // All Symbols ...
|
|
);
|
|
}
|
|
|
|
//
|
|
// Counting ...
|
|
int longsCount = ArraySize(longs);
|
|
int shortsCount = ArraySize(shorts);
|
|
|
|
//
|
|
int maxAllowedLongs = MaxAllowedLongs();
|
|
int maxAllowedShorts = MaxAllowedShorts();
|
|
|
|
//
|
|
// Check Max Allowed Positions ...
|
|
if (maxAllowedLongs > 0 ||
|
|
maxAllowedShorts > 0)
|
|
{
|
|
//
|
|
if (isLong && maxAllowedLongs > 0 && longsCount > 0)
|
|
{
|
|
result = longsCount < maxAllowedLongs;
|
|
}
|
|
else if (!isLong && maxAllowedShorts > 0 && shortsCount > 0)
|
|
{
|
|
result = shortsCount < maxAllowedShorts;
|
|
}
|
|
if (!result)
|
|
{
|
|
//
|
|
state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check Delays Bar if Provided ...
|
|
int delaysBarBetweenTwoSignal = DelayBarBetweenTwoSignal();
|
|
if (delaysBarBetweenTwoSignal > 0)
|
|
{
|
|
//
|
|
// Try To Detect Youngest Position ...
|
|
int youngestAge = 0;
|
|
XPosition youngestPosition;
|
|
|
|
//
|
|
// Long Positions when there are Longs ...
|
|
if (isLong && longsCount > 0)
|
|
{
|
|
//
|
|
youngestAge = GetYoungest(
|
|
youngestPosition,
|
|
longs //
|
|
);
|
|
}
|
|
//
|
|
// Short Positions when there are Shorts ...
|
|
else if (!isLong && shortsCount > 0)
|
|
{
|
|
//
|
|
youngestAge = GetYoungest(
|
|
youngestPosition,
|
|
shorts //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Check Delays When Youngest Position Exists ...
|
|
if (youngestAge > 0 && youngestPosition.IsValid())
|
|
{
|
|
//
|
|
result = youngestAge >= delaysBarBetweenTwoSignal;
|
|
if (!result)
|
|
{
|
|
//
|
|
state = X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check Delays When Youngest Position is not Exists ...
|
|
if (!youngestPosition.IsValid())
|
|
{
|
|
//
|
|
// Try to Detect Last Issued Signal in Model Collections ...
|
|
int symbolIDX = FindLastExecutedSignalItem(signal);
|
|
if (IsValidIndex(symbolIDX))
|
|
{
|
|
//
|
|
// Calculate Requirements ...
|
|
datetime cTime = TimeCurrent();
|
|
int signalPeriodSeconds = PeriodSeconds(signal.period);
|
|
datetime lastExecutedTime = mLastExecutedSignals[symbolIDX].time;
|
|
datetime passedTime = ((datetime)lastExecutedTime +
|
|
((delaysBarBetweenTwoSignal * signalPeriodSeconds)));
|
|
|
|
//
|
|
// Check Conditions ...
|
|
result = cTime >= passedTime;
|
|
if (!result)
|
|
{
|
|
//
|
|
state = X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED;
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check Max Drawdown Percent for Open Trades ...
|
|
double maxAllowedDrawdownPercent = MaxDrawdownPercentForOpenTrades();
|
|
if (maxAllowedDrawdownPercent > 0)
|
|
{
|
|
//
|
|
// Calculate and Update Drawdown Percent ...
|
|
double cdPercent = CalculateMaxDrawdownPercent();
|
|
|
|
//
|
|
result = cdPercent < maxAllowedDrawdownPercent;
|
|
if (!result)
|
|
{
|
|
//
|
|
state = X_SIGNAL_EXECUTION_FAILED_NO_EQUITY;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Execute Specific Signal using Trade Handler ...
|
|
*
|
|
* @param signal: XSignal instance Reference ...
|
|
* @param state: ENUM_X_SIGNAL_EXECUTION_RESULT Reference for olding Signal Execution Result Reason ...
|
|
* @param ignorePolicies: Boolean ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool ExecuteSignal(
|
|
XSignal &signal, // Signal for Execution
|
|
ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Execution State
|
|
bool ignorePolicies = false // Ignore Execution Policies
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Check Signal Validation ...
|
|
result = signal.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Policies ...
|
|
if (!ignorePolicies)
|
|
{
|
|
//
|
|
// Filter Signals if Necessary ...
|
|
result = CanExecute(
|
|
signal,
|
|
state //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Apply Additional Volume to Signal if Provided ...
|
|
double additionalVolume = AdditionalVolume();
|
|
if (additionalVolume > 0)
|
|
{
|
|
signal.volume += mAdditionalVolume;
|
|
}
|
|
|
|
//
|
|
// Execute Signal ...
|
|
result = mTrader.ExecuteSignal(
|
|
signal,
|
|
state //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
// Add XTradeHandler Data ...
|
|
Add(signal);
|
|
|
|
//
|
|
// Handle Last Executed Signal ...
|
|
HandleSignalExecuted(signal);
|
|
|
|
//
|
|
// Alert Executed Signal ...
|
|
string msg = (signal.type == POSITION_TYPE_BUY ? "Long" : "Short") +
|
|
" Signal Provided by: " + signal.provider +
|
|
(signal.pushers > 1 ? " Pushers: " + ToString(signal.pushers) : "") +
|
|
" on: " + signal.symbol +
|
|
" in: " + ToString(signal.period) +
|
|
" Executed Successfully ...";
|
|
Alert(msg);
|
|
}
|
|
|
|
//
|
|
if (!result)
|
|
{
|
|
|
|
//
|
|
// Alert Signal Execution Failed ...
|
|
string msg = "Failed To Execute " +
|
|
(signal.type == POSITION_TYPE_BUY ? "Long" : "Short") +
|
|
" Signal Provided by: " + signal.provider +
|
|
(signal.pushers > 1 ? " Pushers: " + ToString(signal.pushers) : "") +
|
|
" on: " + signal.symbol +
|
|
" in: " + ToString(signal.period) +
|
|
" due Reason: " + ToString(state) + " ...";
|
|
Alert(msg);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Timing Actions ...
|
|
|
|
/**
|
|
* Update Currently Open Positions Info on Data Collection ...
|
|
*/
|
|
void UpdateData()
|
|
{
|
|
//
|
|
// Retrieve Positions ...
|
|
XPosition positions[];
|
|
int count = mTrader.GetPositions(positions);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Loop Through Positions ...
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
// Check Position Registered as Data or not ...
|
|
int idx = -1;
|
|
bool isExists = HasItem(
|
|
iPosition.ticket,
|
|
idx //
|
|
);
|
|
if (isExists)
|
|
{
|
|
//
|
|
// Update Position Data ...
|
|
mData[idx].Update(iPosition);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle Positiona Protections
|
|
*/
|
|
void HandleProtection()
|
|
{
|
|
//
|
|
// Implement Protection Senario Here ...
|
|
int count = Count();
|
|
if (!IsValidSize(count))
|
|
{
|
|
//
|
|
currentDrawdown = 0;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Calculate Max Same Time Trades ...
|
|
maxSameTimeTrades =
|
|
maxSameTimeTrades == 0 ||
|
|
maxSameTimeTrades < count
|
|
? count
|
|
: maxSameTimeTrades;
|
|
|
|
//
|
|
double profitSummary = 0;
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
X121SMCTradeData iData = mData[i];
|
|
|
|
//
|
|
// Profit Sum ...
|
|
profitSummary += iData.profit;
|
|
|
|
//
|
|
XPosition iPosition;
|
|
bool hasPosition = mTrader.GetPosition(
|
|
iData.ticket,
|
|
iPosition //
|
|
);
|
|
if (!hasPosition)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Calculate Break Even Point ...
|
|
double entry = iPosition.entry;
|
|
double points = iData.Points();
|
|
double volume = iPosition.volume;
|
|
bool isLong = IsLong(iData.Type());
|
|
double spread = GetSpread(iData.GetSymbol());
|
|
double bep = iData.CalculateBreakEvenPoint();
|
|
double exitPrice = GetExit(
|
|
iPosition.symbol,
|
|
iPosition.type //
|
|
);
|
|
|
|
//
|
|
double tps[];
|
|
double reachedTPLevel = -1;
|
|
double reachedTPPrice = 0;
|
|
int tpLevelsCount = iPosition.CalculateTPLevels(tps);
|
|
iPosition.CalculateReahedTP(
|
|
reachedTPLevel,
|
|
reachedTPPrice //
|
|
);
|
|
|
|
//
|
|
// All Protections Done for InProfit Positions ...
|
|
if (iData.profit > 0)
|
|
{
|
|
//
|
|
// Check Break Even ...
|
|
bool canRFOnBEP = iData.CanRiskFreeOnBreakEvenPoint();
|
|
if (canRFOnBEP && reachedTPLevel > 0)
|
|
{
|
|
//
|
|
double tpLevel = iData.TPLevelForBreakEven();
|
|
int tpIDX = (int)tpLevel - 1;
|
|
double rfTPPrice = tps[tpIDX];
|
|
bool isSLReady = isLong
|
|
? iPosition.sl < rfTPPrice
|
|
: iPosition.sl > rfTPPrice;
|
|
if (isSLReady && tpLevel == reachedTPLevel - 1)
|
|
{
|
|
//
|
|
double sl = rfTPPrice;
|
|
double tp = iPosition.tp;
|
|
string comment = "RF on BEP ...";
|
|
bool isModified = mTrader.Modify(
|
|
iData.ticket,
|
|
sl,
|
|
tp,
|
|
comment //
|
|
);
|
|
if (isModified)
|
|
{
|
|
//
|
|
string message = ToString(iData.Type()) +
|
|
" Position: " +
|
|
ToString(iData.ticket) +
|
|
" RF On BEP Successfully ...";
|
|
Alert(message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Calculate Max Draw Down ...
|
|
maxDrawdown =
|
|
profitSummary < 0 &&
|
|
(maxDrawdown == 0 ||
|
|
maxDrawdown < profitSummary)
|
|
? profitSummary
|
|
: maxDrawdown;
|
|
|
|
//
|
|
// Calculate Current Drawdown ...
|
|
currentDrawdown =
|
|
profitSummary < 0
|
|
? profitSummary
|
|
: 0;
|
|
|
|
//
|
|
// TODO: Here Implement Collection Based Protections ...
|
|
|
|
//
|
|
Print("Protection");
|
|
}
|
|
|
|
//
|
|
// Protected ...
|
|
protected:
|
|
//
|
|
XCTrade *mTrader; // Instance of Trader Class
|
|
X121SMCTradeCollector *mCollector; // Instance of Trade Collector Class
|
|
|
|
//
|
|
X121SMCTradeData mData[]; // Hold Trade Data
|
|
X121SMCSymbolPositionInfo mSymbolInfos[]; // Symbol Positions Info
|
|
XSymbolLastPosition mLastExecutedSignals[]; // Last Executed Signals
|
|
|
|
//
|
|
// Hedge Related Functions ...
|
|
|
|
//
|
|
// Private ...
|
|
private:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Read Only ...
|
|
int maxSameTimeTrades; // Holds Max Same Time Trades
|
|
double maxDrawdown; // Max Drawdown
|
|
double currentDrawdown; // Current Drawdown
|
|
double drawdownPercent; // Drawdown Percent
|
|
double staticBalanceForCalculateDrawdown; // Static Balance for Max Drawdown Calculation
|
|
|
|
//
|
|
bool mSaveSignals; // Save Signals
|
|
bool mSaveTrades; // Save Trades
|
|
bool mSaveConditions; // Save SL Conditions
|
|
|
|
//
|
|
bool mAllowLong; // Allow Long/Buy Trade Type
|
|
bool mAllowShort; // Allow Short/Sell Trade Type
|
|
int mMaxAllowedLongs; // Max Allowe Long/Buy Trades
|
|
int mMaxAllowedShorts; // Max Allowe Short/Sell Trades
|
|
double mAdditionalVolume; // Volume Additional
|
|
int mDelayBarBetweenTwoSignal; // Delay Bars Between Two Signal
|
|
bool mUseMaxAllowedTradesPerSymbol; // Use Max Allowed Trades Per Symbol
|
|
double mMaxDrawdownPercentForOpenTrades; // Max Drawdown Percent for Open Trades
|
|
double mAcceptNextSameTypeSignalWhenLastInProfit; // Accept Next Same Type Signal When Last in Profit in Point
|
|
|
|
//
|
|
int mMaxAllowedSLToPause; // Max Allowed SL Per Symbol
|
|
int mMaxAllowedSLReachedPauseDelay; // Pause Symbol Trading After Max Allowed SL Reached
|
|
|
|
//
|
|
// Hedging Properties ...
|
|
bool mAllowHedge; // Allow Protector to Hedge Positions
|
|
double mHedgeMinVolumeStep; // Minimum Volume Step For Hedge
|
|
int mMinimumOpenPositionsForHedge; // Minimum Open Positions For Hedge
|
|
double mHedgeMinProfitPerVolumeStep; // Minimum Required Profit For Hedge Per Volume Step
|
|
|
|
//
|
|
XCBarAnalyser mBarAnalyser;
|
|
|
|
//
|
|
// Common Functions ...
|
|
|
|
//
|
|
// Count Data ...
|
|
int Count()
|
|
{
|
|
return ArraySize(mData);
|
|
}
|
|
|
|
//
|
|
// Add Item ...
|
|
bool Add(X121SMCTradeData &item)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = item.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int index = -1;
|
|
if (item.ticket > 0)
|
|
{
|
|
//
|
|
result = !HasItem(
|
|
item.ticket,
|
|
index //
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
result = !HasItem(
|
|
item.GetSymbol(),
|
|
item.Provider(),
|
|
item.GetPeriod(),
|
|
item.XType(),
|
|
index //
|
|
);
|
|
}
|
|
if (!result || IsValidIndex(index))
|
|
{
|
|
//
|
|
result = false;
|
|
return result;
|
|
}
|
|
|
|
//
|
|
AddRef(
|
|
item,
|
|
mData //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Item Index ...
|
|
bool HasItem(
|
|
ulong ticket,
|
|
int &index //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
index = -1;
|
|
|
|
//
|
|
int count = Count();
|
|
result = IsValidSize(count);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
result = mData[i].IsOwn(ticket);
|
|
if (result)
|
|
{
|
|
//
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool HasItem(
|
|
XSignal &signal,
|
|
int &index //
|
|
)
|
|
{
|
|
//
|
|
bool result =
|
|
//
|
|
signal.IsValid() &&
|
|
HasItem(signal.symbol,
|
|
signal.provider,
|
|
signal.period,
|
|
ToPositionType(signal.type),
|
|
index)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool HasItem(
|
|
XPosition &position,
|
|
int &index //
|
|
)
|
|
{
|
|
//
|
|
bool result =
|
|
//
|
|
position.IsValid() &&
|
|
HasItem(position.symbol,
|
|
position.provider,
|
|
position.period,
|
|
ToPositionType(position.type),
|
|
index)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Item Index ...
|
|
bool HasItem(
|
|
string symbol,
|
|
string provider,
|
|
ENUM_TIMEFRAMES period,
|
|
ENUM_X_POSITION_TYPES type,
|
|
int &index //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
index = -1;
|
|
|
|
//
|
|
// Validate ...
|
|
result =
|
|
//
|
|
IsValid(symbol) &&
|
|
IsValid(period) &&
|
|
IsValid(provider) &&
|
|
type != X_POSITION_TYPE_ALL &&
|
|
type != X_POSITION_TYPE_NONE
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int count = Count();
|
|
result = IsValidSize(count);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
result = mData[i].IsOwn(
|
|
symbol,
|
|
provider,
|
|
period,
|
|
type //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Find Specific Symbo Indo Item index ...
|
|
*
|
|
* @param symbol: String ...
|
|
* @param index: Integer ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasSymbol(
|
|
string symbol,
|
|
int &index //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
index = -1;
|
|
|
|
//
|
|
result = IsValid(symbol);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int count = ArraySize(mSymbolInfos);
|
|
result = IsValidSize(count);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
bool isOwn = mSymbolInfos[i]
|
|
.IsOwn(symbol);
|
|
if (isOwn)
|
|
{
|
|
//
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = IsValidIndex(index);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
void Save(int index)
|
|
{
|
|
//
|
|
int count = Count();
|
|
if (!IsValidIndex(index) || index > count - 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Save Trade ...
|
|
if (mSaveTrades)
|
|
{
|
|
mCollector.Save(mData[index]);
|
|
}
|
|
|
|
//
|
|
if (mSaveConditions)
|
|
{
|
|
mCollector.SaveConditions(mData[index]);
|
|
}
|
|
|
|
//
|
|
// Remove Item From List ...
|
|
ArrayRemove(
|
|
mData,
|
|
index,
|
|
1 //
|
|
);
|
|
}
|
|
|
|
//
|
|
void SaveSignal(X121SMCTradeData &item)
|
|
{
|
|
//
|
|
if (!mSaveSignals)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Save Signal ...
|
|
mCollector.SaveSignal(item);
|
|
}
|
|
|
|
//
|
|
// Find Last Signal Execution ...
|
|
int FindLastExecutedSignalItem(XSignal &signal)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (!signal.IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int count = ArraySize(mLastExecutedSignals);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XSymbolLastPosition iLast = mLastExecutedSignals[i];
|
|
if (iLast.symbol == signal.symbol &&
|
|
iLast.provider == signal.provider)
|
|
{
|
|
//
|
|
result = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Handle Last Signal Execution ...
|
|
void HandleSignalExecuted(XSignal &signal)
|
|
{
|
|
//
|
|
if (!signal.IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
datetime cTime = TimeCurrent();
|
|
int symbolIDX = FindLastExecutedSignalItem(signal);
|
|
bool hasItem = IsValidIndex(symbolIDX);
|
|
if (hasItem)
|
|
{
|
|
mLastExecutedSignals[symbolIDX].time = cTime;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
XSymbolLastPosition item;
|
|
|
|
//
|
|
item.time = cTime;
|
|
item.symbol = signal.symbol;
|
|
item.provider = signal.provider;
|
|
|
|
//
|
|
AddRef(
|
|
item,
|
|
mLastExecutedSignals //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
double CalculateMaxDrawdownPercent()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
double mEquity = mTrader.mAccount.GetEquity();
|
|
if (mEquity > currentDrawdown)
|
|
{
|
|
currentDrawdown = mEquity;
|
|
}
|
|
|
|
//
|
|
if (currentDrawdown >= 0)
|
|
{
|
|
//
|
|
drawdownPercent = 0;
|
|
return result;
|
|
}
|
|
|
|
//
|
|
drawdownPercent = (currentDrawdown - mEquity) /
|
|
(staticBalanceForCalculateDrawdown > 0
|
|
? staticBalanceForCalculateDrawdown
|
|
: currentDrawdown) *
|
|
100;
|
|
drawdownPercent = NormalizeDouble(drawdownPercent, 3);
|
|
result = drawdownPercent;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// End of XC121SMCTradeHandler Class ...
|
|
};
|
|
|
|
// |