3783 lines
84 KiB
Plaintext
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[];
|
|
};
|
|
|
|
//
|