1973 lines
38 KiB
Plaintext
1973 lines
38 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Class
|
|
// -------------------------------------------------
|
|
// Name: XCXGuard ...
|
|
// Description: Guard Provider Class ...
|
|
//
|
|
//
|
|
// Maintainer:
|
|
// ------------
|
|
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// Global Properties ...
|
|
#property library
|
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
|
#property link "https://saherelm.ir"
|
|
#property version "1.00"
|
|
#property description "SaherElm Guard Provider Class"
|
|
#property strict
|
|
|
|
//
|
|
// Imports ...
|
|
#include "../Classes/x-saherelm.x-alert.class.mq5"
|
|
#include "../Classes/x-saherelm.x-trade.class.mq5"
|
|
#include "../Libraries/x-saherelm.x-guard.lib.mq5"
|
|
|
|
//
|
|
// Implementation ...
|
|
class XCGuard : public XCBase
|
|
{
|
|
//
|
|
// public ...
|
|
public:
|
|
//
|
|
// Props ...
|
|
double minVolumeFactorForHedge; // Minimum Volume Factor for Hedge Profit Calculation ...
|
|
double minProfitPerVolumeFactorForHedge; // Minimum Required Profit per Volume Factor for Hedg ...
|
|
TOnGuarded onGuardEventListener; // On Guard Event Listener ...
|
|
|
|
//
|
|
// Constructor(s) ...
|
|
XCGuard(
|
|
XCAlert *_alert,
|
|
XCTrade *_trader //
|
|
)
|
|
{
|
|
//
|
|
alert = _alert;
|
|
trader = _trader;
|
|
|
|
//
|
|
minVolumeFactorForHedge = 0.01;
|
|
minProfitPerVolumeFactorForHedge = 0.5;
|
|
}
|
|
|
|
//
|
|
// Deconstructor(s) ...
|
|
~XCGuard()
|
|
{
|
|
//
|
|
ZeroMemory(alert);
|
|
ZeroMemory(trader);
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
void DoGuards(XGuard &guards[])
|
|
{
|
|
//
|
|
bool has = HasChild(guards);
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
XGuard tmp[];
|
|
Copy(
|
|
guards,
|
|
tmp //
|
|
);
|
|
while (HasChild(tmp))
|
|
{
|
|
//
|
|
XGuard iGuard = tmp[0];
|
|
ArrayRemove(
|
|
tmp,
|
|
0,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
// Do Guard Action ...
|
|
DoGuard(iGuard);
|
|
}
|
|
|
|
//
|
|
Clean(tmp);
|
|
}
|
|
|
|
//
|
|
void DoGuard(XGuard &guard)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
// Validate and Do Guard ...
|
|
has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Switch Based on Guard Action ...
|
|
switch (guard.action)
|
|
{
|
|
//
|
|
// Close ...
|
|
case X_GUARD_ACTION_CLOSE:
|
|
DoClose(guard);
|
|
break;
|
|
|
|
//
|
|
// Close All ...
|
|
case X_GUARD_ACTION_CLOSE_ALL:
|
|
DoCloseAll(guard);
|
|
break;
|
|
|
|
//
|
|
// Close All Long Positions ...
|
|
case X_GUARD_ACTION_CLOSE_LONGS:
|
|
DoCloseLongs(guard);
|
|
break;
|
|
|
|
//
|
|
// Close All Short Positions ...
|
|
case X_GUARD_ACTION_CLOSE_SHORTS:
|
|
DoCloseShorts(guard);
|
|
break;
|
|
|
|
//
|
|
// Close In Losts ...
|
|
case X_GUARD_ACTION_CLOSE_IN_LOSTS:
|
|
DoCloseInLosts(guard);
|
|
break;
|
|
|
|
//
|
|
// Close In Profits ...
|
|
case X_GUARD_ACTION_CLOSE_IN_PROFITS:
|
|
DoCloseInProfits(guard);
|
|
break;
|
|
|
|
//
|
|
// Close In Lost Longs ...
|
|
case X_GUARD_ACTION_CLOSE_IN_LOST_LONGS:
|
|
DoCloseInLostLongs(guard);
|
|
break;
|
|
|
|
//
|
|
// Close In Profit Longs ...
|
|
case X_GUARD_ACTION_CLOSE_IN_PROFIT_LONGS:
|
|
DoCloseInProfitLongs(guard);
|
|
break;
|
|
|
|
//
|
|
// Close In Lost Shorts ...
|
|
case X_GUARD_ACTION_CLOSE_IN_LOST_SHORTS:
|
|
DoCloseInLostShorts(guard);
|
|
break;
|
|
|
|
//
|
|
// Close In Profit Shorts ...
|
|
case X_GUARD_ACTION_CLOSE_IN_PROFITS_SHORT:
|
|
DoCloseInProfitShorts(guard);
|
|
break;
|
|
|
|
//
|
|
// Partial Close ...
|
|
case X_GUARD_ACTION_PARTIAL_CLOSE:
|
|
DoPartialClose(guard);
|
|
break;
|
|
|
|
//
|
|
// Trail Stop ...
|
|
case X_GUARD_ACTION_TRAIL_STOP:
|
|
DoTrailStop(guard);
|
|
break;
|
|
|
|
//
|
|
// Trail Target ...
|
|
case X_GUARD_ACTION_TRAIL_TARGET:
|
|
DoTrailTarget(guard);
|
|
break;
|
|
|
|
//
|
|
// Hedge Positions ...
|
|
case X_GUARD_ACTION_HEDGE:
|
|
DoHedge(guard);
|
|
break;
|
|
|
|
//
|
|
}
|
|
}
|
|
|
|
//
|
|
// protected ...
|
|
protected:
|
|
//
|
|
|
|
//
|
|
bool GetPosition(
|
|
XPosition &position,
|
|
XGuard &guard //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
position.Clean();
|
|
|
|
//
|
|
result =
|
|
guard.IsValid() &&
|
|
guard.ticket > 0;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Position ...
|
|
result = trader.GetPosition(
|
|
guard.ticket,
|
|
position //
|
|
);
|
|
if (!result)
|
|
{
|
|
//
|
|
position.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Position ...
|
|
result =
|
|
position.IsValid() &&
|
|
position.symbol == guard.symbol &&
|
|
position.provider == guard.provider &&
|
|
position.period == guard.period;
|
|
if (!result)
|
|
{
|
|
//
|
|
position.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetPositions(
|
|
XPosition &positions[],
|
|
XGuard &guard //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
bool has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = trader.GetPositions(
|
|
positions,
|
|
guard.symbol,
|
|
guard.provider,
|
|
guard.period,
|
|
NULL, // All Types ...
|
|
true, // Filter By Magc ...
|
|
true // Force Clean ...
|
|
);
|
|
|
|
//
|
|
result = ArraySize(positions);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetLongPositions(
|
|
XPosition &positions[],
|
|
XGuard &guard //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
bool has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = trader.GetPositions(
|
|
positions,
|
|
guard.symbol,
|
|
guard.provider,
|
|
guard.period,
|
|
X_POSITION_TYPE_LONG, // Specified Types ...
|
|
true, // Filter By Magc ...
|
|
true // Force Clean ...
|
|
);
|
|
|
|
//
|
|
result = ArraySize(positions);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetShortPositions(
|
|
XPosition &positions[],
|
|
XGuard &guard //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
bool has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = trader.GetPositions(
|
|
positions,
|
|
guard.symbol,
|
|
guard.provider,
|
|
guard.period,
|
|
X_POSITION_TYPE_SHORT, // Specified Types ...
|
|
true, // Filter By Magc ...
|
|
true // Force Clean ...
|
|
);
|
|
|
|
//
|
|
result = ArraySize(positions);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetInProfitPositions(
|
|
XPosition &positions[],
|
|
XGuard &guard //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
bool has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XPosition allPositions[];
|
|
int allPositionsCount = GetPositions(
|
|
allPositions,
|
|
guard //
|
|
);
|
|
has = IsValidSize(allPositionsCount);
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
while (HasChild(allPositions))
|
|
{
|
|
//
|
|
XPosition iPosition = allPositions[0];
|
|
ArrayRemove(
|
|
allPositions,
|
|
0,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
if (iPosition.profit > 0)
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
positions //
|
|
);
|
|
}
|
|
|
|
//
|
|
iPosition.Clean();
|
|
}
|
|
Clean(allPositions);
|
|
|
|
//
|
|
result = ArraySize(positions);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetInLostPositions(
|
|
XPosition &positions[],
|
|
XGuard &guard //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
bool has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XPosition allPositions[];
|
|
int allPositionsCount = GetPositions(
|
|
allPositions,
|
|
guard //
|
|
);
|
|
has = IsValidSize(allPositionsCount);
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
while (HasChild(allPositions))
|
|
{
|
|
//
|
|
XPosition iPosition = allPositions[0];
|
|
ArrayRemove(
|
|
allPositions,
|
|
0,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
if (iPosition.profit < 0)
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
positions //
|
|
);
|
|
}
|
|
|
|
//
|
|
iPosition.Clean();
|
|
}
|
|
Clean(allPositions);
|
|
|
|
//
|
|
result = ArraySize(positions);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetInProfitLongPositions(
|
|
XPosition &positions[],
|
|
XGuard &guard //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
bool has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XPosition allPositions[];
|
|
int allPositionsCount = GetLongPositions(
|
|
allPositions,
|
|
guard //
|
|
);
|
|
has = IsValidSize(allPositionsCount);
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
while (HasChild(allPositions))
|
|
{
|
|
//
|
|
XPosition iPosition = allPositions[0];
|
|
ArrayRemove(
|
|
allPositions,
|
|
0,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
if (iPosition.profit > 0)
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
positions //
|
|
);
|
|
}
|
|
|
|
//
|
|
iPosition.Clean();
|
|
}
|
|
Clean(allPositions);
|
|
|
|
//
|
|
result = ArraySize(positions);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetInLostLongPositions(
|
|
XPosition &positions[],
|
|
XGuard &guard //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
bool has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XPosition allPositions[];
|
|
int allPositionsCount = GetLongPositions(
|
|
allPositions,
|
|
guard //
|
|
);
|
|
has = IsValidSize(allPositionsCount);
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
while (HasChild(allPositions))
|
|
{
|
|
//
|
|
XPosition iPosition = allPositions[0];
|
|
ArrayRemove(
|
|
allPositions,
|
|
0,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
if (iPosition.profit < 0)
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
positions //
|
|
);
|
|
}
|
|
|
|
//
|
|
iPosition.Clean();
|
|
}
|
|
Clean(allPositions);
|
|
|
|
//
|
|
result = ArraySize(positions);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetInProfitShortPositions(
|
|
XPosition &positions[],
|
|
XGuard &guard //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
bool has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XPosition allPositions[];
|
|
int allPositionsCount = GetShortPositions(
|
|
allPositions,
|
|
guard //
|
|
);
|
|
has = IsValidSize(allPositionsCount);
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
while (HasChild(allPositions))
|
|
{
|
|
//
|
|
XPosition iPosition = allPositions[0];
|
|
ArrayRemove(
|
|
allPositions,
|
|
0,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
if (iPosition.profit > 0)
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
positions //
|
|
);
|
|
}
|
|
|
|
//
|
|
iPosition.Clean();
|
|
}
|
|
Clean(allPositions);
|
|
|
|
//
|
|
result = ArraySize(positions);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetInLostShortPositions(
|
|
XPosition &positions[],
|
|
XGuard &guard //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
bool has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XPosition allPositions[];
|
|
int allPositionsCount = GetShortPositions(
|
|
allPositions,
|
|
guard //
|
|
);
|
|
has = IsValidSize(allPositionsCount);
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
while (HasChild(allPositions))
|
|
{
|
|
//
|
|
XPosition iPosition = allPositions[0];
|
|
ArrayRemove(
|
|
allPositions,
|
|
0,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
if (iPosition.profit < 0)
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
positions //
|
|
);
|
|
}
|
|
|
|
//
|
|
iPosition.Clean();
|
|
}
|
|
Clean(allPositions);
|
|
|
|
//
|
|
result = ArraySize(positions);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Guard Handlers ...
|
|
|
|
//
|
|
void DoClose(XGuard &guard)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Do What we want ...
|
|
|
|
//
|
|
// Validate Action and Requirements ...
|
|
has =
|
|
NotEmpty(guard.ticket) &&
|
|
guard.action == X_GUARD_ACTION_CLOSE;
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Retrieve Position ...
|
|
XPosition position;
|
|
has = GetPosition(
|
|
position,
|
|
guard //
|
|
);
|
|
if (!has)
|
|
{
|
|
//
|
|
position.Clean();
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
string comment = "Guard Close ...";
|
|
|
|
//
|
|
has = trader.Close(
|
|
position.ticket,
|
|
comment //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
HandleNotifyPositionGuard(guard.action, position);
|
|
|
|
//
|
|
string message =
|
|
"Guard Closed " +
|
|
ToXString(position.type) +
|
|
" Position (" + ToXString(position.ticket) + ") Successfully ...";
|
|
|
|
//
|
|
alert.SendAlert(message);
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
|
|
//
|
|
position.Clean();
|
|
}
|
|
|
|
//
|
|
void DoCloseAll(XGuard &guard)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Do What we want ...
|
|
has = guard.action == X_GUARD_ACTION_CLOSE_ALL;
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Retrieve Positions ...
|
|
XPosition positions[];
|
|
int count = GetPositions(
|
|
positions,
|
|
guard //
|
|
);
|
|
has = IsValidSize(count);
|
|
if (!has)
|
|
{
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
string comment = "Guard Close All ...";
|
|
|
|
//
|
|
has = trader.Close(
|
|
positions,
|
|
comment //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
HandleNotifyPositionsGuard(guard.action, positions);
|
|
|
|
//
|
|
string message =
|
|
"Guard Closed " +
|
|
ToXString(count) +
|
|
" Positions Successfully ...";
|
|
|
|
//
|
|
alert.SendAlert(message);
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
|
|
//
|
|
Clean(positions);
|
|
}
|
|
|
|
//
|
|
void DoCloseInLosts(XGuard &guard)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Do What we want ...
|
|
has = guard.action == X_GUARD_ACTION_CLOSE_IN_LOSTS;
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Retrieve Positions ...
|
|
XPosition positions[];
|
|
int count = GetInLostPositions(
|
|
positions,
|
|
guard //
|
|
);
|
|
has = IsValidSize(count);
|
|
if (!has)
|
|
{
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
string comment = "Guard Close All In Losts ...";
|
|
|
|
//
|
|
has = trader.Close(
|
|
positions,
|
|
comment //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
HandleNotifyPositionsGuard(guard.action, positions);
|
|
|
|
//
|
|
string message =
|
|
"Guard Closed " +
|
|
ToXString(count) +
|
|
" In Lost Positions Successfully ...";
|
|
|
|
//
|
|
alert.SendAlert(message);
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
|
|
//
|
|
Clean(positions);
|
|
}
|
|
|
|
//
|
|
void DoCloseInProfits(XGuard &guard)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Do What we want ...
|
|
has = guard.action == X_GUARD_ACTION_CLOSE_IN_PROFITS;
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Retrieve Positions ...
|
|
XPosition positions[];
|
|
int count = GetInProfitPositions(
|
|
positions,
|
|
guard //
|
|
);
|
|
has = IsValidSize(count);
|
|
if (!has)
|
|
{
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
string comment = "Guard Close All In Profits ...";
|
|
|
|
//
|
|
has = trader.Close(
|
|
positions,
|
|
comment //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
HandleNotifyPositionsGuard(guard.action, positions);
|
|
|
|
//
|
|
string message =
|
|
"Guard Closed " +
|
|
ToXString(count) +
|
|
" In Profit Positions Successfully ...";
|
|
|
|
//
|
|
alert.SendAlert(message);
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
|
|
//
|
|
Clean(positions);
|
|
}
|
|
|
|
//
|
|
void DoCloseLongs(XGuard &guard)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Do What we want ...
|
|
has = guard.action == X_GUARD_ACTION_CLOSE_LONGS;
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Retrieve Positions ...
|
|
XPosition positions[];
|
|
int count = GetLongPositions(
|
|
positions,
|
|
guard //
|
|
);
|
|
has = IsValidSize(count);
|
|
if (!has)
|
|
{
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
string comment = "Guard Close Longs ...";
|
|
|
|
//
|
|
has = trader.Close(
|
|
positions,
|
|
comment //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
HandleNotifyPositionsGuard(guard.action, positions);
|
|
|
|
//
|
|
string message =
|
|
"Guard Closed " +
|
|
ToXString(count) +
|
|
" Long Positions Successfully ...";
|
|
|
|
//
|
|
alert.SendAlert(message);
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
|
|
//
|
|
Clean(positions);
|
|
}
|
|
|
|
//
|
|
void DoCloseInLostLongs(XGuard &guard)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Do What we want ...
|
|
has = guard.action == X_GUARD_ACTION_CLOSE_IN_LOST_LONGS;
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Retrieve Positions ...
|
|
XPosition positions[];
|
|
int count = GetInLostLongPositions(
|
|
positions,
|
|
guard //
|
|
);
|
|
has = IsValidSize(count);
|
|
if (!has)
|
|
{
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
string comment = "Guard Close All In Lost Longs ...";
|
|
|
|
//
|
|
has = trader.Close(
|
|
positions,
|
|
comment //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
HandleNotifyPositionsGuard(guard.action, positions);
|
|
|
|
//
|
|
string message =
|
|
"Guard Closed " +
|
|
ToXString(count) +
|
|
" In Lost Longs Positions Successfully ...";
|
|
|
|
//
|
|
alert.SendAlert(message);
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
|
|
//
|
|
Clean(positions);
|
|
}
|
|
|
|
//
|
|
void DoCloseInProfitLongs(XGuard &guard)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Do What we want ...
|
|
has = guard.action == X_GUARD_ACTION_CLOSE_IN_PROFIT_LONGS;
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Retrieve Positions ...
|
|
XPosition positions[];
|
|
int count = GetInProfitLongPositions(
|
|
positions,
|
|
guard //
|
|
);
|
|
has = IsValidSize(count);
|
|
if (!has)
|
|
{
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
string comment = "Guard Close All In Profit Longs ...";
|
|
|
|
//
|
|
has = trader.Close(
|
|
positions,
|
|
comment //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
HandleNotifyPositionsGuard(guard.action, positions);
|
|
|
|
//
|
|
string message =
|
|
"Guard Closed " +
|
|
ToXString(count) +
|
|
" In Profit Longs Positions Successfully ...";
|
|
|
|
//
|
|
alert.SendAlert(message);
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
|
|
//
|
|
Clean(positions);
|
|
}
|
|
|
|
//
|
|
void DoCloseShorts(XGuard &guard)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Retrieve Positions ...
|
|
XPosition positions[];
|
|
int count = GetShortPositions(
|
|
positions,
|
|
guard //
|
|
);
|
|
has = IsValidSize(count);
|
|
if (!has)
|
|
{
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
string comment = "Guard Close Shorts ...";
|
|
|
|
//
|
|
has = trader.Close(
|
|
positions,
|
|
comment //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
HandleNotifyPositionsGuard(guard.action, positions);
|
|
|
|
//
|
|
string message =
|
|
"Guard Closed " +
|
|
ToXString(count) +
|
|
" Long Positions Successfully ...";
|
|
|
|
//
|
|
alert.SendAlert(message);
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
|
|
//
|
|
Clean(positions);
|
|
}
|
|
|
|
//
|
|
void DoCloseInLostShorts(XGuard &guard)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Do What we want ...
|
|
has = guard.action == X_GUARD_ACTION_CLOSE_IN_LOST_SHORTS;
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Retrieve Positions ...
|
|
XPosition positions[];
|
|
int count = GetInLostShortPositions(
|
|
positions,
|
|
guard //
|
|
);
|
|
has = IsValidSize(count);
|
|
if (!has)
|
|
{
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
string comment = "Guard Close All In Lost Shorts ...";
|
|
|
|
//
|
|
has = trader.Close(
|
|
positions,
|
|
comment //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
HandleNotifyPositionsGuard(guard.action, positions);
|
|
|
|
//
|
|
string message =
|
|
"Guard Closed " +
|
|
ToXString(count) +
|
|
" In Lost Shorts Positions Successfully ...";
|
|
|
|
//
|
|
alert.SendAlert(message);
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
|
|
//
|
|
Clean(positions);
|
|
}
|
|
|
|
//
|
|
void DoCloseInProfitShorts(XGuard &guard)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Do What we want ...
|
|
has = guard.action == X_GUARD_ACTION_CLOSE_IN_PROFITS_SHORT;
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Retrieve Positions ...
|
|
XPosition positions[];
|
|
int count = GetInProfitShortPositions(
|
|
positions,
|
|
guard //
|
|
);
|
|
has = IsValidSize(count);
|
|
if (!has)
|
|
{
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
string comment = "Guard Close All In Profit Shorts ...";
|
|
|
|
//
|
|
has = trader.Close(
|
|
positions,
|
|
comment //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
HandleNotifyPositionsGuard(guard.action, positions);
|
|
|
|
//
|
|
//
|
|
string message =
|
|
"Guard Closed " +
|
|
ToXString(count) +
|
|
" In Profit Shorts Positions Successfully ...";
|
|
|
|
//
|
|
alert.SendAlert(message);
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
|
|
//
|
|
Clean(positions);
|
|
}
|
|
|
|
//
|
|
void DoPartialClose(XGuard &guard)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Do What we want ...
|
|
|
|
//
|
|
// Validate Action and Requirements ...
|
|
has =
|
|
NotEmpty(guard.ticket) &&
|
|
guard.volumeMultiplier > 0 &&
|
|
guard.action == X_GUARD_ACTION_PARTIAL_CLOSE;
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Retrieve Position ...
|
|
XPosition position;
|
|
has = GetPosition(
|
|
position,
|
|
guard //
|
|
);
|
|
if (!has)
|
|
{
|
|
//
|
|
position.Clean();
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Normalize Volume Multiplier ...
|
|
double vMult = guard.volumeMultiplier;
|
|
if (vMult > 0.5)
|
|
{
|
|
vMult = 0.5;
|
|
}
|
|
if (vMult < 0)
|
|
{
|
|
vMult = 0.5;
|
|
}
|
|
|
|
//
|
|
// Calculate and Normalize Volume ...
|
|
double volume = position.volume * vMult;
|
|
volume = NormalizeVolume(
|
|
volume,
|
|
position.symbol //
|
|
);
|
|
|
|
//
|
|
string comment = "Guard Partially Closed: " + ToXString(volume) + " ...";
|
|
|
|
//
|
|
has = trader.ClosePartial(
|
|
position.ticket,
|
|
volume,
|
|
comment //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
HandleNotifyPositionGuard(guard.action, position);
|
|
|
|
//
|
|
string message =
|
|
"Guard Closed Partially " +
|
|
ToXString(volume) + " of " +
|
|
ToXString(position.type) +
|
|
" Position (" + ToXString(position.ticket) + ") Successfully ...";
|
|
|
|
//
|
|
alert.SendAlert(message);
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
|
|
//
|
|
position.Clean();
|
|
}
|
|
|
|
//
|
|
void DoTrailStop(XGuard &guard)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Do What we want ...
|
|
|
|
//
|
|
// Validate Action and Requirements ...
|
|
has =
|
|
guard.sl >= 0 &&
|
|
NotEmpty(guard.ticket) &&
|
|
(guard.sl <= 0
|
|
? guard.force
|
|
: true) &&
|
|
guard.action == X_GUARD_ACTION_TRAIL_STOP;
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Normalize SL ...
|
|
if (guard.sl < 0)
|
|
{
|
|
guard.sl = 0;
|
|
}
|
|
|
|
//
|
|
// Retrieve Position ...
|
|
XPosition position;
|
|
has = GetPosition(
|
|
position,
|
|
guard //
|
|
);
|
|
if (!has)
|
|
{
|
|
//
|
|
position.Clean();
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
bool isLong = IsLong(position.type);
|
|
bool isGuardPassed =
|
|
guard.sl > 0
|
|
? (isLong
|
|
? position.price > guard.sl &&
|
|
(position.sl == 0 ||
|
|
position.sl < guard.sl)
|
|
: position.price < guard.sl &&
|
|
(position.sl == 0 ||
|
|
position.sl > guard.sl))
|
|
: (guard.sl == 0 && guard.force);
|
|
|
|
//
|
|
// Check Can Trail Stop or not ...
|
|
has =
|
|
//
|
|
// Position Exists ...
|
|
has &&
|
|
//
|
|
// Positions in Profit for Trailling Stop ...
|
|
position.profit > 0 &&
|
|
//
|
|
// Validate SL based on Position Type ...
|
|
isGuardPassed;
|
|
if (!has)
|
|
{
|
|
//
|
|
position.Clean();
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
string comment = "Guard Trail Stop ...";
|
|
|
|
//
|
|
has = trader.Modify(
|
|
position.ticket,
|
|
guard.sl,
|
|
position.tp,
|
|
comment //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
HandleNotifyPositionGuard(guard.action, position);
|
|
|
|
//
|
|
double before = NormalizePrice(position.sl, position.symbol);
|
|
double after = NormalizePrice(guard.sl, position.symbol);
|
|
|
|
//
|
|
string message =
|
|
"Guard Trail Stop " +
|
|
ToXString(position.type) +
|
|
" Position (" + ToXString(position.ticket) + ")" +
|
|
" From: " + ToXString(before) +
|
|
"To: " + ToXString(after) +
|
|
" Successfully ...";
|
|
|
|
//
|
|
alert.SendAlert(message);
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
|
|
//
|
|
position.Clean();
|
|
}
|
|
|
|
//
|
|
void DoTrailTarget(XGuard &guard)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Do What we want ...
|
|
|
|
//
|
|
// Validate Action and Requirements ...
|
|
has =
|
|
guard.tp >= 0 &&
|
|
NotEmpty(guard.ticket) &&
|
|
(guard.tp <= 0
|
|
? guard.force
|
|
: true) &&
|
|
guard.action == X_GUARD_ACTION_TRAIL_TARGET;
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Normalize ...
|
|
if (guard.tp < 0)
|
|
{
|
|
guard.tp = 0;
|
|
}
|
|
|
|
//
|
|
// Retrieve Position ...
|
|
XPosition position;
|
|
has = GetPosition(
|
|
position,
|
|
guard //
|
|
);
|
|
if (!has)
|
|
{
|
|
//
|
|
position.Clean();
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
bool isLong = IsLong(position.type);
|
|
bool isGuardPassed =
|
|
guard.tp > 0
|
|
? (isLong
|
|
? guard.tp > position.price
|
|
: guard.tp < position.price)
|
|
: (guard.tp == 0 && guard.force);
|
|
|
|
//
|
|
// Check Can Trail Stop or not ...
|
|
has =
|
|
//
|
|
// Position Exists ...
|
|
has &&
|
|
//
|
|
// Check TP is not Same ...
|
|
guard.tp != position.tp &&
|
|
//
|
|
// Validate TP based on Current Price ...
|
|
isGuardPassed;
|
|
if (!has)
|
|
{
|
|
//
|
|
position.Clean();
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
string comment = "Guard Trail Target ...";
|
|
|
|
//
|
|
has = trader.Modify(
|
|
position.ticket,
|
|
position.sl,
|
|
guard.tp,
|
|
comment //
|
|
);
|
|
if (has)
|
|
{
|
|
//
|
|
HandleNotifyPositionGuard(guard.action, position);
|
|
|
|
//
|
|
double before = NormalizePrice(position.tp, position.symbol);
|
|
double after = NormalizePrice(guard.tp, position.symbol);
|
|
|
|
//
|
|
string message =
|
|
"Guard Trail Target " +
|
|
ToXString(position.type) +
|
|
" Position (" + ToXString(position.ticket) + ")" +
|
|
" From: " + ToXString(before) +
|
|
"To: " + ToXString(after) +
|
|
" Successfully ...";
|
|
|
|
//
|
|
alert.SendAlert(message);
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
|
|
//
|
|
position.Clean();
|
|
}
|
|
|
|
//
|
|
void DoHedge(XGuard &guard)
|
|
{
|
|
//
|
|
bool has = false;
|
|
|
|
//
|
|
has = guard.IsValid();
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Do What we want ...
|
|
|
|
//
|
|
// Validate Action and Requirements ...
|
|
has =
|
|
(guard.force
|
|
? true
|
|
: (minVolumeFactorForHedge > 0 &&
|
|
minProfitPerVolumeFactorForHedge > 0)) &&
|
|
guard.action == X_GUARD_ACTION_HEDGE;
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Retrieve Positions ...
|
|
XPosition positions[];
|
|
int count = GetPositions(
|
|
positions,
|
|
guard //
|
|
);
|
|
has = HasChild(positions);
|
|
if (!has)
|
|
{
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Calculate Positions Profits and Volumes ...
|
|
double swaps = 0;
|
|
double profits = 0;
|
|
double volumes = 0;
|
|
double commissions = 0;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
swaps += positions[i].swap;
|
|
profits += positions[i].profit;
|
|
volumes += positions[i].volume;
|
|
commissions += positions[i].commission;
|
|
}
|
|
|
|
//
|
|
// Check Profits and Volumes for Hedging ...
|
|
double hedgeValue = profits + (-1 * swaps) + commissions;
|
|
|
|
//
|
|
// Check Force Hedging ...
|
|
if (!guard.force)
|
|
{
|
|
//
|
|
// Calculate Minimum Required Profit for Hedging ...
|
|
double minRequiredProfit =
|
|
(volumes / minVolumeFactorForHedge) * minProfitPerVolumeFactorForHedge;
|
|
|
|
//
|
|
has = hedgeValue >= minRequiredProfit;
|
|
}
|
|
else
|
|
{
|
|
has = hedgeValue > 0;
|
|
}
|
|
|
|
//
|
|
if (!has)
|
|
{
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
string comment = "Guard Hedge ...";
|
|
|
|
//
|
|
// Loop through Positions and Close them One by One ...
|
|
// this is because of Trade Manager to Handle Close Trades ...
|
|
int closedCount = 0;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
has = trader.Close(
|
|
positions[i].ticket,
|
|
comment //
|
|
);
|
|
if (has)
|
|
{
|
|
closedCount++;
|
|
}
|
|
}
|
|
|
|
//
|
|
has = IsValidSize(closedCount);
|
|
if (has)
|
|
{
|
|
//
|
|
HandleNotifyPositionsGuard(guard.action, positions);
|
|
|
|
//
|
|
string message =
|
|
"Guard Hedge " +
|
|
ToXString(closedCount) +
|
|
" Positions by: " +
|
|
ToXString(hedgeValue) +
|
|
" Successfully ...";
|
|
|
|
//
|
|
alert.SendAlert(message);
|
|
}
|
|
|
|
//
|
|
// Cleanup Resources ...
|
|
|
|
//
|
|
Clean(positions);
|
|
}
|
|
|
|
//
|
|
// private ...
|
|
private:
|
|
//
|
|
XCTrade *trader;
|
|
XCAlert *alert;
|
|
|
|
//
|
|
void HandleNotifyPositionGuard(
|
|
ENUM_X_GUARD_ACTIONS action,
|
|
XPosition &position //
|
|
)
|
|
{
|
|
//
|
|
if (!IsSpecifiedValid(action) || !position.IsValid() || onGuardEventListener == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
XPosition positions[];
|
|
AddRef(
|
|
position,
|
|
positions //
|
|
);
|
|
HandleNotifyPositionsGuard(action, positions);
|
|
}
|
|
|
|
//
|
|
void HandleNotifyPositionsGuard(
|
|
ENUM_X_GUARD_ACTIONS action,
|
|
XPosition &positions[] //
|
|
)
|
|
{
|
|
//
|
|
if (!IsSpecifiedValid(action) || !HasChild(positions) || onGuardEventListener == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
onGuardEventListener(action, positions);
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
// |