Files
xMQL5/MQLTestWorkspace/BKPS/14030308/Classes/x-saherelm.x121.xea.class.mq5
T
2024-05-28 08:03:47 +03:30

1676 lines
44 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Class Library
// ----------------------------------------------
// Name: XSCX121EA
// Description: provides all X121 EA requirements ...
// - X5 Provider;
//
//
// 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.xea.class.mq5"
#include "../Classes/x-saherelm.x121.provider.class.mq5"
//
// Define On Signal Event Handler Type Specified for X5 ...
typedef void (*TX121OnSignal)(X121ProviderDescriptor &descriptor);
//
// Class Definition ...
class XSCX121EA : public XSCBaseEA
{
//
// Public ...
public:
//
// Props ...
//
// Constructors ...
XSCX121EA(
//
// XTrade Class Requirements ...
int slippage, // Specify Slippage
ulong magicNumber, // Specify Magic Number
int manageInterval, // Manager Check Intervals Seconds
double maxAllowedSpread, // Max Allowed Spred for Opening Trades
int maxAllowedPositions, // Max Allowed Positions
double maxAllowedDrawdownFactor, // Max Allowed Drawdown Factor
double staticVolume, // Static Volume for Positions
//
// Position Management ...
bool allowLong = true, // Allow Long Trades
bool allowShort = true, // Allow Short Trades
double minProfitPerTrade = 0, // Min Profit Per Trade based On Volume Factor (Hedge)
double minProfitPerVolumeFactor = 0, // Min Volume Factor for Calculating Profit (Hedge)
//
// Event Handlers ...
TOnStopLoss onStopLossTriggered = NULL, // On StopLoass Triggered Event Handler
TOnTakeProfit onTakeProfitTriggered = NULL, // On TakeProfit Triggered Event Handler
TOnDealsChanged onDealsChangedHandler = NULL, // On Deals Changed Event Handler
TOnOrdersChanged onOrdersChangedHandler = NULL, // On Orders Changed Event Handler
TOnPositionsChanged onPositionsChangedHandler = NULL, // On Positions Changed Event Handler
TOnTradeStateChanged onTradeStateChangedHandler = NULL, // On Trade State Changed Event Handler
//
TOnSignal onSignalHandler = NULL, // On Signal Event Handler
//
// Log Handler ...
bool enableAlerts = true, // Enable Alerts
bool logAlerts = true, // Log Alerts
bool terminalAlerts = false, // Terminal Alerts
bool mailAlerts = false, // Mail Alerts
bool pushAlerts = false // Push Alerts
) : XSCBaseEA(slippage,
magicNumber,
manageInterval,
maxAllowedSpread,
maxAllowedPositions,
maxAllowedDrawdownFactor,
staticVolume,
allowLong,
allowShort,
minProfitPerTrade,
minProfitPerVolumeFactor,
onStopLossTriggered,
onTakeProfitTriggered,
onDealsChangedHandler,
onOrdersChangedHandler,
onPositionsChangedHandler,
onTradeStateChangedHandler,
enableAlerts,
logAlerts,
terminalAlerts,
mailAlerts,
pushAlerts //
)
{
}
//
// Deconstructor ...
~XSCX121EA() {}
//
// Properties Getter(s) / Setter(s) ...
//
// Add X5 Specified Signal Event Handler ...
void AddOnSignalEventHandler(TX121OnSignal listener)
{
//
Add(
listener,
mX121OnSignalEventHandlers
//
);
}
//
// Add Specified X5 Provider ...
bool AddProvider(X121ProviderDescriptor &descriptor)
{
//
bool result = false;
//
// Validate Inputs ...
result = descriptor.Init();
if (!result)
{
return result;
}
//
AddRef(
descriptor,
mDescriptors //
);
//
return result;
}
//
// Overrides ...
//
// Customize Token ...
string GetToken() override
{
return GetSpecificToken(this);
}
//
string GetTag() override
{
return this.GetToken();
}
//
void Draw() override
{
//
int descriptorsCount = CountDescriptors();
if (descriptorsCount <= 0)
{
return;
}
//
for (int i = 0; i < descriptorsCount; i++)
{
//
X121ProviderDescriptor iDescriptor = mDescriptors[i];
//
iDescriptor.provider.Draw();
}
}
//
// Check Provider for any Guards ...
bool CheckForGuard(XGuard &guards[]) override
{
//
bool result = false;
//
Clean(guards);
//
int descriptorsCount = CountDescriptors();
result = descriptorsCount > 0;
if (!result)
{
return result;
}
//
for (int i = 0; i < descriptorsCount; i++)
{
//
X121ProviderDescriptor iDescriptor = mDescriptors[i];
//
XGuard iGuards[];
bool iHasGuard = iDescriptor.provider.HasGuard(iGuards);
if (iHasGuard)
{
//
Copy(
iGuards,
guards,
false //
);
}
}
//
result = ArraySize(guards) > 0;
//
return result;
}
//
// Request Provider to Collect all
// Potentially Signals and then
// filters theme here and passed them
// for Executing ...
int RequestForSignal(
XSignal &signals[] // Holds Signals ...
) override
{
//
bool result = 0;
//
Clean(signals);
//
int descriptorsCount = CountDescriptors();
if (descriptorsCount <= 0)
{
return result;
}
//
for (int i = 0; i < descriptorsCount; i++)
{
//
X121ProviderDescriptor iDescriptor = mDescriptors[i];
//
bool iHasSignal = iDescriptor.HasSignal();
if (iHasSignal)
{
//
// Here we Can double check Signals by Conditions
// for Score Base Filtering ...
//
AddRef(
iDescriptor.signal,
signals
//
);
//
NotifyX121OnSignalEventHandlers(iDescriptor);
}
}
//
result = ArraySize(signals);
//
return result;
}
//
// Handl Management Actions ...
// if returns true, it is going to prevent for processing forward ...
bool HandleStateManagement(XSignal &signals[]) override
{
//
bool result = false;
//
XPosition positions[];
int positionsCount = mTrader.GetPositions(positions);
if (positionsCount <= 0)
{
return result;
}
//
// Synch Position Tracker ...
SyncPositionTracker();
//
HandleEQMState(signals);
//
HandleEQMHedge(positions);
//
HandleTrailManagement(positions);
//
// Close all Positions on 22 ...
// TODO: Make it Configurable ...
int closeHour = -1;
MqlDateTime cTime = GetCurrentTime();
if (closeHour >= 0 && cTime.hour == closeHour)
{
//
string comment = "EQM Close on Time ...";
//
XPosition positions[];
int positionsCount = mTrader.GetPositions(positions);
if (positionsCount <= 0)
{
return result;
}
//
int closed = mTrader.Close(
positions,
comment //
);
if (closed > 0)
{
mAlert.Alert(comment);
}
}
//
// Must false ...
return result;
}
//
void HandleEQMHedge(XPosition &positions[])
{
//
// TODO:
// Make them Configurable ...
int numberOfPositionsForHege = 3;
//
int positionsCount = ArraySize(positions);
if (positionsCount <= 0)
{
return;
}
//
// Hedge ...
if (positionsCount >= numberOfPositionsForHege)
{
//
int maxAllowedPositions = GetMaxAllowedPositions();
//
double profit = CalculatePositionsProfit(positions);
double requiredProfit = CalculateRequiredProfitForHedge(positions);
//
bool isReadyForHedge =
positionsCount < maxAllowedPositions
? profit >= requiredProfit
: positionsCount >= maxAllowedPositions && profit >= (requiredProfit * 0.50)
? true
: false;
if (!isReadyForHedge)
{
return;
}
//
string comment = "EQM Hedge ...";
int closed = mTrader.Close(
positions,
comment);
if (closed > 0)
{
//
string message = "EQM Hedge Positions on Profit: " + ToString(profit);
//
mAlert.Alert(message);
//
RemoveEQMOrders();
//
for (int i = 0; i < positionsCount; i++)
{
RemoveTrail(positions[i].ticket);
}
}
}
}
//
void HandleEQMState(XSignal &signals[])
{
//
bool equityReached = !mTrader.CheckEquityForTrade();
bool maxAllowedReached = !mTrader.CheckPositionsForTrade();
bool enableEQM = equityReached || maxAllowedReached;
// if (!enableEQM)
// {
// //
// return;
// }
//
string mSymbols[];
XSCPositionHolder *mHolders[];
int symbolsCount = FilterSymbolBasedPositions(
mSymbols,
mHolders //
);
//
for (int i = 0; i < symbolsCount; i++)
{
//
string iSymbol = mSymbols[i];
XSCPositionHolder *iHolder = mHolders[i];
//
// We Can Select Multiple Positions for Place EQM Supports ...
//
// Select Max In Drawdown Position and Protect it ...
XPosition iSelectedPosition;
bool iHasPosition = iHolder.GetMaxInDrawdown(iSelectedPosition);
if (iHasPosition)
{
//
// Try to Protect Max In Drawdown Positions Position ...
PlaceEQMOrders(iSelectedPosition);
}
}
//
}
//
// Add Or Update EQM Orders ...
void PlaceEQMOrders(XPosition &position)
{
//
// TODO: Make It Configurable ...
int maxEQMCount = 5;
return;
//
// Position Protection Senarioos ...
if (!position.IsValid())
{
return;
}
//
int descriptorIDX = FindDescriptorIndex(position);
if (descriptorIDX <= -1)
{
return;
}
//
X121ProviderDescriptor descriptor = mDescriptors[descriptorIDX];
//
XOHCLSupRes slSupRes;
bool hasSupRes = descriptor
.provider
.GenerateSupRes(
slSupRes,
position.type,
5 //
);
//
XDrawSpecifications supDrawSpecs;
supDrawSpecs.draw = true;
supDrawSpecs.rayRight = true;
supDrawSpecs.clr = clrLightGreen;
//,
XDrawSpecifications resDrawSpecs;
resDrawSpecs.draw = true;
resDrawSpecs.rayRight = true;
resDrawSpecs.clr = clrLightCoral;
//
// DrawSupRes(
// slSupRes,
// supDrawSpecs,
// resDrawSpecs //
// );
//
XSignal supports[];
int supportsCount = GenerateEQMOrders(
supports,
position,
slSupRes //
);
if (!IsValidSize(supportsCount))
{
return;
}
//
XOrder untriggeredOrders[];
int untriggeredOrdersCount = mTrader.GetOrders(
untriggeredOrders,
position.symbol,
XEQMSupportToken,
position.period,
NULL, // All Types ...
ORDER_STATE_PLACED,
true //
);
//
XPosition triggereSupports[];
int tiggeredSupportsCount = mTrader.GetPositions(
triggereSupports,
position.symbol,
XEQMSupportToken,
position.period,
NULL, // All Types ...
true //
);
//
if (untriggeredOrdersCount +
tiggeredSupportsCount >=
maxEQMCount)
{
return;
}
//
XSignal filteredSignals[];
for (int i = 0; i < supportsCount; i++)
{
//
XSignal iSupport = supports[i];
//
double sl;
iSupport.RegularSL(sl);
//
double tp;
iSupport.RegularTP(tp);
//
if (!IsValidSize(untriggeredOrdersCount) && !IsValidSize(tiggeredSupportsCount))
{
//
AddRef(
iSupport,
filteredSignals //
);
//
continue;
}
//
bool isOrdersPassed = true;
if (!IsValidSize(untriggeredOrdersCount))
{
isOrdersPassed = true;
}
else
{
//
for (int j = 0; j < untriggeredOrdersCount; j++)
{
//
XOrder jOrder = untriggeredOrders[j];
//
bool isSame =
//
jOrder.symbol == iSupport.symbol &&
jOrder.period == iSupport.period &&
jOrder.openPrice == iSupport.entry &&
jOrder.sl == sl &&
jOrder.tp == tp
//
;
if (isSame)
{
//
isOrdersPassed = false;
break;
}
}
}
//
bool isPositionsPassed = true;
if (!IsValidSize(tiggeredSupportsCount))
{
isPositionsPassed = true;
}
else
{
//
for (int j = 0; j < tiggeredSupportsCount; j++)
{
//
XPosition jPosition = triggereSupports[j];
//
bool isSame =
//
jPosition.symbol == iSupport.symbol &&
jPosition.period == iSupport.period &&
jPosition.entry == iSupport.entry &&
jPosition.sl == sl &&
jPosition.tp == tp
//
;
if (isSame)
{
//
isPositionsPassed = false;
break;
}
}
}
//
if (isOrdersPassed &&
isPositionsPassed)
{
//
AddRef(
iSupport,
filteredSignals //
);
}
}
int filteredSignalsCount = ArraySize(filteredSignals);
if (!IsValidSize(filteredSignalsCount))
{
return;
}
//
ENUM_X_SIGNAL_EXECUTION_RESULT states[];
int placedOrders = mTrader.ExecuteSignals(
filteredSignals,
states,
ORDER_TIME_GTC,
NULL,
false // Ignore Policies ...
);
if (placedOrders > 0)
{
//
string message = "EQM Placed (" + ToString(placedOrders) + ") Support Orders ...";
//
mAlert.Alert(message);
}
}
//
void RemoveEQMOrders()
{
//
XOrder untriggeredOrders[];
int untriggeredOrdersCount = mTrader.GetOrders(
untriggeredOrders,
NULL,
XEQMSupportToken,
NULL,
NULL, // All Types ...
ORDER_STATE_PLACED,
true //
);
if (!IsValidSize(untriggeredOrdersCount))
{
return;
}
//
int canceleds = mTrader.CancelOrders(
untriggeredOrders //
);
if (canceleds > 0)
{
//
string message = "EQM Cancel Support ...";
//
mAlert.Alert(message);
}
}
//
void HandleTrailManagement(XPosition &positions[])
{
//
// TODO:
// Make them Configurable ...
int maxTrailTPs = 5;
int levelsOnClose = 6;
int riskFreeLevel = 2;
int requiredAgeForTrail = 0;
int requiredDistanceForTrail = 20;
//
int positionsCount = ArraySize(positions);
if (positionsCount <= 0)
{
return;
}
//
double profit = CalculatePositionsProfit(positions);
//
// Trail Positions Stop ...
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = positions[i];
//
bool canManageState =
//
iPosition.provider != XEQMSupportToken
//
;
//
// Position Management for X786 ...
if (canManageState)
{
//
// When Position in Profit, Trail SL ...
if (profit > 0)
{
//
if (iPosition.profit > 0)
{
//
XTrail trail;
bool isTrailedBefore = GetSLTrail(
iPosition.ticket,
trail //
);
//
if (!isTrailedBefore)
{
//
// Add First Time ...
//
// Check Position Age ...
int iPositionAge = iPosition.GetAge(iPosition.period);
if (iPositionAge < requiredAgeForTrail)
{
continue;
}
//
// Check Position Profit Distance ...
double priceDistanceInPoint = PriceToPoint(iPosition.profit / iPosition.volume, iPosition.symbol);
double priceDistance = PointToPrice(priceDistanceInPoint, iPosition.symbol);
if (priceDistance < requiredDistanceForTrail)
{
continue;
}
//
double slDiff = PointToPrice(priceDistance, iPosition.symbol);
double appliedSL = slDiff;
//
double sl =
IsLong(iPosition.type)
? iPosition.sl + appliedSL
: iPosition.sl - appliedSL;
//
// double sl =
// IsLong(iPosition.type)
// ? iPosition.entry + appliedSL
// : iPosition.entry - appliedSL;
//
bool isInit = trail.Init(
iPosition.ticket,
iPosition.type,
iPosition.profit,
iPosition.sl,
sl //
);
if (!isInit)
{
continue;
}
}
else
{
//
// Update Exists ...
//
// Check Profit ...
bool isProfitPassed = iPosition.profit > trail.profit;
if (!isProfitPassed)
{
continue;
}
//
// Check Age Distance from Last ...
int age = iBarShift(
iPosition.symbol,
iPosition.period,
trail.time,
false //
);
if (age < requiredAgeForTrail)
{
continue;
}
//
double priceDistanceInPoint = PriceToPoint((iPosition.profit - trail.profit) / iPosition.volume, iPosition.symbol);
double priceDistance = PointToPrice(priceDistanceInPoint, iPosition.symbol);
if (priceDistance < requiredDistanceForTrail)
{
continue;
}
//
bool isLong = IsLong(iPosition.type);
//
double slDiff = PointToPrice(priceDistance, iPosition.symbol);
double appliedSL = (slDiff / 2);
//
double selectedValue =
//
(riskFreeLevel > 0 &&
trail.level == riskFreeLevel) ||
(isLong
? iPosition.sl < iPosition.entry
: iPosition.sl > iPosition.entry)
? iPosition.entry
: iPosition.sl
//
;
//
double sl =
isLong
? selectedValue + appliedSL
: selectedValue - appliedSL;
//
// Update Trail Values ...
bool isUpdated = trail.Update(
sl,
iPosition.profit //
);
if (!isUpdated)
{
continue;
}
}
//
if (trail.IsValid())
{
//
string comment = trail.GenerateTag();
bool isModified = mTrader.Modify(
trail.ticket,
trail.after,
iPosition.tp,
comment //
);
if (isModified)
{
//
RemoveTrail(trail.ticket);
//
AddSLTrail(trail);
//
string message = "Position (" + ToString(trail.ticket) + ") Trailed SL on Level: " + ToString(trail.level);
mAlert.Alert(message);
}
}
}
}
//
// When Position in Drawdown Trail TP ...
if (profit < 0)
{
//
if (iPosition.profit < 0)
{
//
XTrail trail;
bool isTrailedBefore = GetTPTrail(
iPosition.ticket,
trail //
);
//
if (!isTrailedBefore)
{
//
// Add First Time ...
//
// Check Position Age ...
int iPositionAge = iPosition.GetAge(iPosition.period);
if (iPositionAge < requiredAgeForTrail)
{
continue;
}
//
// Check Position Profit Distance ...
double priceDistanceInPoint = PriceToPoint(MathAbs(iPosition.profit) / iPosition.volume, iPosition.symbol);
double priceDistance = PointToPrice(priceDistanceInPoint, iPosition.symbol);
if (priceDistance < requiredDistanceForTrail)
{
continue;
}
//
double tpDiff = PointToPrice(priceDistance, iPosition.symbol);
double appliedTP = tpDiff / 2;
//
double tp =
IsLong(iPosition.type)
? iPosition.tp - appliedTP
: iPosition.tp + appliedTP;
//
bool isInit = trail.Init(
iPosition.ticket,
iPosition.type,
iPosition.profit,
iPosition.tp,
tp //
);
if (!isInit)
{
continue;
}
}
else
{
//
// Update Exists ...
//
if (trail.level >= maxTrailTPs)
{
continue;
}
//
// Check Profit ...
bool isProfitPassed = MathAbs(iPosition.profit) > MathAbs(trail.profit);
if (!isProfitPassed)
{
continue;
}
//
// Check Age Distance from Last ...
int age = iBarShift(
iPosition.symbol,
iPosition.period,
trail.time,
false //
);
if (age < requiredAgeForTrail)
{
continue;
}
//
double priceDistanceInPoint = PriceToPoint((MathAbs(iPosition.profit) - MathAbs(trail.profit)) / iPosition.volume, iPosition.symbol);
double priceDistance = PointToPrice(priceDistanceInPoint, iPosition.symbol);
//
bool isLong = IsLong(iPosition.type);
//
double tpDiff = PointToPrice(priceDistance, iPosition.symbol);
double appliedTP = tpDiff / 2;
//
double tp =
isLong
? iPosition.tp - appliedTP
: iPosition.tp + appliedTP;
//
// Update Trail Values ...
bool isUpdated = trail.Update(
tp,
iPosition.profit //
);
if (!isUpdated)
{
continue;
}
}
//
if (trail.IsValid())
{
//
string comment = trail.GenerateTag();
bool isModified = mTrader.Modify(
trail.ticket,
iPosition.sl,
trail.after,
comment //
);
if (isModified)
{
//
RemoveTrail(trail.ticket);
//
AddTPTrail(trail);
//
string message = "Position (" + ToString(trail.ticket) + ") Trailed TP on Level: " + ToString(trail.level);
mAlert.Alert(message);
}
}
}
}
}
}
}
//
// Here we Can Filter Signals before Sending them to Execution ...
// based on Providers and etc ...
// for Volumes and Benefits ...
int HandleSignalManagement(XSignal &signals[]) override
{
//
// TODO: Make this Configurable ...
int minDistanceBetweenTwoSameProviderSignal = 7;
//
int result = 0;
//
if (ArraySize(signals) <= 0)
{
return result;
}
//
// Create temp Array for Filtering ...
XSignal tmps[];
Copy(
signals,
tmps //
);
int tmpsCount = ArraySize(tmps);
//
// Cleaning Source ...
Clean(signals);
//
// Loop through Signals for Management ...
for (int i = 0; i < tmpsCount; i++)
{
//
XSignal iSignal = tmps[i];
//
// dont Manage NON Signal Provider's signals ...
string provider = iSignal.provider;
if (!IsValid(provider))
{
//
AddRef(
iSignal,
signals //
);
//
continue;
}
//
XPosition positions[];
int positionsCount = mTrader.GetPositions(
positions,
iSignal.symbol,
iSignal.provider,
NULL, // All Periods ...
iSignal.type //
);
XPosition symbolPositions[];
int symbolPositionsCount = mTrader.GetPositions(
positions,
iSignal.symbol,
NULL, // All Providers ...
NULL, // All Periods ...
iSignal.type //
);
double profit = CalculatePositionsProfit(positions);
double symbolProfit = CalculatePositionsProfit(symbolPositions);
if (positionsCount <= 0)
{
//
// First Signal in a While of Specific Provider ...
//
// iSignal.volume *= 2;
//
AddRef(
iSignal,
signals //
);
//
continue;
}
else if (positionsCount < 2)
{
//
// Next Signal in a While of Specific Provider ...
//
// Find Longest Position and Check it's Age ...
// Compare it by min age for same provider signals ...
XPosition youngest;
int youngestAge = GetYoungest(
youngest,
positions //
);
if (youngestAge == -1 || youngestAge < minDistanceBetweenTwoSameProviderSignal)
{
continue;
}
//
AddRef(
iSignal,
signals //
);
//
continue;
}
// else if (profit > 0 && symbolProfit > 0)
// {
// //
// AddRef(
// iSignal,
// signals //
// );
// }
}
//
result = ArraySize(signals);
//
return result;
}
//
// Request for Support Signals using Guard ...
bool RequestForSupport(
XSignal &support, // Holds Support Signal, if Provided
string provider, // Positions Provided by Specific Provider
string symbol, // Trading Symbol
ENUM_POSITION_TYPE type, // Trading Type
ENUM_TIMEFRAMES period // Specified Time Frame
) override
{
//
// TODO: Implement this ...
//
// Support Senario ...
// Check Support Position Exists or not ...
// Check Positions for Support based on Types ...
// Update Untriggered Positions ...
return false;
}
//
// Tools ...
//
// Management Tracker/Profit etc ...
//
// Handle Position Changed Event ...
void OnPositionsChangedHandler(int count) override
{
//
// Synchronize Tracker ...
SyncPositionTracker();
}
//
// Called when a Position Going in Profit ...
void OnPositionGoingInProfit(XPositionTrack &track) override
{
//
string message = "Position (" + ToString(track.ticket) + ", " + track.symbol + ") Dropped in Profit ...";
//
mAlert.Alert(message);
}
//
// Called when a Position Going to Drawdown ...
void OnPositionGoingToDrawdown(XPositionTrack &track) override
{
//
string message = "Position (" + ToString(track.ticket) + ", " + track.symbol + ") Dropped in Drawdown ...";
//
mAlert.Alert(message);
}
//
// Called when Account Going in Profit ...
void OnGoingToProfit(XProfitTrack &track) override
{
//
string message = "Account In Profit ...";
//
mAlert.Alert(message);
//
RemoveEQMOrders();
}
//
// Called when Account Going in Drawdown ...
void OnGoingToDrawdown(XProfitTrack &track) override
{
//
string message = "Account In Drawdown ...";
//
mAlert.Alert(message);
//
// Here i Have to Detect In DrawDown Positions ...
//
RemoveEQMOrders();
//
string mSymbols[];
XSCPositionHolder *mHolders[];
int symbolsCount = FilterSymbolBasedPositions(
mSymbols,
mHolders //
);
//
for (int i = 0; i < symbolsCount; i++)
{
//
string iSymbol = mSymbols[i];
XSCPositionHolder *iHolder = mHolders[i];
//
XPosition iMaxInDP;
bool hasMaxInDP = iHolder.GetMaxInDrawdown(iMaxInDP);
if (!hasMaxInDP)
{
continue;
}
//
// Try to Protect a Position ...
ProtectPosition(iMaxInDP);
}
}
//
// Protected ...
protected:
//
// Tools ...
//
void NotifyX121OnSignalEventHandlers(X121ProviderDescriptor &descriptor)
{
//
int listenersCount = ArraySize(mX121OnSignalEventHandlers);
if (listenersCount <= 0)
{
return;
}
//
for (int i = 0; i < listenersCount; i++)
{
//
TX121OnSignal iListener = mX121OnSignalEventHandlers[i];
//
iListener(descriptor);
}
}
//
// Protect Specified Position ...
void ProtectPosition(XPosition &position)
{
//
// Here i Can Protect Position ...
// This Protect Include One Position in Market Mode ...
// If Provided ...
// the Positions Selection must passed Some conditions ...
//
string message = "For (" + position.symbol + ") Max In Drawdown Position is: (" +
ToString(position.ticket) + "), by Profit: " + ToString(position.profit);
//
mAlert.Alert(message);
}
//
// Private ...
private:
//
// Props ...
//
// Collection of Signal Event Listeners ...
TX121OnSignal mX121OnSignalEventHandlers[];
//
// a Collection of X5 Provider Descriptors ...
X121ProviderDescriptor mDescriptors[];
//
int CountDescriptors()
{
return ArraySize(mDescriptors);
}
//
// Find Specifc Descriptor ...
int FindDescriptorIndex(
string symbol,
ENUM_TIMEFRAMES period //
)
{
//
int result = -1;
//
if (!IsValid(symbol) ||
!IsValid(period))
{
return result;
}
//
int descriptorsCount = CountDescriptors();
if (!IsValidSize(descriptorsCount))
{
return result;
}
//
for (int i = 0; i < descriptorsCount; i++)
{
//
X121ProviderDescriptor iDescriptor = mDescriptors[i];
//
bool isPassed =
//
iDescriptor.symbol == symbol &&
iDescriptor.period == period
//
;
if (isPassed)
{
//
result = i;
break;
}
}
//
return result;
}
template <typename T>
int FindDescriptorIndex(
T &item //
)
{
return FindDescriptorIndex(
item.symbol,
item.period //
);
}
//
// Trails Holding ...
//
XTrail mSLTrails[];
XTrail mTPTrails[];
//
int CountSLTrails()
{
return ArraySize(mSLTrails);
}
int CountTPTrails()
{
return ArraySize(mTPTrails);
}
//
bool RemoveTrail(ulong ticket)
{
//
bool isSLRemoved = RemoveSLTrail(ticket);
bool isTPRemoved = RemoveTPTrail(ticket);
//
bool result = isSLRemoved || isTPRemoved;
//
return result;
}
bool RemoveSLTrail(ulong ticket)
{
//
bool result = false;
//
int idx = FindSLTrailIndex(ticket);
result = idx >= 0;
if (!result)
{
return result;
}
//
result = ArrayRemove(
mSLTrails,
idx,
1 //
);
//
return result;
}
bool RemoveTPTrail(ulong ticket)
{
//
bool result = false;
//
int idx = FindTPTrailIndex(ticket);
result = idx >= 0;
if (!result)
{
return result;
}
//
result = ArrayRemove(
mTPTrails,
idx,
1 //
);
//
return result;
}
//
int FindSLTrailIndex(ulong ticket)
{
//
int result = -1;
//
int trailsCount = CountSLTrails();
if (ticket <= 0 || trailsCount <= 0)
{
return result;
}
//
for (int i = 0; i < trailsCount; i++)
{
//
XTrail iTrail = mSLTrails[i];
//
if (iTrail.ticket == ticket)
{
//
result = i;
break;
}
}
//
return result;
}
int FindTPTrailIndex(ulong ticket)
{
//
int result = -1;
//
int trailsCount = CountTPTrails();
if (ticket <= 0 || trailsCount <= 0)
{
return result;
}
//
for (int i = 0; i < trailsCount; i++)
{
//
XTrail iTrail = mTPTrails[i];
//
if (iTrail.ticket == ticket)
{
//
result = i;
break;
}
}
//
return result;
}
//
bool GetSLTrail(
ulong ticket,
XTrail &trail //
)
{
//
bool result = false;
//
int idx = FindSLTrailIndex(ticket);
result = idx >= 0;
if (!result)
{
return result;
}
//
trail = mSLTrails[idx];
//
return result;
}
bool GetTPTrail(
ulong ticket,
XTrail &trail //
)
{
//
bool result = false;
//
int idx = FindTPTrailIndex(ticket);
result = idx >= 0;
if (!result)
{
return result;
}
//
trail = mTPTrails[idx];
//
return result;
}
//
void AddSLTrail(
XTrail &trail //
)
{
//
if (!trail.IsValid())
{
return;
}
//
AddRef(
trail,
mSLTrails //
);
}
void AddTPTrail(
XTrail &trail //
)
{
//
if (!trail.IsValid())
{
return;
}
//
AddRef(
trail,
mTPTrails //
);
}
//
// Tools ...
};
//
// Tools ...
//