2143 lines
49 KiB
Plaintext
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 ...
|
|
//
|