Files
xMQL5/BKPS/14040316/XCATBEA/Classes/xcatbea.x-trade.manager.class.mq5
T
2025-06-06 09:20:17 +03:30

3783 lines
84 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Class Library
// --------------------------------------
// Name: XCXCATBEATradeManager
// Description: provides all Requirements for Managing Trades ...
//
//
// Maintainer:
// ------------
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
//
//////////////////////////////////////////////////////
//
// Global Properties ...
#property library
#property copyright "Copyright 2023, SaherElm IT Center"
#property link "https://www.saherelm.ir"
#property version "1.00"
#property strict
//
// Imports ...
#include "../../Classes/x-saherelm.x-alert.class.mq5"
#include "../../Classes/x-saherelm.x-data.collector.class.mq5"
#include "../../Classes/x-saherelm.x-poi.drawer.class.mq5"
#include "../../Classes/x-saherelm.x-trade.class.mq5"
#include "../../Libraries/x-saherelm.x-poi.lib.mq5"
#include "../Libraries/xcatbea.lib.mq5"
#include "../Libraries/xcatbea.signaller.lib.mq5"
//
// Definitions ...
//
enum ENUM_XCATBEA_TRADE_RESTRICTION_PERIOD
{
XCATBEA_TRADE_RESTRICATION_NONE, // None
XCATBEA_TRADE_RESTRICATION_HOURLY, // Per Hour
XCATBEA_TRADE_RESTRICATION_DAILY, // Per Day
XCATBEA_TRADE_RESTRICATION_WEEKLY, // Per Week
XCATBEA_TRADE_RESTRICATION_MONTHLY, // Per Month
};
//
string ToString(ENUM_XCATBEA_TRADE_RESTRICTION_PERIOD value)
{
//
string result = NULL;
//
result = EnumToString(value);
//
return result;
}
//
enum ENUM_XCATBEA_TRADE_FINALIZATION
{
XCATBEA_TRADE_FINAL_NONE, // None
XCATBEA_TRADE_FINAL_TP, // TP
XCATBEA_TRADE_FINAL_SL, // SL
XCATBEA_TRADE_FINAL_CLOSE_IN_PROFIT, // Profit
XCATBEA_TRADE_FINAL_CLOSE_IN_LOSE, // Lost
};
//
string ToString(ENUM_XCATBEA_TRADE_FINALIZATION value)
{
//
string result = NULL;
//
result = EnumToString(value);
//
return result;
}
//
// Position Selecting ...
enum ENUM_XCATBEA_POSITION_SELECT_TYPES
{
XCATBEA_POSITION_SELECT_NONE = 0, // None
XCATBEA_POSITION_SELECT_ALL = 1, // All
XCATBEA_POSITION_SELECT_IN_PROFITS = 2, // In Profit Positions
XCATBEA_POSITION_SELECT_IN_DRAWDOWNS = 3, // In Drawdown Positions
XCATBEA_POSITION_SELECT_OLDEST = 4, // Oldest Position
XCATBEA_POSITION_SELECT_YOUNGEST = 5, // Youngest Position
XCATBEA_POSITION_SELECT_IN_PROFITS_OLDEST = 6, // In Profit Positions Oldest one
XCATBEA_POSITION_SELECT_IN_PROFITS_YOUNGEST = 7, // In Profit Positions Youngest one
XCATBEA_POSITION_SELECT_IN_PROFITS_MIN = 8, // Minimum Profitable Position
XCATBEA_POSITION_SELECT_IN_PROFITS_MAX = 9, // Maximum Profitable Position
XCATBEA_POSITION_SELECT_IN_DRAWDOWN_OLDEST = 10, // In Drawdown Positions Oldest one
XCATBEA_POSITION_SELECT_IN_DRAWDOWN_YOUNGEST = 11, // In Drawdown Positions Youngest one
XCATBEA_POSITION_SELECT_IN_DRAWDOWN_MIN = 12, // Minimum in Drawdown Position
XCATBEA_POSITION_SELECT_IN_DRAWDOWN_MAX = 13, // Maximum in Drawdown Position
XCATBEA_POSITION_SELECT_SAMES = 14, // Same Type Positions
XCATBEA_POSITION_SELECT_SAMES_OLDEST = 15, // Same Type Positions Oldest one
XCATBEA_POSITION_SELECT_SAMES_YOUNGEST = 16, // Same Type Positions Youngest one
XCATBEA_POSITION_SELECT_OPPOSITS = 17, // Opposit Type Positions
XCATBEA_POSITION_SELECT_OPPOSIT_OLDEST = 18, // Opposit Type Positions Oldest one
XCATBEA_POSITION_SELECT_OPPOSIT_YOUNGEST = 19, // Opposit Type Positions Youngest one
XCATBEA_POSITION_SELECT_SAME_IN_PROFITS = 20, // Same Type In Profit Positions
XCATBEA_POSITION_SELECT_SAME_IN_PROFITS_OLDEST = 21, // Same Type In Profit Positions Oldest one
XCATBEA_POSITION_SELECT_SAME_IN_PROFITS_YOUNGEST = 22, // Same Type In Profit Positions Youngest one
XCATBEA_POSITION_SELECT_SAME_IN_PROFITS_MIN = 23, // Minimum Profitable of Same Type Positions
XCATBEA_POSITION_SELECT_SAME_IN_PROFITS_MAX = 24, // Maximum Profitable of Same Type Positions
XCATBEA_POSITION_SELECT_OPPOSIT_IN_PROFITS = 25, // Opposit Type In Profit Positions
XCATBEA_POSITION_SELECT_OPPOSIT_IN_PROFITS_OLDEST = 26, // Opposit Type In Profit Positions Oldest one
XCATBEA_POSITION_SELECT_OPPOSIT_IN_PROFITS_YOUNGEST = 27, // Opposit Type In Profit Positions Youngest one
XCATBEA_POSITION_SELECT_OPPOSIT_IN_PROFITS_MIN = 28, // Minimum Profitable of Opposit Type Positions
XCATBEA_POSITION_SELECT_OPPOSIT_IN_PROFITS_MAX = 29, // Maximum Profitable of Opposit Type Positions
XCATBEA_POSITION_SELECT_SAME_IN_DRAWDOWNS = 30, // Same Type In Deawdown Positions
XCATBEA_POSITION_SELECT_SAME_IN_DRAWDOWN_OLDEST = 31, // Same Type In Deawdown Positions Oldest one
XCATBEA_POSITION_SELECT_SAME_IN_DRAWDOWN_YOUNGEST = 32, // Same Type In Deawdown Positions Youngest one
XCATBEA_POSITION_SELECT_SAME_IN_DRAWDOWN_MIN = 33, // Minimum In Drawdown of Same Type Positions
XCATBEA_POSITION_SELECT_SAME_IN_DRAWDOWN_MAX = 34, // Maximum In Drawdown of Same Type Positions
XCATBEA_POSITION_SELECT_OPPOSITS_IN_DRAWDOWNS = 35, // Opposit Type In Deawdown Positions
XCATBEA_POSITION_SELECT_OPPOSITS_IN_DRAWDOWN_OLDEST = 36, // Opposit Type In Deawdown Positions Oldest one
XCATBEA_POSITION_SELECT_OPPOSITS_IN_DRAWDOWN_YOUNGEST = 37, // Opposit Type In Deawdown Positions Youngest one
XCATBEA_POSITION_SELECT_OPPOSITS_IN_DRAWDOWN_MIN = 38, // Minimum In Drawdown of Opposit Type Positions
XCATBEA_POSITION_SELECT_OPPOSITS_IN_DRAWDOWN_MAX = 39, // Maximum In Drawdown of Opposit Type Positions
};
//
bool IsValid(ENUM_XCATBEA_POSITION_SELECT_TYPES value)
{
return value != XCATBEA_POSITION_SELECT_NONE;
}
//
string ToString(ENUM_XCATBEA_POSITION_SELECT_TYPES value)
{
return EnumToString(value);
}
/**
* Select Specified Position's Related Position(s)
* for Protecting ...
*
* @param selecteds: XPosition instance reference Collection, for Holding Selected Positions ...
* @param positions: XPosition instance reference Collection, All available source Positions ...
* @param forType: ENUM_X_POSITION_TYPES member, Spcified Position Type to Select for it ...
* @param selectType: ENUM_XCATBEA_POSITION_SELECT_TYPES member, Specified Positions Selecting Senario ...
*
* @return ( bool )
*/
bool SelectPosition(
XPosition &selecteds[],
XPosition &positions[],
ENUM_X_POSITION_TYPES forType,
ENUM_XCATBEA_POSITION_SELECT_TYPES selectType //
)
{
//
bool result = false;
//
// Normalize Args ...
Clean(selecteds);
//
// Validate Args ...
result =
IsValid(forType) &&
HasChild(positions) &&
IsValid(selectType);
if (!result)
{
return result;
}
//
// Extract Separate Type of Positions ...
//
int idx = -1;
bool has = false;
XPosition iPosition;
//
bool isLong = IsLong(forType);
bool isShort = IsShort(forType);
int count = ArraySize(positions);
//
XPosition samePositions[];
XPosition oppositPositions[];
XPosition inProfitPositions[];
XPosition inDrawdownPositions[];
XPosition sameInProfitPositions[];
XPosition sameInDrawdownPositions[];
XPosition oppositInProfitPositions[];
XPosition oppositInDrawdownPositions[];
//
for (int i = 0; i < count; i++)
{
//
// Select Indexed Position ...
iPosition = positions[i];
//
bool isIPosLong = IsLong(iPosition.type);
bool isIPosShort = IsShort(iPosition.type);
//
// Select if Same Type ...
bool isSame =
(isLong && isIPosLong) ||
(isShort && isIPosShort);
if (isSame)
{
//
AddRef(
iPosition,
samePositions //
);
}
//
// Select if Opposit Type ...
bool isOpposit =
(isLong && isIPosShort) ||
(isShort && isIPosLong);
if (isOpposit)
{
//
AddRef(
iPosition,
oppositPositions //
);
}
//
iPosition.Clean();
}
//
// Filling Other Requirement Collections ...
//
ExtractInProfitPositions(
positions,
inProfitPositions //
);
//
ExtractInProfitPositions(
samePositions,
sameInProfitPositions //
);
//
ExtractInProfitPositions(
oppositPositions,
oppositInProfitPositions //
);
//
ExtractInDrawdownPositions(
positions,
inDrawdownPositions //
);
//
ExtractInDrawdownPositions(
samePositions,
sameInDrawdownPositions //
);
//
ExtractInDrawdownPositions(
oppositPositions,
oppositInDrawdownPositions //
);
//
// Implement Selection Senario ...
switch (selectType)
{
//
case XCATBEA_POSITION_SELECT_ALL:
//
Copy(
positions,
selecteds //
);
break;
//
case XCATBEA_POSITION_SELECT_IN_PROFITS:
//
Copy(
inProfitPositions,
selecteds //
);
break;
//
case XCATBEA_POSITION_SELECT_IN_DRAWDOWNS:
//
Copy(
inDrawdownPositions,
selecteds //
);
break;
//
case XCATBEA_POSITION_SELECT_OLDEST:
//
GetOldest(
iPosition,
positions //
);
if (iPosition.IsValid())
{
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_YOUNGEST:
//
GetYoungest(
iPosition,
positions //
);
if (iPosition.IsValid())
{
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_IN_PROFITS_OLDEST:
//
GetOldest(
iPosition,
inProfitPositions //
);
if (iPosition.IsValid())
{
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_IN_PROFITS_YOUNGEST:
//
GetYoungest(
iPosition,
inProfitPositions //
);
if (iPosition.IsValid())
{
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_IN_PROFITS_MIN:
//
idx = FindMinProfitIndex(inProfitPositions);
if (IsValidIndex(idx))
{
//
iPosition = inProfitPositions[idx];
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_IN_PROFITS_MAX:
//
idx = FindMaxProfitIndex(inProfitPositions);
if (IsValidIndex(idx))
{
//
iPosition = inProfitPositions[idx];
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_IN_DRAWDOWN_OLDEST:
//
GetOldest(
iPosition,
inDrawdownPositions //
);
if (iPosition.IsValid())
{
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_IN_DRAWDOWN_YOUNGEST:
//
GetYoungest(
iPosition,
inDrawdownPositions //
);
if (iPosition.IsValid())
{
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_IN_DRAWDOWN_MIN:
//
idx = FindMinDrawdownIndex(inDrawdownPositions);
if (IsValidIndex(idx))
{
//
iPosition = inDrawdownPositions[idx];
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_IN_DRAWDOWN_MAX:
//
idx = FindMaxDrawdownIndex(inDrawdownPositions);
if (IsValidIndex(idx))
{
//
iPosition = inDrawdownPositions[idx];
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_SAMES:
//
Copy(
samePositions,
selecteds //
);
break;
//
case XCATBEA_POSITION_SELECT_SAMES_OLDEST:
//
GetOldest(
iPosition,
samePositions //
);
if (iPosition.IsValid())
{
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_SAMES_YOUNGEST:
//
GetYoungest(
iPosition,
samePositions //
);
if (iPosition.IsValid())
{
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_OPPOSITS:
//
Copy(
oppositPositions,
selecteds //
);
break;
//
case XCATBEA_POSITION_SELECT_OPPOSIT_OLDEST:
//
GetOldest(
iPosition,
oppositPositions //
);
if (iPosition.IsValid())
{
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_OPPOSIT_YOUNGEST:
//
GetYoungest(
iPosition,
oppositPositions //
);
if (iPosition.IsValid())
{
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_SAME_IN_PROFITS:
//
Copy(
sameInProfitPositions,
selecteds //
);
break;
//
case XCATBEA_POSITION_SELECT_SAME_IN_PROFITS_OLDEST:
//
GetOldest(
iPosition,
sameInProfitPositions //
);
if (iPosition.IsValid())
{
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_SAME_IN_PROFITS_YOUNGEST:
//
GetYoungest(
iPosition,
sameInProfitPositions //
);
if (iPosition.IsValid())
{
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_SAME_IN_PROFITS_MIN:
//
idx = FindMinProfitIndex(sameInProfitPositions);
if (IsValidIndex(idx))
{
//
iPosition = sameInProfitPositions[idx];
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_SAME_IN_PROFITS_MAX:
//
idx = FindMaxProfitIndex(sameInProfitPositions);
if (IsValidIndex(idx))
{
//
iPosition = sameInProfitPositions[idx];
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_OPPOSIT_IN_PROFITS:
//
Copy(
oppositInProfitPositions,
selecteds //
);
break;
//
case XCATBEA_POSITION_SELECT_OPPOSIT_IN_PROFITS_OLDEST:
//
GetOldest(
iPosition,
oppositInProfitPositions //
);
if (iPosition.IsValid())
{
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_OPPOSIT_IN_PROFITS_YOUNGEST:
//
GetYoungest(
iPosition,
oppositInProfitPositions //
);
if (iPosition.IsValid())
{
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_OPPOSIT_IN_PROFITS_MIN:
//
idx = FindMinProfitIndex(oppositInProfitPositions);
if (IsValidIndex(idx))
{
//
iPosition = oppositInProfitPositions[idx];
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_OPPOSIT_IN_PROFITS_MAX:
//
idx = FindMaxProfitIndex(oppositInProfitPositions);
if (IsValidIndex(idx))
{
//
iPosition = oppositInProfitPositions[idx];
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_SAME_IN_DRAWDOWNS:
//
Copy(
sameInDrawdownPositions,
selecteds //
);
break;
//
case XCATBEA_POSITION_SELECT_SAME_IN_DRAWDOWN_OLDEST:
//
GetOldest(
iPosition,
sameInDrawdownPositions //
);
if (iPosition.IsValid())
{
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_SAME_IN_DRAWDOWN_YOUNGEST:
//
GetYoungest(
iPosition,
sameInDrawdownPositions //
);
if (iPosition.IsValid())
{
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_SAME_IN_DRAWDOWN_MIN:
//
idx = FindMinDrawdownIndex(sameInDrawdownPositions);
if (IsValidIndex(idx))
{
//
iPosition = sameInDrawdownPositions[idx];
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_SAME_IN_DRAWDOWN_MAX:
//
idx = FindMaxDrawdownIndex(sameInDrawdownPositions);
if (IsValidIndex(idx))
{
//
iPosition = sameInDrawdownPositions[idx];
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_OPPOSITS_IN_DRAWDOWNS:
//
Copy(
oppositInDrawdownPositions,
selecteds //
);
break;
//
case XCATBEA_POSITION_SELECT_OPPOSITS_IN_DRAWDOWN_OLDEST:
//
GetOldest(
iPosition,
oppositInDrawdownPositions //
);
if (iPosition.IsValid())
{
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_OPPOSITS_IN_DRAWDOWN_YOUNGEST:
//
GetYoungest(
iPosition,
oppositInDrawdownPositions //
);
if (iPosition.IsValid())
{
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_OPPOSITS_IN_DRAWDOWN_MIN:
//
idx = FindMinDrawdownIndex(oppositInDrawdownPositions);
if (IsValidIndex(idx))
{
//
iPosition = oppositInDrawdownPositions[idx];
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
case XCATBEA_POSITION_SELECT_OPPOSITS_IN_DRAWDOWN_MAX:
//
idx = FindMaxDrawdownIndex(oppositInDrawdownPositions);
if (IsValidIndex(idx))
{
//
iPosition = oppositInDrawdownPositions[idx];
//
AddRef(
iPosition,
selecteds //
);
}
iPosition.Clean();
break;
//
}
//
// Validate Result ...
result = HasChild(selecteds);
//
// Cleanup Resources ...
//
if (!result)
{
Clean(selecteds);
}
//
Clean(samePositions);
Clean(oppositPositions);
Clean(inProfitPositions);
Clean(inDrawdownPositions);
Clean(sameInProfitPositions);
Clean(sameInDrawdownPositions);
Clean(oppositInProfitPositions);
Clean(oppositInDrawdownPositions);
//
return result;
}
//
struct XCATBEASymbolInfo
{
//
// Properties ...
//
string symbol; // Trading Symbol
//
int longs; // All Long Trades
int shorts; // All Short Trades
//
int trades; // All Trades
//
int losses; // All Loosing Trades
int profits; // All Winning Trades
//
datetime managedStart; // Managed Start Time
//
int managedSLs; // Managed SL(s)
int managedTPs; // Managed TP(s)
int managedTrades; // Managed Trades
//
double managedBalance; // Managed Start Balance
double managedProfits; // Managed Profit(s)
//
// Constructor ...
XCATBEASymbolInfo()
{
Clean();
}
//
// Tools ...
//
// Cleanup ...
void Clean()
{
//
symbol = NULL;
//
longs = 0;
shorts = 0;
//
trades = 0;
//
losses = 0;
profits = 0;
//
managedStart = NULL;
//
managedSLs = 0;
managedTPs = 0;
managedTrades = 0;
//
managedBalance = 0;
managedProfits = 0;
//
ZeroMemory(this);
}
//
// Validate ...
bool IsValid()
{
//
bool result = false;
//
result = IsValid(symbol);
//
return result;
}
//
bool IsSameAs(XCATBEASymbolInfo &item)
{
//
bool result = false;
//
result = IsValid() &&
item.IsValid() &&
symbol == item.symbol;
//
return result;
}
//
string GetRestrictionDescription(
ENUM_XCATBEA_TRADE_RESTRICTION_PERIOD period //
)
{
//
string result = NULL;
//
if (!IsValid() &&
period != XCATBEA_TRADE_RESTRICATION_NONE)
{
return result;
}
//
result +=
"-------------------" + "\n" +
"Restrictions: " + "\n" +
"-------------------" + "\n" +
"Symbol: " + ToString(symbol) + "\n" +
"Period: " + ToString(period) + "\n" +
"Start: " + ToFormatString(managedStart) + "\n" +
"Balance: " + ToString(managedBalance) + "\n" +
"-------------------" + "\n" +
"Trades: " + ToString(managedTrades) + "\n" +
"SL: " + ToString(managedSLs) + "\n" +
"TP: " + ToString(managedTPs) + "\n" +
"Profit: " + ToString(managedProfits) + "\n" +
"";
//
return result;
}
};
//
struct XCATBEATradeSession
{
//
// Properties ...
string start; // Session Start Time (hh:mm)
string end; // Session End Time (hh:mm)
string name; // Session Name
//
// Constructor ...
XCATBEATradeSession()
{
Clean();
}
//
// Tools ...
//
// Cleanup ...
void Clean()
{
//
end = NULL;
name = NULL;
start = NULL;
//
ZeroMemory(this);
}
//
// Validate ...
bool IsValid()
{
//
bool result = false;
//
result = IsValid(start) &&
IsValid(end);
if (!result)
{
return result;
}
//
return result;
}
//
// Check Session is Active or Not ...
bool IsActive(datetime time = NULL)
{
//
bool result = false;
//
time = NormalizeTime(time);
//
result = IsValid();
if (!result)
{
return result;
}
//
result = IsTimeInRange(
time,
start,
end //
);
//
return result;
}
};
struct XCATBEASymbolSession
{
//
// Propeties ...
//
string symbol; // Trading Symbol
XCATBEATradeSession sessions[]; // Trading Sessions
//
// Constructor ...
XCATBEASymbolSession()
{
Clean();
}
//
// Tools ...
//
// Cleanup ...
void Clean()
{
//
symbol = NULL;
Clean(sessions);
//
ZeroMemory(this);
}
//
// Validate ...
bool IsValid()
{
//
bool result = false;
//
result = IsValid(symbol);
//
return result;
}
//
// Check Allow Trade in Active Sessions ...
bool CanTrade(datetime time = NULL)
{
//
bool result = false;
//
// Normalize Args ...
time = NormalizeTime(time);
//
// Validating ...
result = IsValid();
if (!result)
{
return result;
}
//
// if there is not any defined sessions for Symbol ...
// it's allow Trading in all times ...
result = !HasChild(sessions);
if (result)
{
return result;
}
//
// Detect an Active Session ...
int count = ArraySize(sessions);
for (int i = 0; i < count; i++)
{
//
result = sessions[i].IsActive(time);
if (result)
{
break;
}
}
//
return result;
}
//
};
//
struct XCATBEATrade
{
//
// Props ...
double swap;
double profit;
XSignal signal;
ulong positionID;
double commission;
XCATBEAStrategyConditions conditions;
ENUM_XCATBEA_TRADE_FINALIZATION finalize;
//
datetime signaledAt;
datetime executedAt;
datetime finalizedAt;
//
// Constructor ...
XCATBEATrade()
{
Clean();
}
//
// Tools ...
/**
* Cleanup Model ...
*/
void Clean()
{
//
swap = 0;
profit = 0;
signal.Clean();
commission = 0;
positionID = 0;
conditions.Clean();
finalize = XCATBEA_TRADE_FINAL_NONE;
//
signaledAt = NULL;
executedAt = NULL;
finalizedAt = NULL;
//
ZeroMemory(this);
}
/**
* Check Has Signal ...
*
* @return ( bool )
*/
bool HasSignal()
{
//
bool result = false;
//
result = signal.IsValid();
//
return result;
}
/**
* Check Signal Executed or Not ...
*
* @return ( bool )
*/
bool IsExecuted()
{
//
bool result = false;
//
result = positionID > 0;
//
return result;
}
/**
* Check a Trade is Finalized or not ...
*
* @return ( bool )
*/
bool IsFinalized()
{
//
bool result = false;
//
result = HasSignal() &&
IsExecuted() &&
finalize != XCATBEA_TRADE_FINAL_NONE;
//
return result;
}
/**
* Generate Summary Info ...
*
* @return ( string )
*/
string Summary()
{
//
string result = NULL;
//
result =
//
ToString("Swap", swap) +
ToString("Profit", profit) +
ToString("Commission", commission) +
ToString("Finalize", ToString(finalize)) +
ToString("PositionID", positionID) +
ToString("----------------") + "\n" +
ToString("Signaled At", ToFormatString(signaledAt)) +
ToString("Executed At", ToFormatString(executedAt)) +
ToString("Finalized At", ToFormatString(finalizedAt))
//
;
//
return result;
}
/**
* Get Data Collection File Name ...
*
* @return ( string )
*/
string GetFileName()
{
//
string result = NULL;
//
bool hasSignal = HasSignal();
bool isExecuted = IsExecuted();
bool isFinalized = IsFinalized();
if (!hasSignal && !isExecuted && !isFinalized)
{
return result;
}
//
result =
//
signal.symbol + "\\" +
ToString(signal.type) + "\\" +
(profit >= 0 ? "Profit" : "Loss") + "\\" +
ToString(positionID) + "_" +
ToString(signal.period) + "_" +
ToFormatString(signaledAt)
//
;
//
return result;
}
/**
* Converts Model to String Representation ...
*
* @param onlySignals: Boolean, Specified Represent Only Signal or not ...
*
* @return ( string )
*/
string ToString(
bool includeSummary = true,
bool includeSignal = true,
bool includeConditions = true //
)
{
//
string result = NULL;
//
// Generating Model Summary ...
string summary = Summary();
//
// Generating Signal Summary ...
string signalSummary = signal.ToString();
//
// Generating Conditions Summary ...
string conditionsSummary = conditions
.conditions
.GenerateSummary(
false,
true,
true,
false // Ignore False Conditions ...
);
//
if (includeSummary)
{
//
result +=
ToString("----------------") + "\n" +
ToString("Summary: ") + "\n" +
ToString("----------------") + "\n" +
summary + "\n";
}
//
if (includeSignal)
{
//
result +=
ToString("----------------") + "\n" +
ToString("Signal: ") + "\n" +
ToString("----------------") + "\n" +
signalSummary + "\n";
}
//
if (includeConditions)
{
//
result +=
ToString("----------------") + "\n" +
ToString("Conditions: ") + "\n" +
ToString("----------------") + "\n" +
conditionsSummary + "\n";
}
//
return result;
}
string GetConditionsString()
{
//
string result = NULL;
//
double bullishScore = 0;
double bearishScore = 0;
conditions
.conditions
.GenerateScore(
bullishScore,
bearishScore //
);
//
string conditionsStr =
conditions
.conditions
.GenerateSummary(
false,
true, // Only Conditions ...
false,
false // Ignore False Conditions ...
);
string condParts[];
int condPartsCount = SplitContent(
condParts,
conditionsStr,
"\n" //
);
if (IsValidSize(condPartsCount))
{
//
conditionsStr = NULL;
while (HasChild(condParts))
{
//
string iStr = condParts[0];
ArrayRemove(
condParts,
0,
1 //
);
//
bool isLast = !HasChild(condParts);
//
bool isCond = Contains(
"is",
iStr,
false //
);
if (isCond)
{
//
string iParts[];
int iPartsCount = SplitContent(
iParts,
iStr,
":" //
);
if (iPartsCount == 2)
{
//
string iVal = iParts[1];
StringTrimLeft(iVal);
StringTrimRight(iVal);
bool isPassed = ToBoolean(iVal);
conditionsStr += (isPassed ? "" : "!") + "conditions." + iParts[0] + (!isLast ? " &&" : "") + "\n";
}
}
}
Clean(condParts);
}
else
{
conditionsStr = NULL;
}
//
result =
"(" + "\n" +
"\\" + "\\" + " " + ToString("Type", ToString(signal.type)) +
"\\" + "\\" + " " + ToString("Profit", profit) +
"\\" + "\\" + " " + ToString("Finalize", ToString(finalize)) +
"\\" + "\\" + " " + ToString("PositionID", positionID) +
"\\" + "\\" + " " + ToString("----------------") + "\n" +
"\\" + "\\" + " " + ToString("Signaled At", ToFormatString(signaledAt)) +
"\\" + "\\" + " " + ToString("Executed At", ToFormatString(executedAt)) +
"\\" + "\\" + " " + ToString("Finalized At", ToFormatString(finalizedAt)) +
"\\" + "\\" + " " + ToString("----------------") + "\n" +
"\\" + "\\" + " " + ToString("Scores:") + "\n" +
"\\" + "\\" + " " + ToString("Bullish", bullishScore) +
"\\" + "\\" + " " + ToString("Bearish", bearishScore) +
"\\" + "\\" + " " + ToString("----------------") + "\n" +
conditionsStr +
(IsValid(conditionsStr) ? "" : "") +
") && ";
//
return result;
}
};
//
// Implementations ...
class XCXCATBEATradeManager : public XCBase
{
//
// Public ...
public:
//
// Props ...
XCAlert *alert;
XCTrade *trader;
bool drawSignal;
XCPOIDrawer *drawer;
XTimeTracker timeTracker;
XCDataCollector *collector;
//
// Constructors ...
XCXCATBEATradeManager(
XCAlert *_alert,
XCTrade *_trader //
)
{
//
alert = _alert;
trader = _trader;
drawSignal = true;
drawer = new XCPOIDrawer();
//
allowTrade = true;
allowLongs = true;
allowShorts = true;
//
forceCloseAt = NULL;
isForceCloseAtTime = false;
//
maxAllowedTPs = 0;
maxAllowedSLs = 0;
maxAllowedTrades = 0;
restrictionsPeriod = XCATBEA_TRADE_RESTRICATION_NONE;
//
reportTrades = true;
reportSignals = true;
reportProtector = true;
reportAfterTradesBalance = true;
//
SaveTrades(false);
//
collector = new XCDataCollector();
//
// Setting Collector Path ...
string mPath = (IsValid(alert.GetPrefix())
? alert.GetPrefix() + "\\"
: "") +
trader.mAccount.GetCompany();
collector.Path(mPath);
}
//
// De Constructors ...
~XCXCATBEATradeManager()
{
//
Clean(trades);
//
timeTracker.Clean();
//
ZeroMemory(alert);
ZeroMemory(trader);
//
delete drawer;
ZeroMemory(drawer);
//
delete collector;
ZeroMemory(collector);
}
//
// Properties ...
//
bool SaveTrades()
{
return mSaveTrades;
}
//
void SaveTrades(bool value)
{
mSaveTrades = value;
}
//
bool SaveSignals()
{
return mSaveSignals;
}
//
void SaveSignals(bool value)
{
mSaveSignals = value;
}
//
bool SaveWins()
{
return mSaveWins;
}
//
void SaveWins(bool value)
{
mSaveWins = value;
}
//
bool SaveLosts()
{
return mSaveLosts;
}
//
void SaveLosts(bool value)
{
mSaveLosts = value;
}
//
bool SaveRestrictions()
{
return mSaveRestrictions;
}
//
void SaveRestrictions(bool value)
{
mSaveRestrictions = value;
}
//
void SetForceCloseTradesAt(
string _forceCloseAt //
)
{
forceCloseAt = _forceCloseAt;
}
//
void SetTradeSession(
string symbol,
string start,
string end,
string name = NULL //
)
{
//
// Validate Args ...
bool has = IsValid(end) &&
IsValid(start) &&
IsValid(symbol);
if (!has)
{
return;
}
//
// Create Session ...
//
XCATBEATradeSession session;
//
session.end = end;
session.name = name;
session.start = start;
//
int sessionIDX = -1;
has = FindSymbolSession(
sessionIDX,
symbol //
);
//
if (!has)
{
//
// Add New Symbol Session ...
//
XCATBEASymbolSession iSymbolSession;
iSymbolSession.symbol = symbol;
//
AddTradingSession(
session,
iSymbolSession //
);
//
AddRef(
iSymbolSession,
sessions //
);
//
iSymbolSession.Clean();
}
else
{
//
// Update Trading Sessions of Exists Symbol Session ...
AddTradingSession(
session,
sessions[sessionIDX] //
);
}
//
// Cleanup Resources ...
session.Clean();
}
//
void SetTradeReports(
bool _reportTrades,
bool _reportSignals,
bool _reportProtector,
bool _reportRestrictions,
bool _reportAfterTradesBalance //
)
{
//
reportTrades = _reportTrades;
reportSignals = _reportSignals;
reportProtector = _reportProtector;
reportRestrictions = _reportRestrictions;
reportAfterTradesBalance = _reportAfterTradesBalance;
}
//
void SetTradePermissions(
bool _allowTrade,
bool _allowLongs,
bool _allowShorts //
)
{
//
allowTrade = _allowTrade;
allowLongs = _allowLongs;
allowShorts = _allowShorts;
}
//
void SetTradeRestrictions(
ENUM_XCATBEA_TRADE_RESTRICTION_PERIOD _period,
int _maxAllowedTPs,
int _maxAllowedSLs,
int _maxAllowedTrades //
)
{
//
// Normalizing Args ...
_maxAllowedTPs = NormalizeInt(_maxAllowedTPs, 0);
_maxAllowedSLs = NormalizeInt(_maxAllowedSLs, 0);
_maxAllowedTrades = NormalizeInt(_maxAllowedTrades, 0);
//
restrictionsPeriod = _period;
maxAllowedTPs = _maxAllowedTPs;
maxAllowedSLs = _maxAllowedSLs;
maxAllowedTrades = _maxAllowedTrades;
}
//
// Tools ...
/**
* Do All Position Managing Senaros ...
*/
void Manage()
{
//
// Handle Restrictions ...
HandleRestrictions();
//
// Check Contains Trades for Managing ...
bool has = HasChild(trades);
if (!has)
{
return;
}
//
// Update Required Infos of Trades ...
int count = ArraySize(trades);
for (int i = 0; i < count; i++)
{
//
has = trades[i].IsExecuted() &&
!trades[i].IsFinalized();
if (!has)
{
continue;
}
//
XPosition iPosition;
has = trader.GetPosition(
trades[i].positionID,
iPosition //
);
if (!has)
{
continue;
}
//
// Update Trade Data ...
trades[i].swap = iPosition.swap;
trades[i].profit = iPosition.profit;
}
//
// Do Trade Protection ...
Protect();
}
/**
* Do All Position Protection Here ...
*/
void Protect()
{
//
string prefix = "Protector: ";
int targetDistance = 5;
//
bool has = HasChild(trades);
if (!has)
{
return;
}
//
XPosition ownPosition[];
XPosition ownLongPosition[];
XPosition ownShortPosition[];
//
int count = ArraySize(trades);
for (int i = 0; i < count; i++)
{
//
has =
trades[i].IsExecuted() &&
!trades[i].IsFinalized();
if (!has)
{
continue;
}
//
XPosition iPosition;
has = trader.GetPosition(
trades[i].positionID,
iPosition //
);
if (!has)
{
continue;
}
//
AddRef(
iPosition,
ownPosition //
);
//
if (IsLong(iPosition.type))
{
//
AddRef(
iPosition,
ownLongPosition //
);
}
else
{
//
AddRef(
iPosition,
ownShortPosition //
);
}
}
//
has = HasChild(ownPosition);
if (!has)
{
//
Clean(ownPosition);
Clean(ownLongPosition);
Clean(ownShortPosition);
//
return;
}
//
double swapSum = 0;
double profitSum = 0;
double commissionSum = 0;
//
// Calculate Required Data On Collection ...
count = ArraySize(ownPosition);
for (int i = 0; i < count; i++)
{
//
XPosition iPosition = ownPosition[i];
//
swapSum += iPosition.swap;
profitSum += iPosition.profit;
commissionSum += iPosition.commission;
}
//
// Do Collection Protectiong ...
//
// Check Force Close ...
if (IsValid(forceCloseAt))
{
//
datetime forceCloseTime = ParseDateTimeFromTimeString(forceCloseAt);
bool canForceClose = IsTimeInRange(
TimeCurrent(),
forceCloseTime //
) &&
!isForceCloseAtTime;
if (canForceClose)
{
//
isForceCloseAtTime = HandleForceCloseTrades(ownPosition);
//
// Prevent Moving Forward ...
return;
}
}
//
// Do Signle Protections ...
for (int i = 0; i < count; i++)
{
//
// Select Position ...
XPosition iPosition = ownPosition[i];
int idx = -1;
has = HasTrade(
idx,
iPosition.ticket //
);
if (!has)
{
continue;
}
//
bool isLong = IsLong(iPosition.type);
double points = GetPoints(iPosition.symbol);
//
// Handle RF On Targets ...
if (iPosition.profit > 0)
{
//
// Handle Risk Free On Targets ...
XTarget targets[];
Copy(
trades[idx].signal.targets,
targets //
);
int targetsCount = ArraySize(targets);
has = IsValidSize(targetsCount);
if (has)
{
//
for (int j = 0; j < targetsCount; j++)
{
//
XTarget jTarget = targets[j];
//
int appliedTargetIDX = -1;
//
// Check Target is Applied Before or Not ...
has =
!trades[idx].signal.isTargetApplied
? true
: trades[idx].signal.appliedTargetIDX < j;
if (!has)
{
continue;
}
//
// Check Traget Validation ...
has =
iPosition.sl == 0
? true
: isLong
? iPosition.sl < jTarget.target
: iPosition.sl > jTarget.target;
if (!has)
{
continue;
}
//
double targetDelta = isLong
? jTarget.target + (targetDistance * points)
: jTarget.target - (targetDistance * points);
//
// Can Risk Free ...
bool canRF =
jTarget.doRF &&
jTarget.target > 0 &&
(isLong
? jTarget.target > iPosition.entry
: jTarget.target < iPosition.entry) &&
(isLong
? iPosition.price > targetDelta
: iPosition.price < targetDelta);
//
// Can Partial Close ...
bool canPC =
jTarget.volumeMultiplier > 0 &&
jTarget.target > 0 &&
(isLong
? jTarget.target > iPosition.entry
: jTarget.target < iPosition.entry) &&
(isLong
? iPosition.price > targetDelta
: iPosition.price < targetDelta);
bool canRFPC = canRF ||
canPC;
if (canRFPC)
{
//
// Handle Risk Free ...
bool isRFDone = false;
if (canRF)
{
//
double tp = iPosition.tp;
double sl = jTarget.target;
string comment = "RF On Target ...";
isRFDone = trader.Modify(
iPosition.ticket,
sl,
tp,
comment //
);
}
//
// Handle Partail Close ...
bool isPCDone = false;
if (canPC)
{
//
double volume = jTarget.volumeMultiplier * iPosition.volume;
volume = NormalizeVolume(volume, iPosition.symbol);
string comment = "RF On Target ...";
isPCDone = trader.ClosePartial(
iPosition.ticket,
volume,
comment //
);
}
//
// Handle Report Action ...
bool isRFPCDone = isRFDone ||
isPCDone;
if (isRFPCDone)
{
//
trades[idx].signal.appliedTargetIDX = j;
trades[idx].signal.isTargetApplied = true;
//
string message = prefix +
ToString(iPosition.type) +
" Position: " +
ToString(iPosition.ticket) +
(isRFDone ? " RF" : "") +
(isPCDone ? " PC" : "") +
" On Traget: " + ToString(jTarget.target) +
" Successfully ...";
HandleReportProtector(message);
}
}
}
}
}
}
}
/**
* Check Specified Symbol is Active for
* Analysing or Open Trades ...
*/
bool IsActiveSession(string symbol)
{
//
bool result = false;
//
// Validate Args ...
result = IsValid(symbol);
if (!result)
{
return result;
}
//
// Check Symbol Session Exists or not ...
int symbolSessionIDX = -1;
bool isSymbolSessionExists = FindSymbolSession(
symbolSessionIDX,
symbol //
);
//
// Chack Trade Session Validating ...
if (isSymbolSessionExists)
{
result = sessions[symbolSessionIDX].CanTrade();
}
//
return result;
}
/**
* Check Signal Execution Conditions ...
*
* @param signal: XSignal instance reference ...
* @param executionResult: ENUM_X_SIGNAL_EXECUTION_RESULT member reference ...
*
* @return ( bool )
*/
bool CheckSignal(
XSignal &signal,
ENUM_X_SIGNAL_EXECUTION_RESULT &executionResult //
)
{
//
bool result = false;
//
// Cleanup ...
executionResult = X_SIGNAL_EXECUTION_UNKNOWN;
//
// Validate Signal ...
result = signal.IsValid();
if (!result)
{
return result;
}
//
// Reporting Signal ...
if (reportSignals)
{
//
string message = signal.GetMessage("Provided");
alert.SendAlert(message);
}
//
SaveSignal(signal);
//
// Check Trade Permission ...
if (!allowTrade)
{
//
result = false;
executionResult = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED;
//
return result;
}
//
bool isLong = IsLong(signal.type);
bool isShort = IsShort(signal.type);
//
bool isLongAndAllowed =
isLong &&
allowLongs;
//
bool isShortAndAllowed =
isShort &&
allowShorts;
//
result = isLongAndAllowed ||
isShortAndAllowed;
if (!result)
{
//
executionResult = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED;
//
return result;
}
//
// Check Symbol Info Exists or not ...
int symbolInfoIDX = -1;
bool isSymbolInfoExists = FindSymbolIndex(
symbolInfoIDX,
signal.symbol //
);
//
// Check Symbol Session Exists or not ...
int symbolSessionIDX = -1;
bool isSymbolSessionExists = FindSymbolSession(
symbolSessionIDX,
signal.symbol //
);
//
// Chack Trade Session Validating ...
if (isSymbolSessionExists)
{
//
result = sessions[symbolSessionIDX].CanTrade();
if (!result)
{
//
executionResult = X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED;
//
return result;
}
}
//
// Check Trade Permissions Based on SL(s) Count ...
bool hasRestrictions = restrictionsPeriod != XCATBEA_TRADE_RESTRICATION_NONE;
if (hasRestrictions)
{
//
// Only Can Check Restrictions when
// Symbol Info Exists ...
if (isSymbolInfoExists)
{
//
bool isTPAllowed = maxAllowedTPs == 0
? true
: symbols[symbolInfoIDX].managedTPs < maxAllowedTPs;
bool isSLAllowed = maxAllowedSLs == 0
? true
: symbols[symbolInfoIDX].managedSLs < maxAllowedSLs;
bool isTradeAllowed = maxAllowedTrades == 0
? true
: symbols[symbolInfoIDX].managedTrades < maxAllowedTrades;
//
result = isTPAllowed &&
isSLAllowed &&
isTradeAllowed;
}
//
// Report Error ...
if (!result)
{
//
executionResult = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED;
//
return result;
}
}
//
return result;
}
/**
* Execute Specified Signal ...
*
* @param signal: XSignal instance reference ...
* @param conditions: XCATBEAStrategyConditions instance reference ...
*
* @return ( bool )
*/
bool Execute(
XSignal &signal,
XCATBEAStrategyConditions &conditions //
)
{
//
bool result = false;
//
result = signal.IsValid();
if (!result)
{
return result;
}
//
int idx = -1;
bool isExists = HasTrade(
idx,
signal //
);
result = !isExists;
if (!result)
{
return result;
}
//
ENUM_X_SIGNAL_EXECUTION_RESULT executionResult;
//
// Checking Signal For Execution ...
result = CheckSignal(
signal,
executionResult //
);
if (result)
{
//
result = trader.ExecuteSignal(
signal,
executionResult //
);
}
//
// Alert Signal Execution ...
if (reportTrades)
{
//
string executionMessage = ToString(executionResult);
//
string message = NULL;
if (result)
{
message = signal.GetMessage("Executed");
}
else
{
message = signal.GetMessage("Failed due (" + executionMessage + ")");
}
//
alert.SendAlert(message);
}
//
if (result)
{
//
// Draw Signal ...
if (drawSignal)
{
//
XCSignalObject *iObj;
isExists = drawer.DrawSignal(
signal,
iObj //
);
//
if (isExists)
{
//
mObjects.Add(iObj);
ZeroMemory(iObj);
}
}
//
// Create Symbol Info Struct ...
XCATBEASymbolInfo iSymbolInfo;
//
iSymbolInfo.trades = 1;
iSymbolInfo.managedTrades = 1;
iSymbolInfo.symbol = signal.symbol;
//
bool isLong = IsLong(signal.type);
if (isLong)
{
iSymbolInfo.longs = 1;
}
else
{
iSymbolInfo.shorts = 1;
}
//
// Fill Balance for Restrications ...
bool hasRestrictions = HasRestrictions();
if (hasRestrictions)
{
//
// Read Balance ...
double balance = trader.mAccount.GetBalance();
iSymbolInfo.managedBalance = balance;
iSymbolInfo.managedStart = TimeCurrent();
}
//
AddOrUpdateSymbolInfo(iSymbolInfo);
//
// Create Trade Struct ...
XCATBEATrade iTrade;
//
ulong positionID = trader.GetLastOpenPositionTicket();
double commission = trader.GetPositionCommission(positionID);
//
iTrade.signal = signal;
iTrade.conditions = conditions;
iTrade.positionID = positionID;
iTrade.commission = commission;
iTrade.signaledAt = signal.time;
iTrade.executedAt = TimeCurrent();
//
AddRef(
iTrade,
trades //
);
}
//
return result;
}
/**
* Retrieve Specified Positions ...
*
* @param positions: XPosition instance Reference Array, which holds Founded Positions ...
* @param symbol: string, Specified Symbol Name ...
* @param provider: string, Specified Provider Name ...
* @param period: ENUM_TIMEFRAMES, Specified Period ...
*
* @return ( int )
*/
int GetPositions(
XPosition &positions[],
string symbol,
string provider,
ENUM_TIMEFRAMES period //
)
{
//
int result = 0;
//
Clean(positions);
//
bool has =
IsValid(symbol) &&
IsValid(period) &&
IsValid(provider);
if (!has)
{
return result;
}
//
result = trader.GetPositions(
positions,
symbol,
provider,
period,
NULL, // All Types ...
true, // Filter By Magic ...
true // Force Clean ...
);
//
result = ArraySize(positions);
//
return result;
}
/**
* Handle Position Take Profit ...
*
* @param deal: XDeal instance reference ...
*/
void HandleTP(const XDeal &deal)
{
//
// Check Ticket Exists or not ...
int idx = -1;
bool isExists = HasTrade(
idx,
deal.positionId //
);
if (!isExists)
{
return;
}
//
// Apply Required Data ...
trades[idx].swap = deal.swap;
trades[idx].profit = deal.profit;
trades[idx].finalizedAt = TimeCurrent();
trades[idx].finalize = XCATBEA_TRADE_FINAL_TP;
//
// Save Trade ...
SaveWin(trades[idx]);
SaveTrade(trades[idx]);
//
// Handle Balance Reporting ...
string prefix = "TP: " + ToString(trades[idx].profit);
HandleReportBalance(prefix);
//
// Handle Symbol Info ...
//
XCATBEASymbolInfo iSymbolInfo;
//
iSymbolInfo.profits = 1;
iSymbolInfo.managedTPs = 1;
iSymbolInfo.symbol = trades[idx].signal.symbol;
iSymbolInfo.managedProfits = trades[idx].profit;
//
AddOrUpdateSymbolInfo(iSymbolInfo);
//
RemoveTrade(idx);
}
/**
* Handle Position Stop Loss ...
*
* @param deal: XDeal instance reference ...
*/
void HandleSL(const XDeal &deal)
{
//
// Check Ticket Exists or not ...
int idx = -1;
bool isExists = HasTrade(
idx,
deal.positionId //
);
if (!isExists)
{
return;
}
//
// Apply Required Data ...
trades[idx].swap = deal.swap;
trades[idx].profit = deal.profit;
trades[idx].finalizedAt = TimeCurrent();
trades[idx].finalize = XCATBEA_TRADE_FINAL_SL;
//
// Save Trade ...
SaveTrade(trades[idx]);
//
// Handle Balance Reporting ...
string prefix = "SL: " + ToString(trades[idx].profit);
HandleReportBalance(prefix);
//
// Handle Symbol Info ...
//
bool isInProfit = trades[idx].profit > 0;
if (isInProfit)
{
SaveWin(trades[idx]);
}
else
{
SaveLost(trades[idx]);
}
//
XCATBEASymbolInfo iSymbolInfo;
//
if (isInProfit)
{
//
iSymbolInfo.profits = 1;
iSymbolInfo.managedTPs = 1;
}
else
{
//
iSymbolInfo.losses = 1;
iSymbolInfo.managedSLs = 1;
}
iSymbolInfo.symbol = trades[idx].signal.symbol;
iSymbolInfo.managedProfits = trades[idx].profit;
//
AddOrUpdateSymbolInfo(iSymbolInfo);
//
RemoveTrade(idx);
}
/**
* Handle Position Force Close ...
*
* @param deal: XDeal instance reference ...
*/
void HandleForceClose(const XPosition &position)
{
//
// Check Ticket Exists or not ...
int idx = -1;
bool isExists = HasTrade(
idx,
position.ticket //
);
if (!isExists)
{
return;
}
//
bool isInProfit = position.profit > 0;
//
// Apply Required Data ...
trades[idx].swap = position.swap;
trades[idx].profit = position.profit;
trades[idx].finalizedAt = TimeCurrent();
trades[idx].commission = position.commission;
trades[idx].finalize = isInProfit
? XCATBEA_TRADE_FINAL_CLOSE_IN_PROFIT
: XCATBEA_TRADE_FINAL_CLOSE_IN_LOSE;
//
// Save Trade ...
SaveTrade(trades[idx]);
if (isInProfit)
{
SaveWin(trades[idx]);
}
else
{
SaveLost(trades[idx]);
}
//
// Handle Balance Reporting ...
string prefix = "Force Close " +
(isInProfit
? "Profit"
: "Loss") +
": " +
ToString(trades[idx].profit);
HandleReportBalance(prefix);
//
// Handle Symbol Info ...
//
XCATBEASymbolInfo iSymbolInfo;
//
if (isInProfit)
{
//
iSymbolInfo.profits = 1;
iSymbolInfo.managedTPs = 1;
}
else
{
//
iSymbolInfo.losses = 1;
iSymbolInfo.managedSLs = 1;
}
iSymbolInfo.symbol = trades[idx].signal.symbol;
iSymbolInfo.managedProfits = trades[idx].profit;
//
AddOrUpdateSymbolInfo(iSymbolInfo);
//
RemoveTrade(idx);
}
/**
* Handle Position Partially Closed Event ...
*
* @param ticket: ULONG ...
* @param profit: double ...
* @param comment: string ...
*/
void HandlePartiallyClosed(
const ulong ticket,
const double profit,
const string comment //
)
{
//
// Handle Balance Reporting ...
string prefix = "Partially Closed: " + ToString(ticket);
//
// Handle Balance Reporting ...
HandleReportBalance(prefix);
}
/**
* Handle Force Close Trades ...
*/
bool HandleForceCloseTrades(
XPosition &positions[] //
)
{
//
bool result = false;
//
result = HasChild(positions);
if (!result)
{
return result;
}
//
string prefix = "Protector: ";
string comment = "Force Close ...";
//
int closedsCount = trader.Close(
positions,
comment //
);
result = IsValidSize(closedsCount);
if (result)
{
//
string message = prefix + "Force Close (" + ToString(closedsCount) + ") Trades at Specified Time ...";
HandleReportProtector(message);
}
//
return result;
}
//
// TODO: Complete this ...
void HandleGuard()
{
}
/**
* Find Executed Trade by Providing Position Ticket ...
*
* @param index: int reference, holding founded item index ...
* @param ticket: ulong, Specified Position Ticket ...
*
* @return ( bool )
*/
bool HasTrade(
int &index,
ulong ticket //
)
{
//
bool result = false;
//
index = -1;
//
result =
ticket > 0 &&
HasChild(trades);
if (!result)
{
return result;
}
//
int count = ArraySize(trades);
for (int i = 0; i < count; i++)
{
//
XCATBEATrade iTrade = trades[i];
//
result =
iTrade.HasSignal() &&
iTrade.IsExecuted() &&
iTrade.positionID == ticket;
if (result)
{
//
index = i;
//
iTrade.Clean();
break;
}
//
iTrade.Clean();
}
//
result = IsValidIndex(index);
//
return result;
}
/**
* Find Trade Item By Signal ...
*
* @param index: int reference, holding founded item index ...
*
* @return ( bool )
*/
bool HasTrade(
int &index,
XSignal &signal //
)
{
//
bool result = false;
//
index = -1;
//
result =
signal.IsValid() &&
HasChild(trades);
if (!result)
{
return result;
}
//
int count = ArraySize(trades);
for (int i = 0; i < count; i++)
{
//
XCATBEATrade iTrade = trades[i];
//
result =
iTrade.HasSignal() &&
iTrade.signal.IsSameAs(signal);
if (result)
{
//
index = i;
//
iTrade.Clean();
break;
}
//
iTrade.Clean();
}
//
result = IsValidIndex(index);
//
return result;
}
/**
* Remove a Trade From List ...
*
* @param index: int ...
*/
void RemoveTrade(int index)
{
//
bool has =
HasChild(trades) &&
IsValidIndex(index) &&
index < ArraySize(trades);
if (!has)
{
return;
}
//
ArrayRemove(
trades,
index,
1 //
);
}
//
// Protected ...
protected:
//
// Tools ...
//
string GetTradeFilePath(XCATBEATrade &trade)
{
//
string fileName = trade.GetFileName();
//
return GetTradeFilePath(fileName);
}
//
string GetTradeFilePath(string fileName)
{
//
string result = NULL;
//
result = collector
.GetFilePath("Trades" + "\\" + fileName);
//
return result;
}
//
string GetSignalFilePath(string fileName)
{
//
string result = NULL;
//
result = collector
.GetFilePath("Signals" + "\\" + fileName);
//
return result;
}
//
string GetWinsFilePath(XCATBEATrade &trade)
{
//
string result = NULL;
//
result = collector
.GetFilePath("Conditions" + "\\" +
trade.signal.symbol + "\\" +
ToString(trade.signal.period) + "_wins");
//
return result;
}
//
string GetLostsFilePath(XCATBEATrade &trade)
{
//
string result = NULL;
//
result = collector
.GetFilePath("Conditions" + "\\" +
trade.signal.symbol + "\\" +
ToString(trade.signal.period) + "_losts");
//
return result;
}
//
string GetRestrictionsFilePath(string symbol)
{
//
string result = NULL;
//
if (!IsValid(symbol))
{
return result;
}
//
result = collector
.GetFilePath("Restrictions" + "\\" + symbol);
//
return result;
}
//
void HandleReportBalance(string prefix = NULL)
{
//
if (!reportAfterTradesBalance)
{
return;
}
//
double balance = trader.mAccount.GetBalance();
string currency = trader.mAccount.GetCurrency();
//
string message =
(IsValid(prefix)
? prefix + " | "
: "") +
"Account Balance: " + ToString(balance) + currency;
alert.SendAlert(message);
}
//
void HandleReportProtector(string message = NULL)
{
//
if (!reportProtector)
{
return;
}
//
alert.SendAlert(message);
}
//
// Save Trades ...
bool SaveTrade(
XCATBEATrade &trade,
bool includeSummary = true,
bool includeSignal = true,
bool includeConditions = true //
)
{
//
bool result = false;
//
if (!mSaveTrades)
{
return result;
}
//
string filePath = GetTradeFilePath(trade);
result = IsValid(filePath);
if (!result)
{
return result;
}
//
string content = trade.ToString(
includeSummary,
includeSignal,
includeConditions //
);
//
result = collector.Save(
filePath,
content //
);
//
return result;
}
//
// Save Signals ...
bool SaveSignal(XSignal &signal)
{
//
bool result = false;
//
// Check Signal Save is Enabled ...
if (!mSaveSignals)
{
return result;
}
//
// Check Signal Validation ...
if (!signal.IsValid())
{
return result;
}
//
// Retrieve Signal File Name ...
string signalFileName = signal.GetFileName();
result = IsValid(signalFileName);
if (!result)
{
return result;
}
//
// Retriev and Validate File Name ...
string filePath = GetSignalFilePath(signalFileName);
result = IsValid(filePath);
if (!result)
{
return result;
}
//
// Generate Content ...
string content = "";
content +=
ToString("----------------") + "\n" +
ToString("Signal: ") + "\n" +
ToString("----------------") + "\n" +
signal.ToString() + "\n";
content +=
ToString("----------------") + "\n" +
ToString("Conditions: ") + "\n" +
ToString("----------------") + "\n" +
signal.conditions + "\n";
//
// Save Content to File ...
result = collector.Save(
filePath,
content //
);
//
// Return Result ...
return result;
}
//
bool SaveWin(XCATBEATrade &trade)
{
//
bool result = false;
//
if (!mSaveWins)
{
return result;
}
//
string filePath = GetWinsFilePath(trade);
result = IsValid(filePath);
if (!result)
{
return result;
}
//
// Preparing Conditions Content ...
string content = trade.GetConditionsString();
//
result = collector.Append(
filePath,
content //
);
//
return result;
}
//
bool SaveLost(XCATBEATrade &trade)
{
//
bool result = false;
//
if (!mSaveLosts)
{
return result;
}
//
string filePath = GetLostsFilePath(trade);
result = IsValid(filePath);
if (!result)
{
return result;
}
//
// Preparing Conditions Content ...
string content = trade.GetConditionsString();
//
result = collector.Append(
filePath,
content //
);
//
return result;
}
//
bool SaveRestrictions(XCATBEASymbolInfo &info)
{
//
bool result = false;
//
if (!mSaveRestrictions)
{
return result;
}
//
result = info.IsValid();
if (!result)
{
return result;
}
//
string filePath = GetRestrictionsFilePath(info.symbol);
result = IsValid(filePath);
if (!result)
{
return result;
}
//
string content = info.GetRestrictionDescription(restrictionsPeriod);
//
result = collector.Append(
filePath,
content //
);
//
return result;
}
//
// Symbol Info ...
//
bool FindSymbolIndex(
int &index,
XCATBEASymbolInfo &item //
)
{
//
bool result = false;
//
index = -1;
//
result = item.IsValid();
if (!result)
{
return result;
}
//
result = HasChild(symbols);
if (!result)
{
return result;
}
//
index = FindIndex(
item,
symbols //
);
//
result = IsValidIndex(index);
//
return result;
}
//
bool FindSymbolIndex(
int &index,
string symbol //
)
{
//
bool result = false;
//
index = -1;
//
result = IsValid(symbol) &&
HasChild(symbols);
if (!result)
{
return result;
}
//
int count = ArraySize(symbols);
for (int i = 0; i < count; i++)
{
//
result = symbols[i].symbol == symbol;
if (result)
{
//
index = i;
break;
}
}
//
result = IsValidIndex(index);
//
return result;
}
//
void AddOrUpdateSymbolInfo(XCATBEASymbolInfo &item)
{
//
bool has = item.IsValid();
if (!has)
{
return;
}
//
int index = -1;
bool isExists = FindSymbolIndex(
index,
item //
);
if (!isExists)
{
//
AddRef(
item,
symbols //
);
}
else
{
//
symbols[index].longs += item.longs;
symbols[index].shorts += item.shorts;
symbols[index].trades += item.trades;
symbols[index].losses += item.losses;
symbols[index].profits += item.profits;
symbols[index].managedSLs += item.managedSLs;
symbols[index].managedTPs += item.managedTPs;
symbols[index].managedTrades += item.managedTrades;
symbols[index].managedProfits += item.managedProfits;
//
// Handle Remove on Managed SL based On Managed TP ...
if (item.managedTPs > 0)
{
//
symbols[index].managedSLs -= item.managedTPs;
if (symbols[index].managedSLs < 0)
{
symbols[index].managedSLs = 0;
}
}
//
// Handle Remove on Managed TP based On Managed SL ...
if (item.managedSLs > 0)
{
//
symbols[index].managedTPs -= item.managedSLs;
if (symbols[index].managedTPs < 0)
{
symbols[index].managedTPs = 0;
}
}
}
}
//
void ResetSymbolsRestrictions()
{
//
bool has = HasChild(symbols);
if (has)
{
//
string prefix = "Protector: ";
//
datetime start = TimeCurrent();
double balance = trader.mAccount.GetBalance();
bool hasRestrictions = HasRestrictions();
if (!hasRestrictions)
{
//
balance = 0;
start = NULL;
}
//
int count = ArraySize(symbols);
for (int i = 0; i < count; i++)
{
//
XCATBEASymbolInfo iInfo = symbols[i];
if (reportRestrictions)
{
//
string message = iInfo.GetRestrictionDescription(restrictionsPeriod);
alert.SendAlert(message);
}
SaveRestrictions(iInfo);
//
symbols[i].managedSLs = 0;
symbols[i].managedTPs = 0;
symbols[i].managedTrades = 0;
symbols[i].managedProfits = 0;
symbols[i].managedStart = start;
symbols[i].managedBalance = balance;
//
iInfo.Clean();
}
//
string message = prefix + "Reset Symbols Restrictions";
HandleReportProtector(message);
}
}
//
void HandleRestrictions()
{
//
bool isNewDay = timeTracker.IsNewDay();
bool isNewHour = timeTracker.IsNewHour();
bool isNewWeek = timeTracker.IsNewWeek();
bool isNewMonth = timeTracker.IsNewMonth();
//
// Reset Force Closed Flag on new Day Starts ...
if (isNewDay)
{
isForceCloseAtTime = false;
}
//
bool canResetRestrictions =
(
//
// Hourly ...
(isNewHour &&
restrictionsPeriod == XCATBEA_TRADE_RESTRICATION_HOURLY)
//
||
//
// Daily ...
(isNewDay &&
restrictionsPeriod == XCATBEA_TRADE_RESTRICATION_DAILY)
//
||
//
// Weekly ...
(isNewWeek &&
restrictionsPeriod == XCATBEA_TRADE_RESTRICATION_WEEKLY)
//
||
//
// Monthly ...
(isNewMonth &&
restrictionsPeriod == XCATBEA_TRADE_RESTRICATION_MONTHLY)
//
)
//
;
if (canResetRestrictions)
{
ResetSymbolsRestrictions();
}
}
//
// Symbol Session ...
//
bool FindSymbolSession(
int &index,
string symbol //
)
{
//
bool result = false;
//
index = -1;
//
result = IsValid(symbol) &&
HasChild(sessions);
if (!result)
{
return result;
}
//
int count = ArraySize(sessions);
for (int i = 0; i < count; i++)
{
//
result = sessions[i].symbol == symbol;
if (result)
{
//
index = i;
break;
}
}
//
result = IsValidIndex(index);
//
return result;
}
//
void AddTradingSession(
XCATBEATradeSession &session,
XCATBEASymbolSession &symbolSession //
)
{
//
bool has = session.IsValid() &&
symbolSession.IsValid();
if (!has)
{
return;
}
//
// Check Session Exists in Symbol Session ...
bool isExists = false;
if (HasChild(symbolSession.sessions))
{
//
int count = ArraySize(symbolSession.sessions);
for (int i = 0; i < count; i++)
{
//
isExists = symbolSession.sessions[i].end == session.end &&
symbolSession.sessions[i].start == session.start;
if (isExists)
{
break;
}
}
}
//
if (!isExists)
{
//
AddRef(
session,
symbolSession.sessions //
);
}
}
//
// Private ...
private:
//
// Props ...
//
bool allowTrade;
bool allowLongs;
bool allowShorts;
//
string forceCloseAt;
bool isForceCloseAtTime;
//
int maxAllowedTPs;
int maxAllowedSLs;
int maxAllowedTrades;
ENUM_XCATBEA_TRADE_RESTRICTION_PERIOD restrictionsPeriod;
bool HasRestrictions()
{
return restrictionsPeriod != XCATBEA_TRADE_RESTRICATION_NONE;
}
//
bool mSaveWins;
bool mSaveLosts;
bool mSaveTrades;
bool mSaveSignals;
bool mSaveRestrictions;
//
bool reportTrades;
bool reportSignals;
bool reportProtector;
bool reportRestrictions;
bool reportAfterTradesBalance;
//
CArrayObj mObjects;
//
XCATBEATrade trades[];
XCATBEASymbolInfo symbols[];
XCATBEASymbolSession sessions[];
};
//