Files
xMQL5/BKPS/14030823/BKPs/14030802-X121/Classes/x-saherelm.x121.xtrade.handler.class.mq5
T
2024-11-15 10:50:11 +03:30

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;
}
//
};
//