Files
xMQL5/MQLTestWorkspace/BKPS/14030222/Classes/x-saherelm.xea.class.mq5
T
2024-05-11 05:36:03 +03:30

2143 lines
49 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Class Library
// ----------------------------------------------
// Name: XSCBaseEA
// Description: provides all Base EA requirements ...
//
//
// Maintainer:
// ------------
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
//
//////////////////////////////////////////////////////
//
// Global Properties ...
#property library
#property copyright "Copyright 2023, SaherElm IT Center"
#property link "https://www.saherelm.ir"
#property version "1.00"
#property strict
//
// START Definitions ...
//
//
// if Signal Execution Failed this is the reason ...
enum ENUM_X_SIGNAL_EXECUTION_FAILED
{
X_NOTHING, // Succeeded ...
X_UNKNOWN, // Failed, but Unknown ...
X_FAILED_REASON_EQUITY, // Failed, Since Equity ...
X_FAILED_REASON_SPREAD, // Failed, Since Spread ...
X_FAILED_REASON_MAX_REACHED // Failed Signce Max Allowed Reached ...
};
//
// END Definitions ...
//
//
// START Import and Inclused requirements ...
//
//
// Includes ...
#include "../Libraries/x-saherelm.alert.lib.mq5"
#include "../Libraries/x-saherelm.common.lib.mq5"
#include "../Classes/x-saherelm.xtrade.class.mq5"
#include "../Classes/x-saherelm.xaccount.class.mq5"
#include "../Classes/x-saherelm.xprovider.class.mq5"
#include "../Libraries/x-saherelm.seriallizer.lib.mq5"
//
// END Import and Inclused requirements ...
//
//
// START Overrides ...
//
//
// END Overrides ...
//
//
// a Class for Handle base requirements ...
// for indicators ...
class XSCBaseEA
{
//
// Public ...
public:
//
// Props ...
XSCTrade *mTrader;
XSCAccount *mAccount;
//
bool isNewHour;
bool isNewDay;
bool isNewWeek;
bool isNewMonth;
bool isNewCandle;
//
bool isInTestMode;
//
bool mWaitsUntilNewCandle;
//
// Constructor ...
void XSCBaseEA(
string symbol, // Trading Symbol
ENUM_TIMEFRAMES period, // Trading Time Frame
ulong magic, // Magic Number
int slippage, // Slippgae
double maxAllowedSpread, // Max Allowed Spread to Execute Signal
int maxAllowedPositions, // Maximum Allowed Same Time Position
double minProfitPerTrade, // Min Profit Per Trade based On Volume Factor (Hedge)
double minProfitPerVolumeFactor, // Min Volume Factor for Calculating Profit (Hedge)
double maxAllowedDrawDownFactor, // Max Allowed Drawdown factor for Open New Positions
TOnStopLoss onStopLossTriggered = NULL, // On StopLoass Triggered Event Handler
TOnTakeProfit onTakeProfitTriggered = NULL, // On TakeProfit Triggered Event Handler
TOnDealsChanged onDealsChangedHandler = NULL, // On Deals Changed Event Handler
TOnOrdersChanged onOrdersChangedHandler = NULL, // On Orders Changed Event Handler
TOnPositionsChanged onPositionsChangedHandler = NULL, // On Positions Changed Event Handler
TOnTradeStateChanged onTradeStateChangedHandler = NULL // On Trade State Changed Event Handler
)
{
//
mSymbol = symbol;
mPeriod = period;
//
mMagic = magic;
mSlippage = slippage;
//
mMaxAllowedSpread = maxAllowedSpread;
//
mMaxAllowedPositions = maxAllowedPositions;
mMaxAllowedDrawDownFactor = maxAllowedDrawDownFactor;
//
mMinProfitPerTrade = minProfitPerTrade;
mMinProfitPerVolumeFactor = minProfitPerVolumeFactor;
//
mOnStopLossTriggered = onStopLossTriggered;
mOnTakeProfitTriggered = onTakeProfitTriggered;
mOnDealsChangedHandler = onDealsChangedHandler;
mOnOrdersChangedHandler = onOrdersChangedHandler;
mOnPositionsChangedHandler = onPositionsChangedHandler;
mOnTradeStateChangedHandler = onTradeStateChangedHandler;
//
// Reset Timings ...
ResetTiming();
//
InitRequirements();
}
//
// Deconstructor ...
void ~XSCBaseEA()
{
//
delete mTrader;
delete mAccount;
}
//
// START Properties ...
//
//
// Symbol ...
string GetSymbol()
{
return mSymbol;
}
//
// Period ...
ENUM_TIMEFRAMES GetPeriod()
{
return mPeriod;
}
//
// Tag ...
string GetTag()
{
return mTag;
}
//
ulong GetMagic()
{
return mMagic;
}
//
int GetSlippage()
{
return mSlippage;
}
//
// Check Long Signalling State ...
bool EnableLongs()
{
return mEnableLongs;
}
//
// Set Long Signalling State ...
void EnableLongs(bool enable)
{
//
if (enable == mEnableLongs)
{
return;
}
//
mEnableLongs = enable;
}
//
// Check Short Signalling State ...
bool EnableShorts()
{
return mEnableShorts;
}
//
// Set Short Signalling State ...
void EnableShorts(bool enable)
{
//
if (enable == mEnableShorts)
{
return;
}
//
mEnableShorts = enable;
}
//
double MaxAllowedSpread()
{
return mMaxAllowedSpread;
}
//
void MaxAllowedSpread(double value)
{
//
if (value <= 0)
{
value = 0;
}
//
if (value == mMaxAllowedSpread)
{
return;
}
//
mMaxAllowedSpread = value;
}
//
// Get Max Allowed Positions at Same Time ...
int MaxAllowedPositions()
{
return mMaxAllowedPositions;
}
//
// Set Max Allowed Positions at Same Time ...
void MaxAllowedPositions(int value)
{
//
if (value < 0 ||
value == mMaxAllowedPositions)
{
return;
}
//
mMaxAllowedPositions = value;
}
//
// Get Max Allowed DrawDown Factor ...
double MaxAllowedDrawDownFactor()
{
return mMaxAllowedDrawDownFactor;
}
//
// Set Max Allowed Positions at Same Time ...
void MaxAllowedDrawDownFactor(double value)
{
//
if (value < 0 ||
value == mMaxAllowedDrawDownFactor)
{
return;
}
//
mMaxAllowedDrawDownFactor = value;
}
//
double MinProfitPerTrade()
{
return mMinProfitPerTrade;
}
//
void MinProfitPerTrade(double value)
{
//
if (value <= 0)
{
value = 0;
}
//
if (value == mMinProfitPerTrade)
{
return;
}
//
mMinProfitPerTrade = value;
}
//
double MinProfitPerVolumeFactor()
{
return mMinProfitPerVolumeFactor;
}
//
void MinProfitPerVolumeFactor(double value)
{
//
if (value <= 0)
{
value = 0;
}
//
if (value == mMinProfitPerVolumeFactor)
{
return;
}
//
mMinProfitPerVolumeFactor = value;
}
//
// END Properties ...
//
//
// START Provided Functions ...
//
//
// Prepare Tag ...
virtual void PrepareTag()
{
mTag = "XEA" + mSymbol + "," + ToString(mPeriod) + (string)mMagic;
}
//
// Handle Chart Events ...
virtual void OnChartEvent(
const int id, // event ID
const long &lparam, // long type event parameter
const double &dparam, // double type event parameter
const string &sparam // string type event parameter
)
{
}
//
// Check any Registered Providers Signalling ...
virtual bool SignalCheck(XSignal &signals[])
{
return false;
}
//
// Check for any Custom Guard Actions Guard Actions ...
virtual bool CheckGuard(XGuard &guards[])
{
return false;
}
//
virtual void BeforeSignalExecution(XSignal &signals[]) {}
//
// NOTE: you have to call these Functions on Static Classes to Handle Works ...
//
// Handle StopLoss Event ...
virtual void OnStopLossTriggered(const XDeal &deal) {}
//
// Handle TakeProfit Event ...
virtual void OnTakeProfitTriggered(const XDeal &deal) {}
//
// Handle Deals Changed Event ...
virtual void OnDealsChangedHandler(int count) {}
//
// Handle Order Changed Event ...
virtual void OnOrdersChangedHandler(int count) {}
//
// Handle Position Changed Event ...
virtual void OnPositionsChangedHandler(int count) {}
//
// Handle Trade State Changed ...
virtual void OnTradeStateChangedHandler(const XOnTradeHandlerState &state) {}
//
// Implemented Actions ...
//
// OnTick Handler ...
void OnTick()
{
//
// First Check Guards ....
// Only when Open Positions Exists or Has Pending Order ...
XGuard guards[];
bool hasGuard = CheckGuard(guards);
if (hasGuard)
{
DoGuards(guards);
}
//
XSignal signals[];
bool hasSignal = SignalCheck(signals);
if (hasSignal)
{
//
// Here we have to Check Signals and also it's State ...
XSignal enabledSignals[];
int signalsCount = ArraySize(signals);
if (signalsCount <= 0)
{
return;
}
//
// Filter Signals by their type and
// also Check EA Enable their type ...
for (int i = 0; i < signalsCount; i++)
{
//
XSignal iSignal = signals[i];
bool isLong = IsLong(iSignal.type);
if ((isLong && mEnableLongs) ||
(!isLong && mEnableShorts))
{
//
Add(
iSignal,
enabledSignals);
}
}
//
int enabledSignalsCount = ArraySize(enabledSignals);
if (enabledSignalsCount <= 0)
{
return;
}
//
// Here we have do All things before Signals Execution ...
// in this way we can implement custom searios on Inherited Classes ...
BeforeSignalExecution(enabledSignals);
//
// Now double chack signals Array ....
// if there isn't any signal we prevent moving forward ...
// this helps us to Manage Signal Executions on Above Part ...
// for inherited classes ...
enabledSignalsCount = ArraySize(enabledSignals);
if (enabledSignalsCount <= 0)
{
return;
}
//
ENUM_X_SIGNAL_EXECUTION_FAILED reasons[];
ExecuteSignals(
enabledSignals,
reasons,
true // Check Policiese ...
);
}
}
//
// Handle On Trade ...
void OnTrade()
{
//
XOnTradeHandlerState state = mTrader.HandleOnTrade();
//
if (
!state.hasNewDeal &&
!state.hasNewOrder &&
!state.hasNewPosition &&
!state.hasNewHistoryOrder)
{
return;
}
//
// STATE ...
//
// Notfy Trade State Changed Event ...
OnTradeStateChangedHandler(state);
//
// DEALS ...
if (state.hasNewDeal)
{
//
// Notfy Deals Changed Event ...
OnDealsChangedHandler(state.newDeals);
//
// Retrieve Last Deal ...
XDeal deals[];
mTrader.GetDeals(deals);
int dealsCount = ArraySize(deals);
if (dealsCount > 0)
{
//
XDeal lastDeal = deals[0];
//
if (lastDeal.reason == DEAL_REASON_TP)
{
OnTakeProfitTriggered(lastDeal);
}
else if (lastDeal.reason == DEAL_REASON_SL)
{
OnStopLossTriggered(lastDeal);
}
}
}
//
// ORDERS ...
if (state.hasNewOrder || state.hasNewHistoryOrder)
{
//
// Notfy Orders Changed Event ...
OnOrdersChangedHandler(state.newOrders + state.newHistoryOrders);
}
//
// POSITIONS ...
if (state.hasNewPosition)
{
//
// Notfy Positions Changed Event ...
OnPositionsChangedHandler(state.newPositions);
}
}
//
// Retrieve Dept Of Market ...
void OnBookEvent(const string &symbol)
{
//
// TODO: Implement this ...
}
//
// TOOLS ...
//
// Execute Specific Signal by Checking Spreads ...
// if provided ...
bool ExecuteSignal(
const XSignal &signal, // Source Signal ...
ENUM_X_SIGNAL_EXECUTION_FAILED &reason, // Provides Error Reason ...
bool checkPoliciese = true // Check Account Policies Before Execute Signal ...
)
{
//
bool result = false;
reason = X_NOTHING;
//
// Check Account Policies ...
if (checkPoliciese)
{
//
// First Check Equity ...
result = CheckEquityForTrade();
if (!result)
{
//
reason = X_FAILED_REASON_EQUITY;
return result;
}
//
// Check Positions Count ...
result = ChecPositionsForTrade();
if (!result)
{
//
reason = X_FAILED_REASON_MAX_REACHED;
return result;
}
//
// Check Spread ...
result = IsSpreadOkForSignalExecution(signal);
if (!result)
{
//
reason = X_FAILED_REASON_SPREAD;
return result;
}
}
//
XSignal tmpSignal = signal;
PrepareSignal(tmpSignal);
//
// Generate Provider Comment ...
string comment = GenerateProvidersString(tmpSignal);
//
result = mTrader
.ExecuteSignal(
tmpSignal,
comment //
);
if (!result)
{
reason = X_UNKNOWN;
}
//
return result;
}
//
// Execute Specific Signals by Checking Spreads ...
// if provided ...
int ExecuteSignals(
const XSignal &signals[], // Signals Collection ...
ENUM_X_SIGNAL_EXECUTION_FAILED &reasons[], // Provides Error Reason ...
bool checkPoliciese = true // Check Account Policies Before Execute Signal ...
)
{
//
int result = 0;
//
Clean(reasons);
//
int signalsCount = ArraySize(signals);
if (signalsCount <= 0)
{
return result;
}
//
// Here we Have to Check Account Policies
// and Execute Signals base on them ...
//
for (int i = 0; i < signalsCount; i++)
{
//
XSignal iSignal = signals[i];
//
ENUM_X_SIGNAL_EXECUTION_FAILED iReason = X_NOTHING;
//
bool isExecuted = ExecuteSignal(
iSignal,
iReason,
checkPoliciese //
);
if (isExecuted)
{
result++;
}
//
Add(
iReason,
reasons);
}
//
return result;
}
//
// Get All Open Trades ...
int GetPositions(
XPosition &result[], // Hold Result ...
string symbol = NULL, // Trading Symbol ...
ENUM_POSITION_TYPE type = NULL, // Trading Type ...
ENUM_TIMEFRAMES period = NULL, // Trading Period ...
string provider = NULL // Signal Provider ...
)
{
//
int mResult = 0;
//
Clean(result);
//
bool hasSymbol = !(symbol == NULL || StringLen(symbol) == 0);
bool hasProvider = !(provider == NULL || StringLen(provider) == 0);
//
int positionsCount = mTrader.CountPositions();
if (positionsCount <= 0)
{
return mResult;
}
//
XPosition positions[];
mTrader.GetPositions(
positions,
symbol,
period);
positionsCount = ArraySize(positions);
if (positionsCount <= 0)
{
return mResult;
}
//
if (!hasProvider && type == NULL)
{
//
Copy(
positions,
result);
//
return ArraySize(result);
}
//
if (type == NULL)
{
//
ArrayResize(
result,
ArraySize(positions));
//
for (int i = 0; i < positionsCount; i++)
{
//
Add(
positions[i],
result);
}
//
return ArraySize(result);
}
//
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = positions[i];
//
string iProvider = ExtractProvider(iPosition.comment);
if (hasProvider && iProvider != provider)
{
continue;
}
//
if (type == NULL || iPosition.type == type)
{
//
Add(
iPosition,
result);
}
}
//
mResult = ArraySize(result);
//
return mResult;
}
//
// Extract Positions by it's Profits ...
void ExtractPositionsBasedOnProfits(
const XPosition &positions[], // Check as Data Source
XPosition &inDPositions[], // Hold In Drawdown Positions
XPosition &inPPositions[] // Hold In Profit Positions
)
{
//
Clean(inDPositions);
Clean(inPPositions);
//
int positionsCount = ArraySize(positions);
if (positionsCount <= 0)
{
return;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = positions[i];
//
if (iPosition.profit > 0)
{
//
Add(
iPosition,
inPPositions);
}
else if (iPosition.profit < 0)
{
//
Add(
iPosition,
inDPositions);
}
}
}
//
// Get All In Profit Trades ...
int GetInProfitPositions(
XPosition &result[], // Hold Result ...
string symbol = NULL, // Trading Symbol ...
ENUM_POSITION_TYPE type = NULL, // Trading Type ...
ENUM_TIMEFRAMES period = NULL, // Trading Period ...
string provider = NULL, // Signal Provider ...
ENUM_X_POSITION_SELECT_METHODS method = NULL // Select Method ...
)
{
//
int mResult = 0;
//
Clean(result);
//
if (method == NULL)
{
method = X_POSITION_SELECT_ALL;
}
//
// Prevent Going Forwars Since selection type is NONE ...
if (method == X_POSITION_SELECT_NONE)
{
return mResult;
}
//
bool isMinSelectable = method == X_POSITION_SELECT_MIN;
bool isMaxSelectable = method == X_POSITION_SELECT_MAX;
//
XPosition positions[];
GetPositions(
positions,
symbol,
type,
period,
provider);
int positionsCount = ArraySize(positions);
if (positionsCount <= 0)
{
return mResult;
}
//
// Define Temp Position for Selecting Max Position ...
XPosition maxPos;
maxPos.profit = INVALID_HANDLE;
//
// Define Temp Position for Selecting Min Position ...
XPosition minPos;
minPos.profit = INVALID_HANDLE;
//
// Loop through available Positions for Selecting Positions ...
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = positions[i];
//
// Check Profit State ...
if (iPosition.profit <= 0)
{
continue;
}
//
// Check Selection State ...
if (isMinSelectable)
{
//
if (minPos.profit == INVALID_HANDLE ||
minPos.profit > iPosition.profit)
{
minPos = iPosition;
}
//
continue;
}
else if (isMaxSelectable)
{
//
if (maxPos.profit == INVALID_HANDLE ||
maxPos.profit < iPosition.profit)
{
maxPos = iPosition;
}
//
continue;
}
else
{
//
Add(
iPosition,
result);
}
}
//
// Add Selected Position if Provided to Results ...
if (isMinSelectable)
{
//
Add(
minPos,
result);
}
else if (isMaxSelectable)
{
//
Add(
maxPos,
result);
}
//
mResult = ArraySize(result);
//
return mResult;
}
//
// Get All In Drawdown Trades ...
int GetInDrawdownPositions(
XPosition &result[], // Hold Result ...
string symbol = NULL, // Trading Symbol ...
ENUM_POSITION_TYPE type = NULL, // Trading Type ...
ENUM_TIMEFRAMES period = NULL, // Trading Period ...
string provider = NULL, // Signal Provider ...
ENUM_X_POSITION_SELECT_METHODS method = NULL // Select Method ...
)
{
//
int mResult = 0;
//
Clean(result);
//
if (method == NULL)
{
method = X_POSITION_SELECT_ALL;
}
//
// Prevent Going Forwars Since selection type is NONE ...
if (method == X_POSITION_SELECT_NONE)
{
return mResult;
}
//
bool isMinSelectable = method == X_POSITION_SELECT_MIN;
bool isMaxSelectable = method == X_POSITION_SELECT_MAX;
//
XPosition positions[];
GetPositions(
positions,
symbol,
type,
period,
provider);
int positionsCount = ArraySize(positions);
if (positionsCount <= 0)
{
return mResult;
}
//
// Define Temp Position for Selecting Max Position ...
XPosition maxPos;
maxPos.profit = INVALID_HANDLE;
//
// Define Temp Position for Selecting Min Position ...
XPosition minPos;
minPos.profit = INVALID_HANDLE;
//
// Loop through available Positions for Selecting Positions ...
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = positions[i];
//
// Check Profit State ...
if (iPosition.profit >= 0)
{
continue;
}
//
// Check Selection State ...
if (isMinSelectable)
{
//
if (minPos.profit == INVALID_HANDLE ||
minPos.profit < iPosition.profit)
{
minPos = iPosition;
}
//
continue;
}
else if (isMaxSelectable)
{
//
if (maxPos.profit == INVALID_HANDLE ||
maxPos.profit > iPosition.profit)
{
maxPos = iPosition;
}
//
continue;
}
else
{
//
Add(
iPosition,
result);
}
}
//
// Add Selected Position if Provided to Results ...
if (isMinSelectable)
{
//
Add(
minPos,
result);
}
else if (isMaxSelectable)
{
//
Add(
maxPos,
result);
}
//
mResult = ArraySize(result);
//
return mResult;
}
//
// Retrieve Orders ...
int GetOrders(
XOrder &result[], // Hold Result ...
string symbol = NULL, // Trading Symbol ...
ENUM_ORDER_TYPE type = NULL, // Trading Type ...
ENUM_ORDER_STATE state = NULL, // Trading State ...
ENUM_TIMEFRAMES period = NULL, // Trading Period ...
string provider = NULL // Signal Provider ...
)
{
//
int mResult = 0;
//
Clean(result);
//
XOrder orders[];
mTrader.GetOrders(
orders,
symbol,
period,
state);
int ordersCount = ArraySize(orders);
if (ordersCount <= 0)
{
return mResult;
}
//
if (type == NULL &&
(provider == NULL ||
StringLen(provider) == 0))
{
//
Copy(
orders,
result);
//
mResult = ArraySize(result);
//
return mResult;
}
//
for (int i = 0; i < ordersCount; i++)
{
//
XOrder iOrder = orders[i];
//
if (type != NULL && iOrder.type != type)
{
continue;
}
//
if (provider != NULL &&
StringLen(provider) > 0)
{
//
// Generate Order Provider ...
string iProvider = ExtractProvider(iOrder.comment);
if (iProvider != provider)
{
continue;
}
}
//
Add(
iOrder,
result);
}
//
mResult = ArraySize(result);
//
return mResult;
}
//
int GetHistoryOrders(
XOrder &result[], // Hold Result ...
string symbol = NULL, // Trading Symbol ...
ENUM_ORDER_TYPE type = NULL, // Trading Type ...
ENUM_ORDER_STATE state = NULL, // Trading State ...
ENUM_TIMEFRAMES period = NULL, // Trading Period ...
string provider = NULL, // Signal Provider ...
datetime startDate = 0, // Start Date ...
datetime endDate = 0 // End Date ...
)
{
//
int mResult = 0;
//
Clean(result);
//
XOrder history[];
int historyCount = mTrader
.GetHistoryOrders(
history,
symbol,
period,
type,
state,
startDate,
endDate);
if (historyCount <= 0)
{
return mResult;
}
//
if (StringLen(provider) == 0 || provider == NULL)
{
//
Copy(
history,
result);
//
mResult = ArraySize(result);
//
return mResult;
}
//
for (int i = 0; i < historyCount; i++)
{
//
XOrder iHistory = history[i];
//
if (provider != NULL &&
StringLen(provider) > 0)
{
//
// Generate Order Provider ...
string iProvider = ExtractProvider(iHistory.comment);
if (iProvider != provider)
{
continue;
}
}
//
Add(
iHistory,
result);
}
//
mResult = ArraySize(result);
//
return mResult;
}
//
int GetHistoryDeals(
XDeal &result[], // Hold Result ...
string symbol = NULL, // Trading Symbol ...
ENUM_DEAL_TYPE type = NULL, // Specify Deal Type ...
ENUM_DEAL_REASON reason = NULL, // Specify Deal Reason ...
ENUM_TIMEFRAMES period = NULL, // Trading Period ...
string provider = NULL, // Signal Provider ...
datetime startDate = 0, // Start Date ...
datetime endDate = 0 // End Date ...
)
{
//
int mResult = 0;
//
Clean(result);
//
XDeal history[];
int historyCount = mTrader
.GetHistoryDeals(
history,
symbol,
type,
reason,
startDate,
endDate);
if (historyCount <= 0)
{
return mResult;
}
//
bool canCheckPeriod = period != NULL;
bool canCheckProvider = provider != NULL &&
StringLen(provider) > 0;
//
if (!canCheckPeriod && !canCheckProvider)
{
//
Copy(
history,
result);
//
mResult = ArraySize(history);
//
return mResult;
}
//
for (int i = 0; i < historyCount; i++)
{
//
XDeal iDeal = history[i];
//
if (canCheckPeriod)
{
//
ENUM_TIMEFRAMES dealPeriod = mTrader.GetDealPeriod(iDeal);
if (dealPeriod != period)
{
continue;
}
}
//
if (canCheckProvider)
{
//
string comment = mTrader.GetDealPositionComment(iDeal);
if (StringLen(comment) <= 0)
{
continue;
}
//
string oProvider = ExtractPeriodString(comment);
if (oProvider != provider)
{
continue;
}
}
//
Add(
iDeal,
result);
}
//
mResult = ArraySize(result);
//
return mResult;
}
//
// GUARD Handlers ...
//
// Parse Recievd Guards and Do them ...
void DoGuards(XGuard &guards[])
{
//
int guardsCount = ArraySize(guards);
if (guardsCount <= 0)
{
return;
}
//
for (int i = 0; i < guardsCount; i++)
{
//
XGuard iGuard = guards[i];
//
switch (iGuard.action)
{
//
// Hedge In Profit Specified Positions ...
case X_GUARD_ACTION_HEDGE:
HandleGuardHedgeAction(
iGuard.provider,
iGuard.symbol,
iGuard.type,
iGuard.period);
break;
//
// Trail Stop Loss in Specified Positions ...
case X_GUARD_ACTION_TRAIL_STOP:
HandleGuardTrailingStopAction(
iGuard.provider,
iGuard.symbol,
iGuard.type,
iGuard.period,
iGuard.dblPayLoad);
break;
//
// Force Close Specified Positions ...
case X_GUARD_ACTION_FORCE_CLOSE:
HandleGuardForceCloseAction(
iGuard.provider,
iGuard.symbol,
iGuard.type,
iGuard.period);
break;
//
// Generate and Place Support Signals ...
case X_GUARD_ACTION_ADD_SUPPORT_SIGNAL:
HandleGuardAddSupportPositionAction(
iGuard.provider,
iGuard.symbol,
iGuard.type,
iGuard.period);
break;
//
// Delete All Placed Pending Orders ...
case X_GUARD_ACTION_CANCEL_PENDING_ORDERS:
HandleGuardCancelPendingOrdersAction(
iGuard.provider,
iGuard.symbol,
iGuard.type,
iGuard.period);
break;
}
}
}
//
// Close All Specified Provider's Positions in Profit Summary ...
void HandleGuardHedgeAction(
string provider, // Positions Provided by Specific Provider
string symbol, // Trading Symbol
ENUM_POSITION_TYPE type, // Trading Type
ENUM_TIMEFRAMES period, // Specified Time Frame
double minProfitForHedging = 1 // Specified Profit for Hedge
)
{
//
XPosition positions[];
int positionsCount = GetPositions(
positions,
symbol,
type,
period,
provider);
if (positionsCount <= 1)
{
return;
}
//
double profit = CalculatePositionsProfit(positions);
double requiredProfit = CalculateRequiredProfitForHedge(positions);
//
bool isReadyForHedge = profit >= requiredProfit;
if (!isReadyForHedge)
{
return;
}
//
string comment = "Guard Hedge " + provider;
int closed = mTrader.ClosePositions(
positions,
comment);
if (closed > 0)
{
//
string message = "Guard Hedge " + provider + "'s Positions on Profit: " + ToString(profit);
//
LogMessage(message);
}
}
//
// Close Max In Profit Trade Guard Action ...
void HandleGuardCloseInProfitAction(
string provider, // Positions Provided by Specific Provider
string symbol, // Trading Symbol
ENUM_POSITION_TYPE type, // Trading Type
ENUM_TIMEFRAMES period, // Specified Time Frame
ENUM_X_POSITION_SELECT_METHODS method = NULL // Select Method
)
{
//
XPosition positions[];
GetInProfitPositions(
positions,
symbol,
type,
period,
provider,
method);
int positionsCount = ArraySize(positions);
if (positionsCount <= 0)
{
return;
}
//
string comment = "Close InProfit ...";
mTrader.ClosePositions(
positions,
comment);
//
string message = "Guard Close (" + ToString(positionsCount) + ") Postion(s) In Profit ...";
LogMessage(message);
}
//
// Close Max In Drawdown Trade Guard Action ...
void HandleGuardCloseInDrawdownAction(
string provider, // Positions Provided by Specific Provider
string symbol, // Trading Symbol
ENUM_POSITION_TYPE type, // Trading Type
ENUM_TIMEFRAMES period, // Specified Time Frame
ENUM_X_POSITION_SELECT_METHODS method = NULL // Select Method
)
{
//
XPosition positions[];
GetInDrawdownPositions(
positions,
symbol,
type,
period,
provider,
method);
int positionsCount = ArraySize(positions);
if (positionsCount <= 0)
{
return;
}
//
string comment = "Close InDrawdown ...";
mTrader.ClosePositions(
positions,
comment);
//
string message = "Guard Close (" + ToString(positionsCount) + ") Position(s) In Drawdown ...";
LogMessage(message);
}
//
// Force Close Specified Set Of Position ...
void HandleGuardForceCloseAction(
string provider, // Positions Provided by Specific Provider
string symbol, // Trading Symbol
ENUM_POSITION_TYPE type, // Trading Type
ENUM_TIMEFRAMES period, // Specified Time Frame
ulong ticket = 0 // Specific Ticket
)
{
//
string comment = "";
//
// Close All Positions ...
if (ticket == 0)
{
//
XPosition positions[];
GetPositions(
positions,
symbol,
type,
period,
provider);
if (ArraySize(positions) <= 0)
{
return;
}
//
comment = provider + " Force Close Guard ...";
//
mTrader.ClosePositions(
positions,
comment);
}
//
// Close Specific Position ...
else
{
//
XPosition position;
bool hasPosition = mTrader.GetPosition(
position,
ticket);
//
if (hasPosition)
{
//
comment = provider + "(" + ToString(ticket) + ")" + " Force Close Guard ...";
//
mTrader.Close(
ticket,
comment);
}
}
//
if (StringLen(comment) > 0)
{
LogMessage(comment);
}
}
//
// Trailing Specified Set Of Positions Stop Losses ...
void HandleGuardTrailingStopAction(
string provider, // Positions Provided by Specific Provider
string symbol, // Trading Symbol
ENUM_POSITION_TYPE type, // Trading Type
ENUM_TIMEFRAMES period, // Specified Time Frame
double sl // Desired SL Value ...
)
{
//
if (sl <= 0)
{
return;
}
//
NormalizePrice(
sl,
symbol);
//
XPosition positions[];
GetPositions(
positions,
symbol,
type,
period,
provider);
int positionsCount = ArraySize(positions);
if (positionsCount <= 0)
{
return;
}
//
int modified = 0;
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = positions[i];
//
string comment = PrepareSLTrailComment(iPosition.comment);
//
if (iPosition.sl == sl)
{
continue;
}
//
bool isModified = mTrader.Modify(
iPosition.ticket,
sl,
iPosition.tp,
comment);
if (isModified)
{
modified++;
}
}
//
if (modified > 0)
{
//
string msg = "(" + ToString(modified) + ") Position's Stop Trailed Successfully ...";
//
LogMessage(msg);
}
}
//
// Add Support Signal for Specified Positions ...
void HandleGuardAddSupportPositionAction(
string provider, // Positions Provided by Specific Provider
string symbol, // Trading Symbol
ENUM_POSITION_TYPE type, // Trading Type
ENUM_TIMEFRAMES period // Specified Time Frame
)
{
//
// TODO: Implement this ...
}
//
// Cancel all Placed Orders ...
void HandleGuardCancelPendingOrdersAction(
string provider, // Positions Provided by Specific Provider
string symbol, // Trading Symbol
ENUM_POSITION_TYPE type, // Trading Type
ENUM_TIMEFRAMES period // Specified Time Frame
)
{
//
// TODO: Implement this ...
}
//
// END Provided Functions ...
//
//
// Protected ...
protected:
//
string GetTagPrefix()
{
//
string result = "(" + mSymbol + ")(" + ToString(mPeriod) + ")";
//
return result;
}
//
// Symbol ...
string mSymbol;
//
// Period ...
ENUM_TIMEFRAMES mPeriod;
//
// ExpertAdviser MAgic Number ...
ulong mMagic;
//
// Slipppage ...
int mSlippage;
//
// Tag Identifier ...
string mTag;
//
bool mEnableLongs;
bool mEnableShorts;
//
double mMaxAllowedSpread;
//
int mMaxAllowedPositions;
double mMaxAllowedDrawDownFactor;
//
double mMinProfitPerTrade;
double mMinProfitPerVolumeFactor;
//
// Prepare a Signal and Do Calculations ...
void PrepareSignal(
XSignal &signal // a Signal for Preparation ...
)
{
//
// Normalize Signal ...
NormalizeSignal(signal);
}
//
// Check Acocunt Balance is Allow new Trades or not ...
bool CheckEquityForTrade()
{
//
bool result = false;
//
if (mMaxAllowedDrawDownFactor <= 0)
{
//
result = true;
return result;
}
//
double equity = mAccount.GetEquity();
double balance = mAccount.GetBalance();
//
double selectedBalance = MathMax(equity, balance) - MathMin(equity, balance);
//
double balanceForFactor = MathAbs(equity - balance);
if (balanceForFactor <= 0)
{
balanceForFactor = balance;
}
else
{
balanceForFactor = equity;
}
//
double maxAllowedBalanceDrawDown = balanceForFactor * mMaxAllowedDrawDownFactor;
//
result = equity > balance ||
(equity <= balance &&
selectedBalance <= maxAllowedBalanceDrawDown);
//
return result;
}
//
// Check Max Allowed Positions Policy for Trade ...
bool ChecPositionsForTrade()
{
//
bool result = false;
//
if (mMaxAllowedPositions <= 0)
{
//
result = true;
return result;
}
//
int positionsCount = mTrader.CountPositions();
if (positionsCount <= 0)
{
//
result = true;
return result;
}
//
result = positionsCount <= mMaxAllowedPositions;
//
return result;
}
//
// Check Spread is Ok for Executing Specific Signal ...
bool IsSpreadOkForSignalExecution(const XSignal &signal)
{
//
bool result = false;
//
bool isSpreadCheckEnable = mMaxAllowedSpread > 0;
if (!isSpreadCheckEnable)
{
result = true;
}
else
{
//
// Retrieve Signal Spread ...
double spread = PriceToPoint(
signal.symbol,
GetSpread(signal.symbol));
result = spread <= mMaxAllowedSpread;
}
//
return result;
}
//
// Calculate Required Profit for Hedging ...
double CalculateRequiredProfitForHedge(
XPosition &positions[] // Source
)
{
//
double result = 0;
//
int positionsCount = ArraySize(positions);
if (positionsCount <= 0)
{
return result;
}
//
bool isHedgingEnable = mMinProfitPerTrade > 0 && mMinProfitPerVolumeFactor > 0;
if (!isHedgingEnable)
{
return result;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = positions[i];
//
if (mMinProfitPerTrade > 0 && mMinProfitPerVolumeFactor > 0)
{
//
result +=
((iPosition.volume / mMinProfitPerVolumeFactor) *
mMinProfitPerTrade) +
(-1 * iPosition.swap);
}
}
//
return result;
}
//
// Calculate Positions Profit Summary ...
double CalculatePositionsProfit(
XPosition &positions[] // Source
)
{
//
double result = 0;
//
int positionsCount = ArraySize(positions);
if (positionsCount <= 0)
{
return result;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = positions[i];
//
result += iPosition.profit;
}
//
return result;
}
//
// Close a Position Pack and Cancel All of it's Supports ...
bool HandleClosePack(XPositionPack &pack)
{
//
bool result = false;
//
if (pack.ticket <= 0)
{
return result;
}
//
XOrder orders[];
XPosition positions[];
//
bool hasPos = pack.position.ticket > 0;
if (hasPos)
{
Add(
pack.position,
positions);
}
//
bool hasSupportPos = pack.supportPositionsCount > 0;
if (hasSupportPos)
{
//
Copy(
pack.supportPositions,
positions,
false);
}
//
bool hasSupportOrd = pack.supportOrdersCount > 0;
if (hasSupportOrd)
{
//
Copy(
pack.supportOrders,
orders);
}
//
string comment = "Close Pack";
//
int closed = mTrader.ClosePositions(positions, comment);
int canceled = mTrader.CancelOrders(orders);
//
result = closed + canceled == ArraySize(orders) + ArraySize(positions);
if (result)
{
//
string message = "Close Position(" + ToString(pack.ticket) + ")'s Pack ...";
//
LogMessage(message);
}
//
return result;
}
//
// Private ...
private:
//
// Define Requirements ...
//
// XSCTrade Event Handlers ...
TOnStopLoss mOnStopLossTriggered;
TOnTakeProfit mOnTakeProfitTriggered;
TOnDealsChanged mOnDealsChangedHandler;
TOnOrdersChanged mOnOrdersChangedHandler;
TOnPositionsChanged mOnPositionsChangedHandler;
TOnTradeStateChanged mOnTradeStateChangedHandler;
//
// Initi Requirements ...
void InitRequirements()
{
//
// Account Manager ...
mAccount = new XSCAccount();
//
// Trader ...
mTrader = new XSCTrade(
mSlippage,
mMagic);
//
// Attach Event Handlers ...
//
if (mOnStopLossTriggered != NULL)
{
mTrader.AddOnStopLossEventHandler(mOnStopLossTriggered);
}
//
if (mOnTakeProfitTriggered != NULL)
{
mTrader.AddOnTakeProfitEventHandler(mOnTakeProfitTriggered);
}
//
if (mOnDealsChangedHandler != NULL)
{
mTrader.AddOnDealsChangedEventHandler(mOnDealsChangedHandler);
}
//
if (mOnOrdersChangedHandler != NULL)
{
mTrader.AddOnOrdersChangedEventHandler(mOnOrdersChangedHandler);
}
//
if (mOnPositionsChangedHandler != NULL)
{
mTrader.AddOnPositionsChangedEventHandler(mOnPositionsChangedHandler);
}
//
if (mOnTradeStateChangedHandler != NULL)
{
mTrader.AddOnTradeStateChangedEventHandler(mOnTradeStateChangedHandler);
}
}
};
//
// START Usefull Functions ...
//
//
// END Usefull Functions ...
//