3990 lines
192 KiB
Plaintext
3990 lines
192 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Class Library
|
|
// ----------------------------------------------
|
|
// Name: X121SCTradeHandler
|
|
// Description: provides all Trade Handling requirements ...
|
|
//
|
|
//
|
|
// 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.xtrade.class.mq5"
|
|
#include "../Parsers/x-saherelm.x121.parser.mq5"
|
|
|
|
//
|
|
// Definitions ...
|
|
|
|
//
|
|
// an Structure for Holding Positions Data ...
|
|
struct X121TradeData
|
|
{
|
|
//
|
|
datetime time; // Issue Time (Open Position)
|
|
string symbol; // Trading Symbol
|
|
double entry; // Entry Price
|
|
double volume; // Volume
|
|
string provider; // Signaller
|
|
ENUM_TIMEFRAMES period; // Trading Timeframe
|
|
ENUM_X_POSITION_TYPES type; // Position Type
|
|
|
|
//
|
|
ulong ticket; // Position Ticket
|
|
double swap; // Swap
|
|
double profit; // Profit on Close
|
|
double commission; // Commission
|
|
double maxDrawdown; // Max Position Drawdown
|
|
string message; // Close Reason
|
|
datetime endTime; // End Time
|
|
|
|
//
|
|
XSignal signal; // Signal Object
|
|
int pushers; // Signal Pushers
|
|
string conditions; // Signal Conditions
|
|
|
|
//
|
|
int trailStep; // Trail Step
|
|
bool partiallyClosed; // Partially Closed or not
|
|
datetime lastProtectedOn; // Last Protected On
|
|
|
|
//
|
|
// Constructor ...
|
|
void XTradeInfo()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Filling Trade Handler ...
|
|
bool Fill(XSignal &_signal)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
Clean();
|
|
|
|
//
|
|
// Check Signal Validation ...
|
|
result = _signal.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
signal = _signal;
|
|
time = _signal.time;
|
|
entry = _signal.entry;
|
|
symbol = _signal.symbol;
|
|
volume = _signal.volume;
|
|
period = _signal.period;
|
|
pushers = _signal.pushers;
|
|
provider = _signal.provider;
|
|
conditions = _signal.conditions;
|
|
type = ToPositionType(_signal.type);
|
|
|
|
//
|
|
if (_signal.IsExecuted())
|
|
{
|
|
ticket = _signal.positionId;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Filling Trade Handler ...
|
|
bool Fill(XPosition &_position)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
Clean();
|
|
|
|
//
|
|
// Check Signal Validation ...
|
|
result = _position.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
time = _position.openAt;
|
|
symbol = _position.symbol;
|
|
entry = _position.entry;
|
|
volume = _position.volume;
|
|
provider = _position.provider;
|
|
period = _position.period;
|
|
type = ToPositionType(_position.type);
|
|
|
|
//
|
|
ticket = _position.ticket;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Update Data ...
|
|
bool Update(XPosition &_position)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = _position.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
profit = _position.profit;
|
|
swap = _position.swap;
|
|
|
|
//
|
|
if (profit < 0 &&
|
|
(maxDrawdown == 0 ||
|
|
MathAbs(profit) > MathAbs(maxDrawdown)))
|
|
{
|
|
maxDrawdown = profit;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
time = NULL;
|
|
type = NULL;
|
|
symbol = NULL;
|
|
period = NULL;
|
|
endTime = NULL;
|
|
message = NULL;
|
|
provider = NULL;
|
|
|
|
//
|
|
swap = 0;
|
|
entry = 0;
|
|
ticket = 0;
|
|
profit = 0;
|
|
volume = 0;
|
|
commission = 0;
|
|
maxDrawdown = 0;
|
|
|
|
//
|
|
trailStep = 0;
|
|
lastProtectedOn = NULL;
|
|
partiallyClosed = false;
|
|
|
|
//
|
|
signal.Clean();
|
|
}
|
|
|
|
//
|
|
// Validation ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
ticket > 0 &&
|
|
IsValid(time) &&
|
|
IsValid(symbol) &&
|
|
IsValid(period)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Trade Data Age ...
|
|
int GetAge()
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (!IsValid(symbol) ||
|
|
!IsValid(time) ||
|
|
!IsValid(endTime) ||
|
|
!IsValid(period))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int startIndex = iBarShift(
|
|
symbol,
|
|
period,
|
|
time,
|
|
false //
|
|
);
|
|
|
|
//
|
|
int endIndex = iBarShift(
|
|
symbol,
|
|
period,
|
|
endTime,
|
|
false //
|
|
);
|
|
|
|
//
|
|
result = MathAbs(startIndex - endIndex);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Own of Trade Data ...
|
|
// based on Ticket ...
|
|
bool IsOwn(
|
|
ulong _ticket //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = _ticket == ticket;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Own of Trade Data ...
|
|
// based on Symbol/Provider and Period ...
|
|
bool IsOwn(
|
|
string _symbol,
|
|
string _provider,
|
|
ENUM_TIMEFRAMES _period,
|
|
ENUM_X_POSITION_TYPES _type //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid(_symbol) &&
|
|
IsValid(_period) &&
|
|
IsValid(_provider) &&
|
|
type != X_POSITION_TYPE_ALL &&
|
|
type != X_POSITION_TYPE_NONE &&
|
|
//
|
|
type == _type &&
|
|
period == _period &&
|
|
symbol == _symbol &&
|
|
provider == _provider
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Data Collector ...
|
|
|
|
//
|
|
// Get Data File Name ...
|
|
string GetFileName()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
symbol + "\\" +
|
|
ToString(type) + "\\" +
|
|
(profit >= 0 ? "Profit" : "Loss") + "\\" +
|
|
ToString(ticket) + "_" +
|
|
ToString(period) + "_" +
|
|
ToFormatString(time)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Signal File Name ...
|
|
string GetSignalFileName()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
result =
|
|
//
|
|
symbol + "\\" +
|
|
ToString(type) + "\\" +
|
|
provider + "_" +
|
|
ToFormatString(time)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Convert(s) To String Representation(s) ...
|
|
string ToString(
|
|
bool onlySignals = false //
|
|
)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
int age = GetAge();
|
|
|
|
//
|
|
result =
|
|
//
|
|
(onlySignals ? "" : ToString("Ticket", ticket)) +
|
|
ToString("Symbol", symbol) +
|
|
ToString("Period", period) +
|
|
ToString("Entry", entry) +
|
|
ToString("Provider", provider) +
|
|
ToString("Type", ToString(type)) +
|
|
ToString("Time", time) +
|
|
//
|
|
// 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", pushers) +
|
|
"Conditions:" + "\n" +
|
|
"-------------" + "\n" +
|
|
conditions +
|
|
""
|
|
//
|
|
) +
|
|
//
|
|
""
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
struct XSymbolData
|
|
{
|
|
//
|
|
string symbol;
|
|
int longSL;
|
|
int shortSL;
|
|
datetime disableLong;
|
|
datetime disableShort;
|
|
|
|
//
|
|
void XSymbolData()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
void Clean()
|
|
{
|
|
//
|
|
symbol = NULL;
|
|
longSL = 0;
|
|
shortSL = 0;
|
|
disableLong = NULL;
|
|
disableShort = NULL;
|
|
}
|
|
|
|
//
|
|
bool CanLong()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
datetime cTime = TimeCurrent();
|
|
|
|
//
|
|
result = !IsValid(disableLong) ||
|
|
(IsValid(disableLong) &&
|
|
cTime > disableLong);
|
|
if (result)
|
|
{
|
|
disableLong = NULL;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool CanShort()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
datetime cTime = TimeCurrent();
|
|
|
|
//
|
|
result = !IsValid(disableShort) ||
|
|
(IsValid(disableShort) &&
|
|
cTime > disableShort);
|
|
if (result)
|
|
{
|
|
disableShort = NULL;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Model a Position and it's Protected Positions ...
|
|
struct XProtectedPosition
|
|
{
|
|
//
|
|
XPosition main; // Main Position ...
|
|
X121TradeData data; // Trade Handler Data ...
|
|
|
|
//
|
|
XPosition supports[]; // Support Positions ...
|
|
|
|
/**
|
|
* Count Supported Positions
|
|
*/
|
|
int CountSupports()
|
|
{
|
|
return ArraySize(supports);
|
|
}
|
|
|
|
/**
|
|
* Extract All Positions into Specified Array
|
|
* of Positions ...
|
|
*/
|
|
int ExtractPositions(
|
|
XPosition &positions[] //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
if (main.IsValid())
|
|
{
|
|
//
|
|
AddRef(
|
|
main,
|
|
positions //
|
|
);
|
|
}
|
|
|
|
//
|
|
int supportsCount = CountSupports();
|
|
if (IsValidSize(supportsCount))
|
|
{
|
|
//
|
|
Copy(
|
|
supports,
|
|
positions,
|
|
false //
|
|
);
|
|
}
|
|
|
|
//
|
|
result = ArraySize(positions);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Implementation ...
|
|
|
|
//
|
|
// a Class For Read and Write Trade Info Data in Files ...
|
|
class X121TradeCollector
|
|
{
|
|
//
|
|
// Public ...
|
|
public:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Constructor(s) ...
|
|
void X121TradeCollector(
|
|
string _path = NULL // Base Path
|
|
)
|
|
{
|
|
//
|
|
mAccount = new XSCAccount();
|
|
|
|
//
|
|
if (IsValid(_path))
|
|
{
|
|
mPath = _path;
|
|
}
|
|
else
|
|
{
|
|
mPath = "X121TradeData" + "\\" + mAccount.GetCompany();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~X121TradeCollector()
|
|
{
|
|
}
|
|
|
|
//
|
|
bool IsExists(X121TradeData &item)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int mHandler = GetFileHandlerForRead(item);
|
|
result = mHandler != INVALID_HANDLE;
|
|
FileClose(mHandler);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool Save(X121TradeData &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;
|
|
}
|
|
|
|
//
|
|
bool SaveSignal(X121TradeData &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;
|
|
}
|
|
|
|
//
|
|
// Conditions only save for Loss Signals ...
|
|
// this means the profit must be Lower than Zero ...
|
|
// ans also message Contains SL ...
|
|
bool SaveConditions(X121TradeData &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 ...
|
|
|
|
//
|
|
XSCAccount *mAccount;
|
|
|
|
//
|
|
string GetFilePath(X121TradeData &item)
|
|
{
|
|
//
|
|
string fileName = item.GetFileName();
|
|
|
|
//
|
|
return GetFilePath(fileName);
|
|
}
|
|
string GetFilePath(string fileName)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
result =
|
|
//
|
|
mPath + "\\" + "Trades" + "\\" + fileName + ".x121.log"
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string GetSignalFilePath(X121TradeData &item)
|
|
{
|
|
//
|
|
string fileName = item.GetSignalFileName();
|
|
|
|
//
|
|
return GetSignalFilePath(fileName);
|
|
}
|
|
string GetSignalFilePath(string fileName)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
result =
|
|
//
|
|
mPath + "\\" + "Signals" + "\\" + fileName + ".x121.log"
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string GetConditionsFilePath(X121TradeData &item)
|
|
{
|
|
//
|
|
bool isLong = IsLong(item.type);
|
|
|
|
//
|
|
string fileName =
|
|
item.symbol + "\\" +
|
|
(isLong ? "Longs" : "Shorts");
|
|
|
|
//
|
|
return GetConditionsFilePath(fileName);
|
|
}
|
|
string GetConditionsFilePath(string fileName)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
result =
|
|
//
|
|
mPath + "\\" + "Conditions" + "\\" + fileName + ".x121.log"
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetFileHandlerForRead(X121TradeData &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(X121TradeData &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(X121TradeData &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(X121TradeData &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(X121TradeData &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(X121TradeData &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;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Trade Handler Class ...
|
|
class X121SCTradeHandler : public XSCBaseAlert
|
|
{
|
|
//
|
|
// Public ...
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor(s) ...
|
|
void X121SCTradeHandler(XSCTrade *trader)
|
|
{
|
|
//
|
|
mTrader = trader;
|
|
lastSignalOn = NULL;
|
|
mAdditionalVolume = 0;
|
|
mCollector = new X121TradeCollector();
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~X121SCTradeHandler()
|
|
{
|
|
//
|
|
delete mTrader;
|
|
delete mCollector;
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
//
|
|
bool SaveSignals()
|
|
{
|
|
return mSaveSignals;
|
|
}
|
|
|
|
//
|
|
void SaveSignals(bool value)
|
|
{
|
|
mSaveSignals = value;
|
|
}
|
|
|
|
//
|
|
bool SaveTrades()
|
|
{
|
|
return mSaveTrades;
|
|
}
|
|
|
|
//
|
|
void SaveTrades(bool value)
|
|
{
|
|
mSaveTrades = value;
|
|
}
|
|
|
|
//
|
|
bool SaveConditions()
|
|
{
|
|
return mSaveConditions;
|
|
}
|
|
|
|
//
|
|
void SaveConditions(bool value)
|
|
{
|
|
mSaveConditions = value;
|
|
}
|
|
|
|
//
|
|
bool AllowLong()
|
|
{
|
|
return mAllowLong;
|
|
}
|
|
|
|
//
|
|
void AllowLong(bool value)
|
|
{
|
|
mAllowLong = value;
|
|
}
|
|
|
|
//
|
|
bool AllowShort()
|
|
{
|
|
return mAllowShort;
|
|
}
|
|
|
|
//
|
|
void AllowShort(bool value)
|
|
{
|
|
mAllowShort = value;
|
|
}
|
|
|
|
//
|
|
int MaxAllowedLongs()
|
|
{
|
|
return mMaxAllowedLongs;
|
|
}
|
|
|
|
//
|
|
void MaxAllowedLongs(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mMaxAllowedLongs = value;
|
|
}
|
|
|
|
//
|
|
int MaxAllowedShorts()
|
|
{
|
|
return mMaxAllowedShorts;
|
|
}
|
|
|
|
//
|
|
void MaxAllowedShorts(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mMaxAllowedShorts = value;
|
|
}
|
|
|
|
//
|
|
bool UseMaxAllowedTradesPerSymbol()
|
|
{
|
|
return mUseMaxAllowedTradesPerSymbol;
|
|
}
|
|
|
|
//
|
|
void UseMaxAllowedTradesPerSymbol(bool value)
|
|
{
|
|
mUseMaxAllowedTradesPerSymbol = value;
|
|
}
|
|
|
|
//
|
|
double MaxDrawdownPercentForOpenTrades()
|
|
{
|
|
return mMaxDrawdownPercentForOpenTrades;
|
|
}
|
|
|
|
//
|
|
void MaxDrawdownPercentForOpenTrades(double value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mMaxDrawdownPercentForOpenTrades = value;
|
|
}
|
|
|
|
//
|
|
int NumberOfSLForPauseSignalling()
|
|
{
|
|
return mNumberOfSLForPauseSignalling;
|
|
}
|
|
|
|
//
|
|
void NumberOfSLForPauseSignalling(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mNumberOfSLForPauseSignalling = value;
|
|
}
|
|
|
|
//
|
|
int SignallingPauseDelayInMinute()
|
|
{
|
|
return mSignallingPauseDelayInMinute;
|
|
}
|
|
|
|
//
|
|
void SignallingPauseDelayInMinute(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mSignallingPauseDelayInMinute = value;
|
|
}
|
|
|
|
//
|
|
// Protector Start ...
|
|
|
|
//
|
|
bool UseForceMomentumsInProtection()
|
|
{
|
|
return mUseForceMomentumsInProtection;
|
|
}
|
|
|
|
//
|
|
void UseForceMomentumsInProtection(bool value)
|
|
{
|
|
mUseForceMomentumsInProtection = value;
|
|
}
|
|
|
|
//
|
|
int DelayBarBetweenTwoSignal()
|
|
{
|
|
return mDelayBarBetweenTwoSignal;
|
|
}
|
|
|
|
//
|
|
void DelayBarBetweenTwoSignal(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mDelayBarBetweenTwoSignal = value;
|
|
}
|
|
|
|
//
|
|
double AcceptNextSameTypeSignalWhenLastInProfit()
|
|
{
|
|
return mAcceptNextSameTypeSignalWhenLastInProfit;
|
|
}
|
|
|
|
//
|
|
void AcceptNextSameTypeSignalWhenLastInProfit(double value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mAcceptNextSameTypeSignalWhenLastInProfit = value;
|
|
}
|
|
|
|
//
|
|
// In Profit Position Protecting ...
|
|
|
|
//
|
|
// Trail ...
|
|
|
|
//
|
|
bool AllowTrail()
|
|
{
|
|
return mAllowTrail;
|
|
}
|
|
|
|
//
|
|
void AllowTrail(bool value)
|
|
{
|
|
mAllowTrail = value;
|
|
}
|
|
|
|
//
|
|
double TrailStartDistance()
|
|
{
|
|
return mTrailStartDistance;
|
|
}
|
|
|
|
//
|
|
void TrailStartDistance(double value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mTrailStartDistance = value;
|
|
}
|
|
|
|
//
|
|
double TrailStep()
|
|
{
|
|
return mTrailStep;
|
|
}
|
|
|
|
//
|
|
void TrailStep(double value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mTrailStep = value;
|
|
}
|
|
|
|
//
|
|
int RemoveTPAfterTrailedLevel()
|
|
{
|
|
return mRemoveTPAfterTrailedLevel;
|
|
}
|
|
|
|
//
|
|
void RemoveTPAfterTrailedLevel(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mRemoveTPAfterTrailedLevel = value;
|
|
}
|
|
|
|
//
|
|
bool OnlyTrailUnprotected()
|
|
{
|
|
return mOnlyTrailUnprotected;
|
|
}
|
|
|
|
//
|
|
void OnlyTrailUnprotected(bool value)
|
|
{
|
|
mOnlyTrailUnprotected = value;
|
|
}
|
|
|
|
//
|
|
// Partial Close (In Profit) ...
|
|
|
|
//
|
|
double PartialCloseInProfitDistance()
|
|
{
|
|
return mPartialCloseInProfitDistance;
|
|
}
|
|
|
|
//
|
|
void PartialCloseInProfitDistance(double value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mPartialCloseInProfitDistance = value;
|
|
}
|
|
|
|
//
|
|
double PartialCloseInProfitVolume()
|
|
{
|
|
return mPartialCloseInProfitVolume;
|
|
}
|
|
|
|
//
|
|
void PartialCloseInProfitVolume(double value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mPartialCloseInProfitVolume = value;
|
|
}
|
|
|
|
//
|
|
// In Drawdown Positions Protecting ...
|
|
|
|
//
|
|
// Protect ...
|
|
|
|
//
|
|
bool AllowProtect()
|
|
{
|
|
return mAllowProtect;
|
|
}
|
|
|
|
//
|
|
void AllowProtect(bool value)
|
|
{
|
|
mAllowProtect = value;
|
|
}
|
|
|
|
//
|
|
double ProtectionStartDistance()
|
|
{
|
|
return mProtectionStartDistance;
|
|
}
|
|
|
|
//
|
|
void ProtectionStartDistance(double value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mProtectionStartDistance = value;
|
|
}
|
|
|
|
//
|
|
int ProtectionDelay()
|
|
{
|
|
return mProtectionDelay;
|
|
}
|
|
|
|
//
|
|
void ProtectionDelay(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mProtectionDelay = value;
|
|
}
|
|
|
|
//
|
|
double ProtectionVolumeMultiplier()
|
|
{
|
|
return mProtectionVolumeMultiplier;
|
|
}
|
|
|
|
//
|
|
void ProtectionVolumeMultiplier(double value)
|
|
{
|
|
//
|
|
if (value < 1)
|
|
{
|
|
value = 1;
|
|
}
|
|
|
|
//
|
|
mProtectionVolumeMultiplier = value;
|
|
}
|
|
|
|
//
|
|
int MaxAllowedProtection()
|
|
{
|
|
return mMaxAllowedProtection;
|
|
}
|
|
|
|
//
|
|
void MaxAllowedProtection(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mMaxAllowedProtection = value;
|
|
}
|
|
|
|
//
|
|
bool UseEntryAsProtectionSL()
|
|
{
|
|
return mUseEntryAsProtectionSL;
|
|
}
|
|
|
|
//
|
|
void UseEntryAsProtectionSL(bool value)
|
|
{
|
|
mUseEntryAsProtectionSL = value;
|
|
}
|
|
|
|
//
|
|
bool ProtectOnConditions()
|
|
{
|
|
return mProtectOnConditions;
|
|
}
|
|
|
|
//
|
|
void ProtectOnConditions(bool value)
|
|
{
|
|
mProtectOnConditions = value;
|
|
}
|
|
|
|
//
|
|
bool AllowDirectionProtct()
|
|
{
|
|
return mAllowDirectionProtct;
|
|
}
|
|
|
|
//
|
|
void AllowDirectionProtct(bool value)
|
|
{
|
|
mAllowDirectionProtct = value;
|
|
}
|
|
|
|
//
|
|
// Partial Close (In Drawdown) ...
|
|
|
|
//
|
|
double PartialCloseInDrawdownDistance()
|
|
{
|
|
return mPartialCloseInDrawdownDistance;
|
|
}
|
|
|
|
//
|
|
void PartialCloseInDrawdownDistance(double value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mPartialCloseInDrawdownDistance = value;
|
|
}
|
|
|
|
//
|
|
double PartialCloseInDrawdownVolume()
|
|
{
|
|
return mPartialCloseInDrawdownVolume;
|
|
}
|
|
|
|
//
|
|
void PartialCloseInDrawdownVolume(double value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mPartialCloseInDrawdownVolume = value;
|
|
}
|
|
|
|
//
|
|
// Hedge Props ...
|
|
|
|
//
|
|
bool AllowHedge()
|
|
{
|
|
return mAllowHedge;
|
|
}
|
|
|
|
//
|
|
void AllowHedge(bool value)
|
|
{
|
|
mAllowHedge = value;
|
|
}
|
|
|
|
//
|
|
double HedgeMinVolumeStep()
|
|
{
|
|
return mHedgeMinVolumeStep;
|
|
}
|
|
|
|
//
|
|
// Min: 0.01
|
|
// Max 0.1
|
|
void HedgeMinVolumeStep(double value)
|
|
{
|
|
//
|
|
if (value < 0.01)
|
|
{
|
|
value = 0.01;
|
|
}
|
|
|
|
//
|
|
if (value > 0.1)
|
|
{
|
|
value = 0.1;
|
|
}
|
|
|
|
//
|
|
mHedgeMinVolumeStep = value;
|
|
}
|
|
|
|
//
|
|
int MinimumOpenPositionsForHEHedge()
|
|
{
|
|
return mMinimumOpenPositionsForHEHedge;
|
|
}
|
|
|
|
//
|
|
void MinimumOpenPositionsForHEHedge(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mMinimumOpenPositionsForHEHedge = value;
|
|
}
|
|
|
|
//
|
|
double HedgeHEMinProfitPerVolumeStep()
|
|
{
|
|
return mHedgeHEMinProfitPerVolumeStep;
|
|
}
|
|
|
|
//
|
|
// Min: 0.01
|
|
void HedgeHEMinProfitPerVolumeStep(double value)
|
|
{
|
|
//
|
|
if (value < 0.01)
|
|
{
|
|
value = 0.01;
|
|
}
|
|
|
|
//
|
|
mHedgeHEMinProfitPerVolumeStep = value;
|
|
}
|
|
|
|
//
|
|
double HedgeBEMinProfitPerVolumeStep()
|
|
{
|
|
return mHedgeBEMinProfitPerVolumeStep;
|
|
}
|
|
|
|
//
|
|
// Min: 0.01
|
|
void HedgeBEMinProfitPerVolumeStep(double value)
|
|
{
|
|
//
|
|
if (value < 0.01)
|
|
{
|
|
value = 0.01;
|
|
}
|
|
|
|
//
|
|
mHedgeBEMinProfitPerVolumeStep = value;
|
|
}
|
|
|
|
//
|
|
// Read Only Props ...
|
|
|
|
//
|
|
int MaxSameTimeTrades()
|
|
{
|
|
return maxSameTimeTrades;
|
|
}
|
|
|
|
//
|
|
// Calculate Max Drawdown and it's Percent ...
|
|
double GetMaxDrawdown()
|
|
{
|
|
//
|
|
XPosition positions[];
|
|
int positionsCount = mTrader.GetPositions(positions);
|
|
if (IsValidSize(positionsCount))
|
|
{
|
|
double mEquity = mTrader.mAccount.GetEquity();
|
|
if (mEquity > maxDrawdown)
|
|
{
|
|
maxDrawdown = mEquity;
|
|
}
|
|
|
|
//
|
|
drawdownPercent = (maxDrawdown - mEquity) / (staticBalanceForCalculateDrawdown > 0 ? staticBalanceForCalculateDrawdown : maxDrawdown) * 100;
|
|
drawdownPercent = NormalizeDouble(drawdownPercent, 3);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
maxDrawdown = 0.0;
|
|
drawdownPercent = 0.0;
|
|
}
|
|
|
|
//
|
|
return drawdownPercent;
|
|
}
|
|
|
|
//
|
|
double AdditionalVolume()
|
|
{
|
|
return mAdditionalVolume;
|
|
}
|
|
|
|
//
|
|
// Position Retrievers ...
|
|
|
|
/**
|
|
* Retrieve Positions as XProtetedPosition structure
|
|
* @param positions: Argument 1
|
|
* @return ( int )
|
|
*/
|
|
int GetPositions(
|
|
XProtectedPosition &positions[] //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
// Retrieve Positions from Trader Class ...
|
|
XPosition allPositions[];
|
|
int allPositionsCount = mTrader.GetPositions(
|
|
allPositions,
|
|
NULL, // All Symbols ...
|
|
NULL, // All Providers ...
|
|
NULL, // All Periods ...
|
|
X_POSITION_TYPE_ALL, // Long and Short ...
|
|
false, // Filter By Magic ...
|
|
true // Force Clean ...
|
|
);
|
|
if (!IsValidSize(allPositionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Filter Support Positions ...
|
|
XPosition mainPositions[];
|
|
XPosition supportPositions[];
|
|
for (int i = 0; i < allPositionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = allPositions[i];
|
|
|
|
//
|
|
// Check Validation ...
|
|
if (!iPosition.IsValid())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check Position Support or not ...
|
|
bool isSupport = IsSupport(iPosition.comment);
|
|
if (isSupport)
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
supportPositions //
|
|
);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
mainPositions //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Check Main Positions Count ...
|
|
int mainPositionsCount = ArraySize(mainPositions);
|
|
if (!IsValidSize(mainPositionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int supportPositionsCount = ArraySize(supportPositions);
|
|
|
|
//
|
|
for (int i = 0; i < mainPositionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = mainPositions[i];
|
|
|
|
//
|
|
XProtectedPosition iProtected;
|
|
iProtected.main = iPosition;
|
|
Clean(iProtected.supports);
|
|
|
|
//
|
|
// Loop Through Support Positions To Find iPositions Support ...
|
|
if (IsValidSize(supportPositionsCount))
|
|
{
|
|
//
|
|
for (int j = 0; j < supportPositionsCount; j++)
|
|
{
|
|
//
|
|
XPosition jSupport = supportPositions[j];
|
|
|
|
//
|
|
ulong supportParentTicket = ExtractSupportedTicket(jSupport.comment);
|
|
bool isSupport = supportParentTicket > 0;
|
|
if (isSupport &&
|
|
supportParentTicket == iPosition.ticket)
|
|
{
|
|
//
|
|
AddRef(
|
|
jSupport,
|
|
iProtected.supports //
|
|
);
|
|
}
|
|
|
|
//
|
|
ulong eqmSupportParentTicket = ExtractEQMSupportedTicket(jSupport.comment);
|
|
bool isEQMSupport = eqmSupportParentTicket > 0;
|
|
if (isEQMSupport &&
|
|
eqmSupportParentTicket == iPosition.ticket)
|
|
{
|
|
//
|
|
AddRef(
|
|
jSupport,
|
|
iProtected.supports //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Findout X121TradeData ...
|
|
int iIDX = -1;
|
|
bool hasItem = HasItem(
|
|
iPosition.ticket,
|
|
iIDX //
|
|
);
|
|
if (hasItem && IsValidIndex(iIDX))
|
|
{
|
|
iProtected.data = mData[iIDX];
|
|
}
|
|
|
|
//
|
|
AddRef(
|
|
iProtected,
|
|
positions //
|
|
);
|
|
}
|
|
|
|
//
|
|
Clean(allPositions);
|
|
Clean(mainPositions);
|
|
Clean(supportPositions);
|
|
|
|
//
|
|
result = ArraySize(positions);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Trade Handling Functions ...
|
|
|
|
//
|
|
// First Step of Trade Handling ...
|
|
// Since Must Call when a Signal Executed ...
|
|
void AddData(
|
|
XSignal &signal, // Executed Signal
|
|
double commission = 0 // Commission
|
|
)
|
|
{
|
|
//
|
|
// Check Signal Valid ...
|
|
if (!signal.IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check Signal Support or Recovery ...
|
|
bool isSupport = IsSupport(signal.comment);
|
|
bool isRecovery = ExtractRecoveredTicket(signal.comment) > 0;
|
|
|
|
//
|
|
X121TradeData item;
|
|
bool isFilled = item.Fill(signal);
|
|
if (!isFilled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
item.commission = commission;
|
|
|
|
//
|
|
Add(item);
|
|
|
|
//
|
|
SaveSignal(item);
|
|
}
|
|
|
|
//
|
|
void Finish(const XDeal &deal)
|
|
{
|
|
//
|
|
int idx = -1;
|
|
bool hasItem = HasItem(
|
|
deal.positionId,
|
|
idx //
|
|
);
|
|
if (!hasItem)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Update Item Info ...
|
|
mData[idx].swap = deal.swap;
|
|
mData[idx].endTime = deal.time;
|
|
mData[idx].profit = deal.profit;
|
|
|
|
//
|
|
mData[idx].message =
|
|
deal.reason == DEAL_REASON_TP ? "TP" : "SL";
|
|
|
|
//
|
|
Save(idx);
|
|
}
|
|
|
|
//
|
|
void Finish(
|
|
const ulong ticket,
|
|
const XPosition &position,
|
|
const string comment //
|
|
)
|
|
{
|
|
//
|
|
int idx = -1;
|
|
bool hasItem = HasItem(
|
|
ticket,
|
|
idx //
|
|
);
|
|
if (!hasItem)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Update Item Info ...
|
|
mData[idx].swap = position.swap;
|
|
mData[idx].endTime = TimeCurrent();
|
|
mData[idx].profit = position.profit;
|
|
|
|
//
|
|
mData[idx].message = comment;
|
|
|
|
//
|
|
Save(idx);
|
|
}
|
|
|
|
//
|
|
// this Method call's by a Timer,
|
|
// or in OnTick for Update Positions,
|
|
// Data ...
|
|
void UpdateData()
|
|
{
|
|
//
|
|
XPosition positions[];
|
|
int count = mTrader.GetPositions(positions);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
int idx = -1;
|
|
bool isExists = HasItem(
|
|
iPosition.ticket,
|
|
idx //
|
|
);
|
|
if (!isExists)
|
|
{
|
|
//
|
|
// Add New Data ...
|
|
|
|
//
|
|
// Find Executed Signal Deal History ...
|
|
XDeal deals[];
|
|
double commission = 0;
|
|
int dealsCount = mTrader.GetDeals(
|
|
deals,
|
|
iPosition.symbol,
|
|
iPosition.provider,
|
|
iPosition.period,
|
|
NULL,
|
|
DEAL_ENTRY_IN //
|
|
);
|
|
if (IsValidSize(dealsCount))
|
|
{
|
|
//
|
|
for (int i = 0; i < dealsCount; i++)
|
|
{
|
|
//
|
|
XDeal iDeal = deals[i];
|
|
if (iDeal.positionId == iPosition.ticket)
|
|
{
|
|
//
|
|
commission = iDeal.commission;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
X121TradeData iData;
|
|
iData.Fill(
|
|
iPosition //
|
|
);
|
|
|
|
//
|
|
iData.ticket = iPosition.ticket;
|
|
|
|
//
|
|
Add(iData);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Update Exists ...
|
|
mData[idx].Update(iPosition);
|
|
}
|
|
}
|
|
|
|
//
|
|
count = Count();
|
|
if (count > maxSameTimeTrades)
|
|
{
|
|
maxSameTimeTrades = count;
|
|
}
|
|
|
|
//
|
|
GetMaxDrawdown();
|
|
}
|
|
|
|
//
|
|
void UpdateSignal(XSignal &signal)
|
|
{
|
|
//
|
|
if (!signal.IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int count = Count();
|
|
if (!IsValidSize(count))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
bool isOwn = mData[i].IsOwn(
|
|
signal.symbol,
|
|
signal.provider,
|
|
signal.period,
|
|
ToPositionType(signal.type) //
|
|
);
|
|
if (isOwn)
|
|
{
|
|
mData[i].Fill(signal);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
void RemoveSignal(XSignal &signal)
|
|
{
|
|
//
|
|
if (!signal.IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int signalIDX = -1;
|
|
ENUM_X_POSITION_TYPES xType = ToPositionType(signal.type);
|
|
bool hasSignal = HasItem(
|
|
signal.symbol,
|
|
signal.provider,
|
|
signal.period,
|
|
xType,
|
|
signalIDX //
|
|
);
|
|
if (!hasSignal || !IsValidIndex(signalIDX))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Remove Item From List ...
|
|
ArrayRemove(
|
|
mData,
|
|
signalIDX,
|
|
1 //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Position Execute and Sync Functions ...
|
|
|
|
/**
|
|
* Validate Signal For Execution ...
|
|
*/
|
|
bool CanExecute(XSignal &signal)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Signal ...
|
|
result = signal.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isLong = IsLong(signal.type);
|
|
|
|
//
|
|
// Chekc Signalling Enable or not ...
|
|
result =
|
|
isLong
|
|
? mAllowLong
|
|
: mAllowShort;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Signal is Support or not ...
|
|
bool isSupport = IsSupport(signal.comment);
|
|
result = !isSupport;
|
|
if (!result)
|
|
{
|
|
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)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int symbolIDX = -1;
|
|
bool hasSymbol = HasSymbol(
|
|
signal.symbol,
|
|
symbolIDX //
|
|
);
|
|
if (hasSymbol)
|
|
{
|
|
//
|
|
result =
|
|
isLong
|
|
? mSymbolData[symbolIDX].CanLong()
|
|
: mSymbolData[symbolIDX].CanShort();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Execute Specific Signal using Trade Handler ...
|
|
*/
|
|
bool ExecuteSignal(
|
|
XSignal &signal, // Signal for Execution
|
|
ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Execution State
|
|
X121StrategyConditions &conditions, // Signal Conditions
|
|
bool ignorePolicies = false // Ignore Execution Policies
|
|
)
|
|
{
|
|
//
|
|
state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS;
|
|
bool result = false;
|
|
|
|
//
|
|
// Check Signal Validation ...
|
|
result = signal.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Policies ...
|
|
if (!ignorePolicies)
|
|
{
|
|
//
|
|
// Filter Signals if Necessary ...
|
|
result = CanExecute(signal);
|
|
if (!result)
|
|
{
|
|
//
|
|
state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS;
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isLong = IsLong(signal.type);
|
|
|
|
//
|
|
// Check Allow Trade Type ...
|
|
result =
|
|
isLong
|
|
? mAllowLong
|
|
: mAllowShort;
|
|
if (!result)
|
|
{
|
|
//
|
|
state = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED;
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Trades Count ...
|
|
if (mMaxAllowedLongs > 0 || mMaxAllowedShorts > 0)
|
|
{
|
|
//
|
|
XPosition longs[];
|
|
XPosition shorts[];
|
|
|
|
//
|
|
// Counting Positions ...
|
|
if (mUseMaxAllowedTradesPerSymbol)
|
|
{
|
|
//
|
|
mTrader.GetPositions(
|
|
longs,
|
|
shorts,
|
|
signal.symbol //
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
mTrader.GetPositions(
|
|
longs,
|
|
shorts,
|
|
NULL // All Symbols ...
|
|
);
|
|
}
|
|
|
|
//
|
|
int longsCount = ArraySize(longs);
|
|
int shortsCount = ArraySize(shorts);
|
|
|
|
//
|
|
result =
|
|
//
|
|
// Long ...
|
|
isLong
|
|
? mMaxAllowedLongs <= 0
|
|
? true
|
|
: longsCount < mMaxAllowedLongs
|
|
//
|
|
// Short ...
|
|
: mMaxAllowedShorts <= 0
|
|
? true
|
|
: shortsCount < mMaxAllowedShorts
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
//
|
|
state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED;
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Position Delays ...
|
|
if (result && mDelayBarBetweenTwoSignal > 0)
|
|
{
|
|
//
|
|
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 //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Only Check when there is must to check and conditions happens ...
|
|
if (youngestAge > 0 && youngestPosition.IsValid())
|
|
{
|
|
//
|
|
result = youngestAge >= mDelayBarBetweenTwoSignal;
|
|
if (!result)
|
|
{
|
|
//
|
|
state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED;
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check Drawdown ...
|
|
if (mMaxDrawdownPercentForOpenTrades > 0)
|
|
{
|
|
//
|
|
drawdownPercent = GetMaxDrawdown();
|
|
|
|
//
|
|
result =
|
|
drawdownPercent <= 0
|
|
? true
|
|
: drawdownPercent < mMaxDrawdownPercentForOpenTrades;
|
|
if (!result)
|
|
{
|
|
//
|
|
state = X_SIGNAL_EXECUTION_FAILED_NO_EQUITY;
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add Additional Volume to Signal ...
|
|
signal.volume += mAdditionalVolume;
|
|
|
|
//
|
|
bool isFiltered =
|
|
//
|
|
conditions.IsValid() &&
|
|
x121Parser.IsFiltered(
|
|
signal,
|
|
conditions //
|
|
);
|
|
if (isFiltered)
|
|
{
|
|
//
|
|
RemoveSignal(signal);
|
|
result = false;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Attach Conditions Summary to Signal ...
|
|
string conditionsSummary = conditions.GenerateSummary(
|
|
false,
|
|
false,
|
|
true,
|
|
false //
|
|
);
|
|
|
|
//
|
|
signal.conditions = x121Parser.GenerateSignalConditions(
|
|
signal,
|
|
conditions //
|
|
);
|
|
|
|
//
|
|
// Check Signal Delay ...
|
|
datetime currentTime = TimeCurrent();
|
|
int delay = DelayBarBetweenTwoSignal();
|
|
bool isDelayPassed = delay <= 0
|
|
? true
|
|
: !IsValid(lastSignalOn)
|
|
? true
|
|
: MathAbs(TimeToSeconds(currentTime)) - MathAbs(TimeToSeconds(lastSignalOn)) >= ulong(delay * PeriodSeconds(_Period));
|
|
if (!isDelayPassed)
|
|
{
|
|
//
|
|
result = false;
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Execute Signal ...
|
|
result = mTrader.ExecuteSignal(
|
|
signal,
|
|
state //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
double commission = mTrader.GetPositionCommission(signal.positionId);
|
|
|
|
//
|
|
// Add Signal to Trade Handler ...
|
|
AddData(
|
|
signal,
|
|
commission //
|
|
);
|
|
|
|
//
|
|
lastSignalOn = currentTime;
|
|
|
|
//
|
|
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);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Positions Management ...
|
|
|
|
//
|
|
// Reset Position Management ...
|
|
void ResetSymbolData()
|
|
{
|
|
//
|
|
Clean(mSymbolData);
|
|
}
|
|
|
|
//
|
|
// Handle SL ...
|
|
void HandleSL(ulong positionId)
|
|
{
|
|
//
|
|
int idx = -1;
|
|
bool hasItem = HasItem(
|
|
positionId,
|
|
idx //
|
|
);
|
|
if (!hasItem)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
string symbol = mData[idx].symbol;
|
|
bool isLong = IsLong(mData[idx].type);
|
|
|
|
//
|
|
int symbolIDX = -1;
|
|
bool hasSymbol = HasSymbol(
|
|
symbol,
|
|
symbolIDX //
|
|
);
|
|
if (!hasSymbol)
|
|
{
|
|
//
|
|
// Add New One ...
|
|
|
|
//
|
|
XSymbolData sData;
|
|
sData.symbol = symbol;
|
|
|
|
//
|
|
if (isLong)
|
|
{
|
|
sData.longSL = 1;
|
|
}
|
|
else
|
|
{
|
|
sData.shortSL = 1;
|
|
}
|
|
|
|
//
|
|
AddRef(
|
|
sData,
|
|
mSymbolData //
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Update Eists ...
|
|
|
|
//
|
|
datetime cTime = TimeCurrent();
|
|
int maxAllowedSL = NumberOfSLForPauseSignalling();
|
|
int pauseMinute = SignallingPauseDelayInMinute();
|
|
|
|
//
|
|
if (isLong)
|
|
{
|
|
//
|
|
mSymbolData[symbolIDX].longSL++;
|
|
|
|
//
|
|
if (pauseMinute > 0 &&
|
|
maxAllowedSL > 0 &&
|
|
!IsValid(mSymbolData[symbolIDX].disableLong) &&
|
|
mSymbolData[symbolIDX].longSL == maxAllowedSL)
|
|
{
|
|
//
|
|
mSymbolData[symbolIDX].longSL = 0;
|
|
mSymbolData[symbolIDX].disableLong = (datetime)((long)cTime + (pauseMinute * 60));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
mSymbolData[symbolIDX].shortSL++;
|
|
|
|
//
|
|
if (pauseMinute > 0 &&
|
|
maxAllowedSL > 0 &&
|
|
!IsValid(mSymbolData[symbolIDX].disableShort) &&
|
|
mSymbolData[symbolIDX].shortSL == maxAllowedSL)
|
|
{
|
|
//
|
|
mSymbolData[symbolIDX].shortSL = 0;
|
|
mSymbolData[symbolIDX].disableShort = (datetime)((long)cTime + (pauseMinute * 60));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle TP ...
|
|
void HandleTP(ulong positionId)
|
|
{
|
|
//
|
|
int idx = -1;
|
|
bool hasItem = HasItem(
|
|
positionId,
|
|
idx //
|
|
);
|
|
if (!hasItem)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
string symbol = mData[idx].symbol;
|
|
bool isLong = IsLong(mData[idx].type);
|
|
|
|
//
|
|
int symbolIDX = -1;
|
|
bool hasSymbol = HasSymbol(
|
|
symbol,
|
|
symbolIDX //
|
|
);
|
|
if (hasSymbol)
|
|
{
|
|
//
|
|
// Update Eists ...
|
|
|
|
//
|
|
if (isLong)
|
|
{
|
|
//
|
|
if (mSymbolData[symbolIDX].longSL > 0)
|
|
{
|
|
mSymbolData[symbolIDX].longSL--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
if (mSymbolData[symbolIDX].shortSL > 0)
|
|
{
|
|
mSymbolData[symbolIDX].shortSL--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Protection Functions ...
|
|
|
|
/**
|
|
* Handle Positiona Protections
|
|
*/
|
|
void HandleProtection()
|
|
{
|
|
//
|
|
// Retrieve Positions ...
|
|
XProtectedPosition pPositions[];
|
|
int pPositionsCount = GetPositions(
|
|
pPositions //
|
|
);
|
|
|
|
//
|
|
// Validate Count ...
|
|
if (!IsValidSize(pPositionsCount))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
bool isHedged = HandleHedge(pPositions);
|
|
if (isHedged)
|
|
{
|
|
//
|
|
// Renew Data ...
|
|
Clean(pPositions);
|
|
int pPositionsCount = GetPositions(
|
|
pPositions //
|
|
);
|
|
|
|
//
|
|
// Validate Count ...
|
|
if (!IsValidSize(pPositionsCount))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
int protectedPositions = 0;
|
|
for (int i = 0; i < pPositionsCount; i++)
|
|
{
|
|
//
|
|
// Check Position is Protectable or not ...
|
|
XProtectedPosition iProtected = pPositions[i];
|
|
XPosition iPosition = iProtected.main;
|
|
|
|
//
|
|
bool isProtected = HandlePositionProtecting(
|
|
iPosition,
|
|
iProtected.supports,
|
|
pPositions //
|
|
);
|
|
if (isProtected)
|
|
{
|
|
protectedPositions++;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (protectedPositions > 0)
|
|
{
|
|
//
|
|
// Renew Data ...
|
|
Clean(pPositions);
|
|
int pPositionsCount = GetPositions(
|
|
pPositions //
|
|
);
|
|
|
|
//
|
|
// Validate Count ...
|
|
if (!IsValidSize(pPositionsCount))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Protected ...
|
|
protected:
|
|
//
|
|
XSCTrade *mTrader; // Instance of Trader Class
|
|
X121TradeCollector *mCollector; // Instance of Trade Collector Class
|
|
|
|
//
|
|
X121TradeData mData[]; // Hold Trade Data
|
|
XSymbolData mSymbolData[]; // Hold Symbols SL TP Data
|
|
|
|
//
|
|
// Hedge Related Functions ...
|
|
|
|
/**
|
|
* Handle Hedging On Positions ...
|
|
*/
|
|
bool HandleHedge(XProtectedPosition &positions[])
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Check Hedging is Enabled Or Not ...
|
|
result = AllowHedge();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Minimum Volume Step is Provided or not ...
|
|
double minVolumeStep = HedgeMinVolumeStep();
|
|
result = minVolumeStep > 0;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Positions ...
|
|
int positionsCount = ArraySize(positions);
|
|
result = IsValidSize(positionsCount);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Required Info ...
|
|
double swaps = 0; // Summary of Positions Swaps ...
|
|
double profits = 0; // Summary of Positions and Supports Profits ...
|
|
double volumes = 0; // Summary of Positions and Supports Volumes ...
|
|
int supportsCount = 0; // Number of Protecting Positions ...
|
|
double commissions = 0; // Summary of Positions and Supports Commissions ...
|
|
XPosition flatPositions[]; // Flat Positions ...
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XProtectedPosition iProtected = positions[i];
|
|
|
|
//
|
|
XPosition iPositions[];
|
|
int iPositionsCount = iProtected.ExtractPositions(iPositions);
|
|
if (IsValidSize(iPositionsCount))
|
|
{
|
|
//
|
|
Copy(
|
|
iPositions,
|
|
flatPositions,
|
|
false //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Collect Main Positions Data ...
|
|
swaps += iProtected.main.swap;
|
|
profits += iProtected.main.profit;
|
|
volumes += iProtected.main.volume;
|
|
commissions += mTrader.GetPositionCommission(iProtected.main.ticket);
|
|
|
|
//
|
|
int iSupportsCount = iProtected.CountSupports();
|
|
supportsCount += iSupportsCount;
|
|
|
|
//
|
|
if (IsValidSize(iSupportsCount))
|
|
{
|
|
//
|
|
// Collectiong Supports Positions Data ...
|
|
for (int j = 0; j < iSupportsCount; j++)
|
|
{
|
|
//
|
|
XPosition jSupport = iProtected.supports[j];
|
|
|
|
//
|
|
swaps += jSupport.swap;
|
|
profits += jSupport.profit;
|
|
volumes += jSupport.volume;
|
|
|
|
//
|
|
commissions += mTrader.GetPositionCommission(jSupport.ticket);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// First Step is Handle HE Hedge ...
|
|
|
|
//
|
|
int minOpenPositions = MinimumOpenPositionsForHEHedge();
|
|
double heMinProfitPerVolumeStep = HedgeHEMinProfitPerVolumeStep();
|
|
double beMinProfitPerVolumeStep = HedgeBEMinProfitPerVolumeStep();
|
|
|
|
//
|
|
// Check HE Hedge Conditions ...
|
|
bool allowHEHedge = minOpenPositions > 0 && heMinProfitPerVolumeStep > 0;
|
|
if (allowHEHedge)
|
|
{
|
|
//
|
|
// Implement HE Hedge ...
|
|
|
|
//
|
|
// Check Main Positions Count and also not Support Positions ...
|
|
result = supportsCount == 0 &&
|
|
positionsCount >= minOpenPositions;
|
|
if (result)
|
|
{
|
|
//
|
|
// Check Profits ...
|
|
result = profits > 0;
|
|
if (result)
|
|
{
|
|
//
|
|
// Calculate Required Profit ...
|
|
double volumeSteps = volumes / minVolumeStep;
|
|
double minRequiredProfit = (volumeSteps * heMinProfitPerVolumeStep) +
|
|
commissions + (-1 * swaps);
|
|
|
|
//
|
|
// Check Profits Satisfied Required Profit's For Hedge or not ...
|
|
result = profits >= minRequiredProfit;
|
|
if (result)
|
|
{
|
|
//
|
|
int flatPositionsCount = ArraySize(flatPositions);
|
|
result = IsValidSize(flatPositionsCount);
|
|
if (result)
|
|
{
|
|
//
|
|
string comment = "EQM HE Hedge ...";
|
|
int closed = mTrader.Close(
|
|
flatPositions,
|
|
comment //
|
|
);
|
|
|
|
//
|
|
result = closed > 0;
|
|
if (result)
|
|
{
|
|
//
|
|
string message = "EQM HE Hedge Close (" + ToString(flatPositionsCount) + ") Positions by: " + ToString(profits);
|
|
Alert(message);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check BE Hedge Conditions ...
|
|
bool allowBEHedge = positionsCount >= 1 &&
|
|
supportsCount >= 1 &&
|
|
beMinProfitPerVolumeStep > 0;
|
|
if (allowBEHedge)
|
|
{
|
|
//
|
|
// Implement BE Hedge ...
|
|
|
|
//
|
|
// Check Profits ...
|
|
result = profits > 0;
|
|
if (result)
|
|
{
|
|
//
|
|
// Calculate Required Profit ...
|
|
double volumeSteps = volumes / minVolumeStep;
|
|
double minRequiredProfit = (volumeSteps * beMinProfitPerVolumeStep) +
|
|
commissions + (-1 * swaps);
|
|
|
|
//
|
|
// Check Profits Satisfied Required Profit's For Hedge or not ...
|
|
result = profits >= minRequiredProfit;
|
|
if (result)
|
|
{
|
|
//
|
|
int flatPositionsCount = ArraySize(flatPositions);
|
|
result = IsValidSize(flatPositionsCount);
|
|
if (result)
|
|
{
|
|
//
|
|
string comment = "EQM BE Hedge ...";
|
|
int closed = mTrader.Close(
|
|
flatPositions,
|
|
comment //
|
|
);
|
|
|
|
//
|
|
result = closed > 0;
|
|
if (result)
|
|
{
|
|
//
|
|
string message = "EQM BE Hedge Close (" + ToString(flatPositionsCount) + ") Positions by: " + ToString(profits);
|
|
Alert(message);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Handle Protecting Position ...
|
|
*/
|
|
bool HandlePositionProtecting(
|
|
XPosition &position, // Main Position
|
|
XPosition &supports[], // Supports
|
|
XProtectedPosition &positions[] // All Positions
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Find Position's Item Data ...
|
|
int iDX = -1;
|
|
result = HasItem(
|
|
position.ticket,
|
|
iDX //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int supportsCount = ArraySize(supports);
|
|
|
|
//
|
|
// Handle Protection Of Protection Signals ...
|
|
if (supportsCount > 0)
|
|
{
|
|
HandleProtectionOfProtectors(supports);
|
|
}
|
|
|
|
//
|
|
// Here we Make Sure this Position has reached Proper distance ...
|
|
|
|
//
|
|
bool isLong = IsLong(position.type);
|
|
bool isInProfit = position.profit > 0;
|
|
datetime currentTime = TimeCurrent();
|
|
|
|
//
|
|
double profitInPoint = position.GetProfitInPoint();
|
|
double pointValue = position.GetPointsValue();
|
|
|
|
//
|
|
// Determines there is a Freezed Position or not ...
|
|
bool hasFreezed = false;
|
|
int positionsCount = ArraySize(positions);
|
|
if (IsValidSize(positionsCount))
|
|
{
|
|
//
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
int iSupportsCount = ArraySize(positions[i].supports);
|
|
|
|
//
|
|
hasFreezed = iSupportsCount == 1 &&
|
|
positions[i].main.tp == 0 &&
|
|
positions[i].main.sl == 0 &&
|
|
positions[i].supports[0].tp == 0 &&
|
|
positions[i].supports[0].sl == 0 &&
|
|
positions[i].main.volume == positions[i].supports[0].volume;
|
|
if (hasFreezed)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Reading Requirements for Trailling Stops ...
|
|
bool allowTrail = AllowTrail();
|
|
double trailStep = TrailStep();
|
|
double trailStartDistance = TrailStartDistance();
|
|
bool allowOnlyUnprotecteds = OnlyTrailUnprotected();
|
|
int removeTPAfterTrailedLevel = RemoveTPAfterTrailedLevel();
|
|
bool disableTrailWhenFreezedPosition = false; // DisableTrailWhenFreezedPosition();
|
|
bool canTrail = isInProfit &&
|
|
allowTrail &&
|
|
trailStep > 0 &&
|
|
profitInPoint > 0 &&
|
|
trailStartDistance > 0 &&
|
|
(!allowOnlyUnprotecteds
|
|
? true
|
|
: supportsCount <= 0) &&
|
|
profitInPoint >= trailStartDistance &&
|
|
(!disableTrailWhenFreezedPosition
|
|
? true
|
|
: !hasFreezed);
|
|
|
|
//
|
|
// Reading Requirements for Partial Close ...
|
|
// In Profit ...
|
|
double partialCloseInProfitDistance = PartialCloseInProfitDistance();
|
|
double partialCloseInProfitVolume = PartialCloseInProfitVolume();
|
|
bool canPartialCloseInProfit = isInProfit &&
|
|
profitInPoint > 0 &&
|
|
!mData[iDX].partiallyClosed &&
|
|
partialCloseInProfitVolume > 0 &&
|
|
profitInPoint >= partialCloseInProfitDistance;
|
|
|
|
//
|
|
// In Drawdown ...
|
|
double partialCloseInDrawdownDistance = PartialCloseInProfitDistance();
|
|
double partialCloseInDrawdownVolume = PartialCloseInProfitVolume();
|
|
bool canPartialCloseInDrawdown = !isInProfit &&
|
|
profitInPoint < 0 &&
|
|
!mData[iDX].partiallyClosed &&
|
|
partialCloseInDrawdownVolume > 0 &&
|
|
MathAbs(profitInPoint) >= partialCloseInDrawdownDistance;
|
|
|
|
//
|
|
double partialCloseVolume = canPartialCloseInProfit
|
|
? partialCloseInProfitVolume
|
|
: canPartialCloseInDrawdown
|
|
? partialCloseInDrawdownVolume
|
|
: 0;
|
|
|
|
//
|
|
bool canPartialClose = partialCloseVolume > 0 &&
|
|
(canPartialCloseInProfit ||
|
|
canPartialCloseInDrawdown);
|
|
|
|
//
|
|
// Reading Requirement for Freezing Positions ...
|
|
|
|
//
|
|
// Protect ...
|
|
bool allowProtect = AllowProtect();
|
|
int protectionDelay = ProtectionDelay();
|
|
bool protectOnConditions = ProtectOnConditions();
|
|
int maxAllowedProtection = MaxAllowedProtection();
|
|
bool useEntryAsProtectionSL = UseEntryAsProtectionSL();
|
|
double protectDistance = ProtectionStartDistance();
|
|
bool allowDirectionProtect = AllowDirectionProtct();
|
|
double protectVolumeMultiplier = ProtectionVolumeMultiplier();
|
|
bool canProtect =
|
|
!isInProfit &&
|
|
allowProtect &&
|
|
protectDistance > 0 &&
|
|
protectionDelay >= 0 &&
|
|
protectVolumeMultiplier >= 1 &&
|
|
(maxAllowedProtection <= 0
|
|
? true
|
|
: supportsCount < maxAllowedProtection) &&
|
|
MathAbs(profitInPoint) >= MathAbs(protectDistance);
|
|
|
|
//
|
|
result =
|
|
canTrail ||
|
|
canProtect ||
|
|
canPartialClose;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int zIndex = 0;
|
|
int cIndex = zIndex + 1;
|
|
int pIndex = cIndex + 1;
|
|
int ppIndex = pIndex + 1;
|
|
|
|
//
|
|
// Last Bar ...
|
|
XOHCL cBar;
|
|
result = cBar.Init(
|
|
position.symbol,
|
|
position.period,
|
|
cIndex //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Previous Bar of Last Bar ...
|
|
XOHCL pBar;
|
|
result = cBar.GetPreviousBar(pBar);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Last Swing Low Bar ...
|
|
XOHCL lastSwingLow;
|
|
result = cBar.FindLastSwingLow(lastSwingLow);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Last Swing High Bar ...
|
|
XOHCL lastSwingHigh;
|
|
result = cBar.FindLastSwingHigh(lastSwingHigh);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Common Conditions For Bullish and Bearish Powers ...
|
|
|
|
//
|
|
// For Trend ...
|
|
XOHCL tmpHSW[];
|
|
XOHCL tmpLSW[];
|
|
|
|
//
|
|
// Detect Bullish/Bearish Patterns and Trends ...
|
|
|
|
//
|
|
// Bullish ...
|
|
bool hasBullishPower = cBar.HasBullishPower();
|
|
bool hasBullishPattern = HasBullishPattern(cBar);
|
|
bool hasBullishPressure = cBar.HasBullishPressure();
|
|
bool isBullishTrend = cBar.HasBullishTrend(
|
|
tmpHSW,
|
|
tmpLSW,
|
|
true //
|
|
);
|
|
bool isBullishTrend1 = cBar.HasBullishTrend(
|
|
tmpHSW,
|
|
tmpLSW,
|
|
false //
|
|
);
|
|
bool hasBullishTrend =
|
|
//
|
|
isBullishTrend
|
|
//
|
|
||
|
|
//
|
|
isBullishTrend1
|
|
//
|
|
;
|
|
|
|
//
|
|
// Bearish ...
|
|
bool hasBearishPower = cBar.HasBearishPower();
|
|
bool hasBearishPattern = HasBearishPattern(cBar);
|
|
bool hasBearishPressure = cBar.HasBearishPressure();
|
|
bool isBearishTrend = cBar.HasBearishTrend(
|
|
tmpHSW,
|
|
tmpLSW,
|
|
true //
|
|
);
|
|
bool isBearishTrend1 = cBar.HasBearishTrend(
|
|
tmpHSW,
|
|
tmpLSW,
|
|
false //
|
|
);
|
|
bool hasBearishTrend =
|
|
//
|
|
isBearishTrend
|
|
//
|
|
||
|
|
//
|
|
isBearishTrend1
|
|
//
|
|
;
|
|
|
|
//
|
|
// Define Conditions ...
|
|
MqlTick ticks[];
|
|
int ticksCount = CopyTicks(
|
|
position.symbol,
|
|
ticks,
|
|
COPY_TICKS_ALL,
|
|
0,
|
|
5 //
|
|
);
|
|
|
|
//
|
|
bool isTicksBullishForLong = false;
|
|
bool isTicksBearishForLong = false;
|
|
bool isTicksBullishForShort = false;
|
|
bool isTicksBearishForShort = false;
|
|
|
|
//
|
|
if (ticksCount == 5)
|
|
{
|
|
//
|
|
isTicksBullishForLong =
|
|
//
|
|
GetTickEntry(ticks[0], POSITION_TYPE_BUY, position.symbol) > GetTickEntry(ticks[1], POSITION_TYPE_BUY, position.symbol) &&
|
|
GetTickEntry(ticks[1], POSITION_TYPE_BUY, position.symbol) > GetTickEntry(ticks[2], POSITION_TYPE_BUY, position.symbol) &&
|
|
GetTickEntry(ticks[2], POSITION_TYPE_BUY, position.symbol) > GetTickEntry(ticks[3], POSITION_TYPE_BUY, position.symbol)
|
|
//
|
|
;
|
|
|
|
//
|
|
isTicksBearishForLong =
|
|
//
|
|
GetTickEntry(ticks[0], POSITION_TYPE_BUY, position.symbol) < GetTickEntry(ticks[1], POSITION_TYPE_BUY, position.symbol) &&
|
|
GetTickEntry(ticks[1], POSITION_TYPE_BUY, position.symbol) < GetTickEntry(ticks[2], POSITION_TYPE_BUY, position.symbol) &&
|
|
GetTickEntry(ticks[2], POSITION_TYPE_BUY, position.symbol) < GetTickEntry(ticks[3], POSITION_TYPE_BUY, position.symbol)
|
|
//
|
|
;
|
|
|
|
//
|
|
isTicksBullishForShort =
|
|
//
|
|
GetTickEntry(ticks[0], POSITION_TYPE_SELL, position.symbol) > GetTickEntry(ticks[1], POSITION_TYPE_SELL, position.symbol) &&
|
|
GetTickEntry(ticks[1], POSITION_TYPE_SELL, position.symbol) > GetTickEntry(ticks[2], POSITION_TYPE_SELL, position.symbol) &&
|
|
GetTickEntry(ticks[2], POSITION_TYPE_SELL, position.symbol) > GetTickEntry(ticks[3], POSITION_TYPE_SELL, position.symbol)
|
|
//
|
|
;
|
|
|
|
//
|
|
isTicksBearishForShort =
|
|
//
|
|
GetTickEntry(ticks[0], POSITION_TYPE_SELL, position.symbol) < GetTickEntry(ticks[1], POSITION_TYPE_SELL, position.symbol) &&
|
|
GetTickEntry(ticks[1], POSITION_TYPE_SELL, position.symbol) < GetTickEntry(ticks[2], POSITION_TYPE_SELL, position.symbol) &&
|
|
GetTickEntry(ticks[2], POSITION_TYPE_SELL, position.symbol) < GetTickEntry(ticks[3], POSITION_TYPE_SELL, position.symbol)
|
|
//
|
|
;
|
|
}
|
|
|
|
//
|
|
// News Momentum Change ...
|
|
|
|
//
|
|
double hh5 = cBar.FindHighest(
|
|
5,
|
|
MODE_HIGH //
|
|
);
|
|
|
|
//
|
|
double ll5 = cBar.FindLowest(
|
|
5,
|
|
MODE_LOW //
|
|
);
|
|
|
|
//
|
|
bool isForecBullishMomentum = false;
|
|
bool isForceBearishMomentum = false;
|
|
bool useForceMomentum = UseForceMomentumsInProtection();
|
|
if (ticksCount == 5 && useForceMomentum)
|
|
{
|
|
//
|
|
isForecBullishMomentum =
|
|
//
|
|
GetTickEntry(ticks[0], POSITION_TYPE_BUY, position.symbol) >= hh5
|
|
//
|
|
&&
|
|
//
|
|
(
|
|
//
|
|
GetTickEntry(ticks[0], POSITION_TYPE_BUY, position.symbol) > GetTickEntry(ticks[1], POSITION_TYPE_BUY, position.symbol) &&
|
|
GetTickEntry(ticks[1], POSITION_TYPE_BUY, position.symbol) > GetTickEntry(ticks[2], POSITION_TYPE_BUY, position.symbol) &&
|
|
GetTickEntry(ticks[2], POSITION_TYPE_BUY, position.symbol) > GetTickEntry(ticks[3], POSITION_TYPE_BUY, position.symbol) &&
|
|
GetTickEntry(ticks[3], POSITION_TYPE_BUY, position.symbol) > GetTickEntry(ticks[4], POSITION_TYPE_BUY, position.symbol)
|
|
//
|
|
)
|
|
//
|
|
;
|
|
|
|
//
|
|
isForceBearishMomentum =
|
|
//
|
|
GetTickEntry(ticks[0], POSITION_TYPE_SELL, position.symbol) <= ll5
|
|
//
|
|
&&
|
|
//
|
|
(
|
|
//
|
|
GetTickEntry(ticks[0], POSITION_TYPE_SELL, position.symbol) < GetTickEntry(ticks[1], POSITION_TYPE_SELL, position.symbol) &&
|
|
GetTickEntry(ticks[1], POSITION_TYPE_SELL, position.symbol) < GetTickEntry(ticks[2], POSITION_TYPE_SELL, position.symbol) &&
|
|
GetTickEntry(ticks[2], POSITION_TYPE_SELL, position.symbol) < GetTickEntry(ticks[3], POSITION_TYPE_SELL, position.symbol) &&
|
|
GetTickEntry(ticks[3], POSITION_TYPE_SELL, position.symbol) < GetTickEntry(ticks[4], POSITION_TYPE_SELL, position.symbol)
|
|
//
|
|
)
|
|
//
|
|
;
|
|
}
|
|
|
|
//
|
|
bool hasBullishDecision =
|
|
//
|
|
cBar.IsBullishDecision()
|
|
//
|
|
;
|
|
|
|
//
|
|
bool hasBearishDecision =
|
|
//
|
|
cBar.IsBearishDecision()
|
|
//
|
|
;
|
|
|
|
//
|
|
bool hasBullishConditions =
|
|
//
|
|
(
|
|
//
|
|
hasBullishTrend &&
|
|
hasBullishDecision &&
|
|
(hasBullishPower ||
|
|
hasBullishPattern ||
|
|
hasBullishPressure)
|
|
//
|
|
)
|
|
//
|
|
;
|
|
|
|
//
|
|
bool hasBearishConditions =
|
|
//
|
|
(
|
|
//
|
|
hasBearishTrend &&
|
|
hasBearishDecision &&
|
|
(hasBearishPower ||
|
|
hasBearishPattern ||
|
|
hasBearishPressure)
|
|
//
|
|
)
|
|
//
|
|
;
|
|
|
|
//
|
|
// Do Trail ...
|
|
bool isTrailed = false;
|
|
if (canTrail)
|
|
{
|
|
//
|
|
bool hasTrailConditions =
|
|
isLong
|
|
? (isForecBullishMomentum ||
|
|
(isTicksBullishForLong &&
|
|
hasBullishConditions))
|
|
: (isForceBearishMomentum ||
|
|
(isTicksBearishForShort &&
|
|
hasBearishConditions));
|
|
if (hasTrailConditions)
|
|
{
|
|
//
|
|
double entry = position.entry;
|
|
int lastTrailedStep = mData[iDX].trailStep;
|
|
|
|
//
|
|
double requiredProfit =
|
|
lastTrailedStep == 0
|
|
? trailStartDistance
|
|
: trailStartDistance + (lastTrailedStep * trailStep);
|
|
|
|
//
|
|
bool isProfitsPassed = profitInPoint > requiredProfit;
|
|
if (isProfitsPassed)
|
|
{
|
|
//
|
|
double delta = (requiredProfit * pointValue);
|
|
|
|
//
|
|
double sl =
|
|
isLong
|
|
? entry + delta
|
|
: entry - delta;
|
|
|
|
//
|
|
string comment = "EQM Trail Stop ...";
|
|
|
|
//
|
|
bool canRemoveTP =
|
|
position.tp != 0 &&
|
|
removeTPAfterTrailedLevel > 0 &&
|
|
mData[iDX].trailStep == removeTPAfterTrailedLevel;
|
|
double tp =
|
|
canRemoveTP
|
|
? 0
|
|
: position.tp;
|
|
|
|
//
|
|
// Try to Modify Position ...
|
|
isTrailed = mTrader.Modify(
|
|
position.ticket,
|
|
sl,
|
|
tp,
|
|
comment //
|
|
);
|
|
if (isTrailed)
|
|
{
|
|
//
|
|
mData[iDX].trailStep++;
|
|
|
|
//
|
|
string message = "EQM Trail (" + ToString(position.ticket) + ") Stop in Level: " + ToString(mData[iDX].trailStep) + " ...";
|
|
Alert(message);
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Force Trail When passed half way ...
|
|
else
|
|
{
|
|
//
|
|
// Handle Force Trail ...
|
|
double requiredProfit = position.GetRewardInPoint() / 2;
|
|
if (position.sl > 0 &&
|
|
position.sl < position.entry &&
|
|
profitInPoint >= requiredProfit)
|
|
{
|
|
//
|
|
double delta = requiredProfit - (requiredProfit / 3);
|
|
double sl =
|
|
isLong
|
|
? position.entry + (delta * pointValue)
|
|
: position.entry - (delta * pointValue);
|
|
|
|
//
|
|
string comment = "EQM Force Trail Stop ...";
|
|
|
|
//
|
|
// Try to Modify Position ...
|
|
isTrailed = mTrader.Modify(
|
|
position.ticket,
|
|
sl,
|
|
position.tp,
|
|
comment //
|
|
);
|
|
if (isTrailed)
|
|
{
|
|
//
|
|
mData[iDX].trailStep++;
|
|
|
|
//
|
|
string message = "EQM Force Trail (" + ToString(position.ticket) + ") Stop ...";
|
|
Alert(message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Do Partial Close ...
|
|
bool isPartialClosed = false;
|
|
if (canPartialClose)
|
|
{
|
|
//
|
|
string comment = "EQM Partial Close ...";
|
|
|
|
//
|
|
// Do Partial Closing ...
|
|
isPartialClosed = mTrader.ClosePartial(
|
|
position.ticket,
|
|
partialCloseVolume,
|
|
comment //
|
|
);
|
|
if (isPartialClosed)
|
|
{
|
|
//
|
|
mData[iDX].partiallyClosed = true;
|
|
|
|
//
|
|
string message = "EQM Partially Closed " + ToString(partialCloseVolume) + " of (" + ToString(position.ticket) + ") ...";
|
|
Alert(message);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Protect ...
|
|
bool isProtected = false;
|
|
if (canProtect)
|
|
{
|
|
//
|
|
// Protection Conditions ...
|
|
bool hasLongProtectConditions = isForecBullishMomentum ||
|
|
(isTicksBullishForLong &&
|
|
hasBullishConditions);
|
|
bool hasShortProtectConditions = isForceBearishMomentum ||
|
|
(isTicksBearishForShort &&
|
|
hasBearishConditions);
|
|
|
|
//
|
|
// Check Protection Delay ...
|
|
datetime currentTime = TimeCurrent();
|
|
datetime lastProtectedOn = mData[iDX].lastProtectedOn;
|
|
bool isProtectionDelayPassed =
|
|
protectionDelay <= 0
|
|
? true
|
|
: !IsValid(lastProtectedOn)
|
|
? true
|
|
: (TimeToSeconds(currentTime) - TimeToSeconds(lastProtectedOn)) > (ulong)protectionDelay;
|
|
|
|
//
|
|
// Checking Protection Conditions ...
|
|
bool hasProtectConditions =
|
|
isProtectionDelayPassed &&
|
|
(!protectOnConditions
|
|
? true
|
|
: allowDirectionProtect
|
|
? (hasLongProtectConditions ||
|
|
hasShortProtectConditions)
|
|
: isLong
|
|
? hasShortProtectConditions
|
|
: hasLongProtectConditions);
|
|
|
|
//
|
|
// Check Protection Conditions Happens ...
|
|
if (hasProtectConditions)
|
|
{
|
|
//
|
|
bool isInDirectProtection =
|
|
!protectOnConditions
|
|
? true
|
|
: isLong
|
|
? hasShortProtectConditions
|
|
: hasLongProtectConditions;
|
|
|
|
//
|
|
double sl =
|
|
!isInDirectProtection
|
|
? position.sl
|
|
: useEntryAsProtectionSL
|
|
? position.entry
|
|
: position.tp;
|
|
double tp =
|
|
!isInDirectProtection
|
|
? position.tp
|
|
: position.sl;
|
|
double volume = protectVolumeMultiplier * position.volume;
|
|
ENUM_POSITION_TYPE type =
|
|
!isInDirectProtection
|
|
? position.type
|
|
: GetOpposit(position.type);
|
|
double entry = GetEntry(
|
|
position.symbol,
|
|
type //
|
|
);
|
|
ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET;
|
|
|
|
//
|
|
// Prepare Signal ...
|
|
XSignal signal;
|
|
bool isPrepared = signal.Prepare(
|
|
position.symbol,
|
|
position.provider,
|
|
position.period,
|
|
type,
|
|
mode,
|
|
entry,
|
|
volume,
|
|
sl,
|
|
tp //
|
|
);
|
|
|
|
//
|
|
if (isPrepared)
|
|
{
|
|
//
|
|
// Generate Comment for Recover and Support ...
|
|
string comment = GenerateSupportTag(position.ticket);
|
|
|
|
//
|
|
signal.comment = comment;
|
|
|
|
//
|
|
X121StrategyConditions conditions;
|
|
ENUM_X_SIGNAL_EXECUTION_RESULT state;
|
|
isProtected = ExecuteSignal(
|
|
signal,
|
|
state,
|
|
conditions,
|
|
true // Support Signal need to Ignore Policies ...
|
|
);
|
|
if (isProtected)
|
|
{
|
|
//
|
|
// Update Last Protected On Data Handler ...
|
|
mData[iDX].lastProtectedOn = currentTime;
|
|
|
|
//
|
|
// Alert ...
|
|
string message = "EQM Open " + (IsLong(type) ? "Long" : "Short") + " Protect Position for (" + ToString(position.ticket) + ") ...";
|
|
Alert(message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
result =
|
|
isTrailed ||
|
|
isProtected ||
|
|
isPartialClosed;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Handle Protection of Support(s) ...
|
|
*
|
|
* @param supports: Supports Array ...
|
|
*/
|
|
void HandleProtectionOfProtectors(XPosition &supports[])
|
|
{
|
|
//
|
|
int supportsCount = ArraySize(supports);
|
|
|
|
//
|
|
if (!IsValidSize(supportsCount))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// TODO: Implement Supports Protection ...
|
|
|
|
//
|
|
// Trailling ...
|
|
}
|
|
|
|
//
|
|
// Private ...
|
|
private:
|
|
//
|
|
// Props ...
|
|
double mAdditionalVolume; // Volume Additional
|
|
|
|
//
|
|
// Read Only ...
|
|
int maxSameTimeTrades; // Max Same Time Trades
|
|
double maxDrawdown; // Max 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
|
|
bool mUseMaxAllowedTradesPerSymbol; // Use Max Allowed Trades Per Symbol
|
|
int mNumberOfSLForPauseSignalling; // Number of SL For Pause Signalling Per Symbol/Type
|
|
int mSignallingPauseDelayInMinute; // Signalling Pause Delay In Minute
|
|
double mMaxDrawdownPercentForOpenTrades; // Max Drawdown Percent for Open Trades
|
|
|
|
//
|
|
// Protector ...
|
|
|
|
//
|
|
bool mUseForceMomentumsInProtection; // Use Force Momentums In Protection;
|
|
int mDelayBarBetweenTwoSignal; // Delay Bars Between Two Signal
|
|
double mAcceptNextSameTypeSignalWhenLastInProfit; // Accept Next Same Type Signal When Last in Profit in Point
|
|
|
|
//
|
|
datetime lastSignalOn;
|
|
|
|
//
|
|
// Since Signal Filtering done based on
|
|
// Strategy and it's not related to Public
|
|
// TradeHandler for Seperation of Concern issue,
|
|
// we do this here ...
|
|
X121StartegyConditionsParser x121Parser;
|
|
|
|
//
|
|
// In Profit Positions Protecting ...
|
|
|
|
//
|
|
// Trail ...
|
|
bool mAllowTrail; // Allow Trail Stop for Positions
|
|
double mTrailStartDistance; // Specify Trail Start in Point
|
|
double mTrailStep; // Trail Step in Point
|
|
int mRemoveTPAfterTrailedLevel; // Remove Trailed Position TP after Level
|
|
bool mOnlyTrailUnprotected; // Only Trail Unprotected Positionss
|
|
|
|
//
|
|
// Partial Close (In Profit) ...
|
|
double mPartialCloseInProfitDistance; // Specify Partial Close Profit in Point
|
|
double mPartialCloseInProfitVolume; // Specify Partial Close in Profit Volume
|
|
|
|
//
|
|
// In Drawdown Positions Protecting ...
|
|
|
|
//
|
|
// Protect ...
|
|
bool mAllowProtect; // Allow Proptecting
|
|
double mProtectionStartDistance; // Protection Start Drawdown in Profit
|
|
double mProtectionVolumeMultiplier; // Protection Volume Multiplier
|
|
int mMaxAllowedProtection; // Max Allowed Protection
|
|
bool mUseEntryAsProtectionSL; // Use Position Entry For SL of Protect
|
|
bool mAllowDirectionProtct; // Allow also Directional Protect
|
|
bool mProtectOnConditions; // Do Protection only when Conditions happens
|
|
int mProtectionDelay; // Delay Between two Protection in Secconds
|
|
|
|
//
|
|
// Partial Close (In Drawdown) ...
|
|
double mPartialCloseInDrawdownDistance; // Specify Partial Close Drawdown in Point
|
|
double mPartialCloseInDrawdownVolume; // Specify Partial Close in Drawdown Volume
|
|
|
|
//
|
|
// Hedging Properties ...
|
|
bool mAllowHedge; // Allow Protector to Hedge Positions
|
|
double mHedgeMinVolumeStep; // Minimum Volume Step For Hedge
|
|
int mMinimumOpenPositionsForHEHedge; // Minimum Open Positions For HE Hedge
|
|
double mHedgeHEMinProfitPerVolumeStep; // Minimum Required Profit For HE Hedge Per Volume Step
|
|
double mHedgeBEMinProfitPerVolumeStep; // Minimum Required Profit For BE Hedge Per Volume Step
|
|
|
|
//
|
|
// Common Functions ...
|
|
|
|
//
|
|
// Count Data ...
|
|
int Count()
|
|
{
|
|
return ArraySize(mData);
|
|
}
|
|
|
|
//
|
|
// Add Item ...
|
|
bool Add(X121TradeData &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.symbol,
|
|
item.provider,
|
|
item.period,
|
|
item.type,
|
|
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;
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
//
|
|
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(X121TradeData &item)
|
|
{
|
|
//
|
|
if (!mSaveSignals)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Save Signal ...
|
|
mCollector.SaveSignal(item);
|
|
}
|
|
|
|
//
|
|
// Symbol Data Parsing ...
|
|
|
|
//
|
|
bool HasSymbol(
|
|
string symbol,
|
|
int &index //
|
|
)
|
|
{
|
|
//
|
|
index = -1;
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid(symbol);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int count = ArraySize(mSymbolData);
|
|
result = IsValidSize(count);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Loop through Symbol Data ...
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XSymbolData iData = mSymbolData[i];
|
|
|
|
//
|
|
if (iData.symbol == symbol)
|
|
{
|
|
//
|
|
index = i;
|
|
result = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
// |