Files
MQL5Data/X121SMCEA/Experts/x-121.smc.expert.class.mq5
T
2025-03-17 23:40:10 +03:30

2446 lines
60 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Class Library
// --------------------------------------
// Name: XC121SMCExpert
// Description: provides all based classes for use ...
//
//
// 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-expert.class.mq5"
#include "../../Helpers/x-saherelm.x121.xcc.helper.mq5"
#include "../../Helpers/x-saherelm.x121.xct.helper.mq5"
#include "../Classes/x-121.smc.x-tradehandler.class.mq5"
#include "../Libraries/x-121.smc.lib.mq5"
#include "../Strategy/x-121.smc.strategy.class.mq5"
//
// Definitions ...
string XC121SMCExpertToken = "XC121SMCEA";
//
// Implementation ...
class XC121SMCExpert : public XCBaseExpert
{
//
public:
//
XCX121XCCHelper *xccHelper;
XCX121XCTHelper *xctHelper;
//
// Signal Event Listener ...
TOnStopLoss OnPositionSLEventListener;
TOnTakeProfit OnPositionTPEventListener;
TOnPartialClose OnPositionPartialCloseEventListener;
TOnModify OnPositionModifiedEventListener;
TOnForceClose OnPositionForceCloseEventListener;
//
TOnDealsChanged OnDealsChangedEventListener;
TOnOrdersChanged OnOrdersChangedEventListener;
TOnPositionsChanged OnPositionsChangedEventListener;
//
TOnX121SMCSignal OnSignalEventListener;
//
// Constructor(s) ...
XC121SMCExpert()
{
mShowCandles = true;
}
//
// Deconstructor(s) ...
~XC121SMCExpert()
{
Clean(mStrategies);
}
//
// Getter(s) / Setter(s) ...
//
// Signalling Props ...
/**
* Get Allow Long Signals State ...
*
* @return ( bool )
*/
bool AllowLong()
{
return mAllowLong;
}
/**
* Set Allow Long Signals State ...
*
* @param value: Boolean ...
*/
void AllowLong(bool value)
{
//
mAllowLong = value;
ReConfigure();
}
/**
* Get Allow Short Signals State ...
*
* @return ( bool )
*/
bool AllowShort()
{
return mAllowShort;
}
/**
* Set Allow Short Signals State ...
*
* @param value: Boolean ...
*/
void AllowShort(bool value)
{
//
mAllowShort = value;
ReConfigure();
}
/**
* Get Max Allowed Long Signals ...
* 0 => Unlimited ...
*
* @return ( int )
*/
int MaxAllowedLongs()
{
return mMaxAllowedLongs;
}
/**
* Set Max Allowed Long Signals ...
*
* @param value: Integer ...
* 0 => Unlimited ...
*/
void MaxAllowedLongs(int value)
{
//
if (value < 0)
{
value = 0;
}
//
mMaxAllowedLongs = value;
ReConfigure();
}
/**
* Get Max Allowed Short Signals ...
* 0 => Unlimited ...
*
* @return ( int )
*/
int MaxAllowedShorts()
{
return mMaxAllowedShorts;
}
/**
* Set Max Allowed Short Signals ...
*
* @param value: Integer ...
* 0 => Unlimited ...
*/
void MaxAllowedShorts(int value)
{
//
if (value < 0)
{
value = 0;
}
//
mMaxAllowedShorts = value;
ReConfigure();
}
/**
* Get Use Max Allowed Signal Types Per Symbol State ...
*
* @return ( bool )
*/
bool UseMaxAllowedSignalsPerSymbol()
{
return mUseMaxAllowedSignalsPerSymbol;
}
/**
* Set Use Max Allowed Signal Types Per Symbol State ...
*
* @param value: Boolean ...
*/
void UseMaxAllowedSignalsPerSymbol(bool value)
{
//
mUseMaxAllowedSignalsPerSymbol = false;
ReConfigure();
}
/**
* Get Last Position Profit In Points for Accept new Signal ...
* 0 => Accept All ...
*
* @return ( double )
*/
double LastPositionProfitForAcceptNextInPoint()
{
return mLastPositionProfitForAcceptNextInPoint;
}
/**
* Set Last Position Profit In Points for Accept new Signal ...
*
* @param value: Double ...
* 0 => Accept All ...
*/
void LastPositionProfitForAcceptNextInPoint(double value)
{
//
if (value < 0)
{
value = 0;
}
//
mLastPositionProfitForAcceptNextInPoint = value;
ReConfigure();
}
/**
* Get Delay between two Signals in Bars ...
* 0 => Accept All ...
*
* @return ( int )
*/
int DelaysBetweenTwoSignalsInBar()
{
return mDelaysBetweenTwoSignalsInBar;
}
/**
* Set Delay between two Signals in Bars ...
*
* @param value: Integer ...
* 0 => Accept All ...
*/
void DelaysBetweenTwoSignalsInBar(int value)
{
//
if (value < 0)
{
value = 0;
}
//
mDelaysBetweenTwoSignalsInBar = value;
ReConfigure();
}
/**
* Get Max Allowed Spread for Signalling ...
* 0 => Accept All ...
*
* @return ( double )
*/
double MaxAllowedSpread()
{
return mMaxAllowedSpread;
}
/**
* Set Max Allowed Spread for Signalling ...
*
* @param value: Double ...
* 0 => Accept All ...
*/
void MaxAllowedSpread(double value)
{
//
if (value < 0)
{
value = 0;
}
//
mMaxAllowedSpread = value;
ReConfigure();
}
//
// Trade ...
/**
* Get Allow Open Trade On Signals State ...
*
* @return ( bool )
*/
bool AllowTrade()
{
return mAllowTrade;
}
/**
* Set Allow Open Trade On Signals State ...
*
* @param value: Boolean ...
*/
void AllowTrade(bool value)
{
mAllowTrade = value;
}
/**
* Get Enable Trade on Signals on Time ...
*
* @return ( string )
*/
string StartTradeAt()
{
return mStartTradeAt;
}
/**
* Set Enable Trade on Signals on Time ...
*
* @param value: String ...
*/
void StartTradeAt(string value)
{
mStartTradeAt = value;
}
/**
* Get Enable Trade on Signals on Time ...
*
* @return ( string )
*/
string StopTradeAt()
{
return mStopTradeAt;
}
/**
* Set Enable Trade on Signals on Time ...
*
* @param value: String ...
*/
void StopTradeAt(string value)
{
mStopTradeAt = value;
}
/**
* Get Enable Close All Trades on Signals on Time ...
*
* @return ( string )
*/
string CloseAllTradesAt()
{
return mCloseAllTradesAt;
}
/**
* Set Enable Close All Trades on Signals on Time ...
*
* @param value: String ...
*/
void CloseAllTradesAt(string value)
{
mCloseAllTradesAt = value;
}
//
// Risk Management Props ...
/**
* Get Risk to Reward Ratio ...
*
* @return ( double )
*/
double R2R()
{
return mR2R;
}
/**
* Set Risk to Reward Ratio ...
*
* @param value: Double ...
*/
void R2R(double value)
{
//
if (value < 1)
{
value = 1;
}
//
mR2R = value;
ReConfigure();
}
/**
* Get Static Volume ...
*
* @return ( double )
*/
double Volume()
{
return mVolume;
}
/**
* Set Static Volume ...
*
* @param value: Double ...
*/
void Volume(double value)
{
//
if (value < 0.01)
{
value = 0.01;
}
//
mVolume = value;
ReConfigure();
}
/**
* Get Static Balance for Calculate Trade Volume ...
*
* @return ( double )
*/
double StaticBalance()
{
return mStaticBalance;
}
/**
* Set Static Balance for Calculate Trade Volume ...
*
* @param value: Argument 1
*/
void StaticBalance(double value)
{
//
if (value < 0)
{
value = 0;
}
//
mStaticBalance = value;
}
/**
* Get Balance Used In Each Trade ...
*
* @return ( double )
*/
double BalancePerTrade()
{
return mBalancePerTrade;
}
/**
* Set Balance Used In Each Trade ...
*
* @param value: Argument 1
*/
void BalancePerTrade(double value)
{
//
if (value < 0)
{
value = 0;
}
//
mBalancePerTrade = value;
}
/**
* Get Risk Percent Per Balance in Each Trade ...
*
* @return ( double )
*/
double RiskPercentPerBalance()
{
return mRiskPercentPerBalance;
}
/**
* Set Risk Percent Per Balance in Each Trade ...
*
* @param value: Double
*/
void RiskPercentPerBalance(double value)
{
//
if (value < 0)
{
value = 0;
}
//
mRiskPercentPerBalance = value;
ReConfigure();
}
/**
* Get Dynamic Risk Management State ...
*
* @return ( bool )
*/
bool DynamicRiskManagement()
{
return mDynamicRiskManagement;
}
/**
* Set Dynamic Risk Management State ...
*
* @param value: Boolean ...
*/
void DynamicRiskManagement(bool value)
{
//
mDynamicRiskManagement = value;
ReConfigure();
}
/**
* Get Use Dynamic Volume State ...
*
* @return ( bool )
*/
bool UseDynamicVolume()
{
return mUseDynamicVolume;
}
/**
* Set Use Dynamic Volume State ...
*
* @param value: Boolean ...
*/
void UseDynamicVolume(bool value)
{
//
mUseDynamicVolume = value;
ReConfigure();
}
/**
* Get Increase Volume Step ...
*
* @return ( double )
*/
double DynamicVolumeStep()
{
return mDynamicVolumeStep;
}
/**
* Set Increase Volume Step ...
*
* @param value: Double ...
*/
void DynamicVolumeStep(double value)
{
//
if (value < 0.01)
{
value = 0.01;
}
//
mDynamicVolumeStep = value;
ReConfigure();
}
/**
* Get Balance Factor for Generate Dynamic Volume ...
*
* @return ( double )
*/
double DynamicVolumeBalanceFactor()
{
return mDynamicVolumeBalanceFactor;
}
/**
* Set Balance Factor for Generate Dynamic Volume ...
*
* @param value: Double ...
*/
void DynamicVolumeBalanceFactor(double value)
{
//
if (value < 0)
{
value = 0;
}
//
mDynamicVolumeBalanceFactor = value;
ReConfigure();
}
/**
* Get Max Allowed Drawdown Percent for Open Trades ...
* 0 => Ignore ...
* min => 0 ...
* max => 100 ...
*
* @return ( double )
*/
double MaxAllowedDrawdownToOpenTrades()
{
return mMaxAllowedDrawdownToOpenTrades;
}
/**
* Set Max Allowed Drawdown Percent for Open Trades ...
*
* @param value: Double ...
* 0 => Ignore ...
* min => 0 ...
* max => 100 ...
*/
void MaxAllowedDrawdownToOpenTrades(double value)
{
//
if (value < 0)
{
value = 0;
}
//
if (value > 50)
{
value = 50;
}
//
mMaxAllowedDrawdownToOpenTrades = value;
ReConfigure();
}
/**
* Get Max Allowed SL for Pause Signalling Per Symbol ...
* 0 => Unlimited ...
*
* @return ( int )
*/
int MaxAllowedSLToPauseSignallingPerSymbol()
{
return mMaxAllowedSLToPauseSignallingPerSymbol;
}
/**
* Set Max Allowed SL for Pause Signalling Per Symbol ...
*
* @param value: Integer ...
* 0 => Unlimited ...
*/
void MaxAllowedSLToPauseSignallingPerSymbol(int value)
{
//
if (value < 0)
{
value = 0;
}
//
mMaxAllowedSLToPauseSignallingPerSymbol = value;
ReConfigure();
}
/**
* Get Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds ...
* 0 => Ignore ...
*
* @return ( int )
*/
int PauseSignallingAfterReachesMaxAllowedSLInSecconds()
{
return mPauseSignallingAfterReachesMaxAllowedSLInSecconds;
}
/**
* Set Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds ...
*
* @param value: Integer ...
* 0 => Ignore ...
*/
void PauseSignallingAfterReachesMaxAllowedSLInSecconds(int value)
{
//
if (value < 0)
{
value = 0;
}
//
mPauseSignallingAfterReachesMaxAllowedSLInSecconds = value;
ReConfigure();
}
//
// Protection Props ...
/**
* Get Allow Hedge Positions State ...
*
* @return ( bool )
*/
bool AllowHedging()
{
return mAllowHedging;
}
/**
* Set Allow Hedge Positions State ...
*
* @param value: Boolean ...
*/
void AllowHedging(bool value)
{
//
mAllowHedging = value;
ReConfigure();
}
/**
* Get Minimum Open Positions for Hedging ...
* 0 => Ignore ...
*
* @return ( int )
*/
int MinOpenTradesFroHedging()
{
return mMinOpenTradesFroHedging;
}
/**
* Set Minimum Open Positions for Hedging ...
*
* @param value: Integer ...
* 0 => Ignore ...
*/
void MinOpenTradesFroHedging(int value)
{
//
if (value < 0)
{
value = 0;
}
//
mMinOpenTradesFroHedging = value;
ReConfigure();
}
/**
* Get Minimum Volume Step for Hedging ...
* 0 => Ignore ...
*
* @return ( double )
*/
double HedgingMinVolumeStep()
{
return mHedgingMinVolumeStep;
}
/**
* Set Minimum Volume Step for Hedging ...
*
* @param value: Double ...
* 0 => Ignore ...
*/
void HedgingMinVolumeStep(double value)
{
//
if (value < 0)
{
value = 0;
}
//
if (value > 0 && value < 0.01)
{
value = 0.01;
}
//
if (value > 0 && value > 0.1)
{
value = 0.1;
}
//
mHedgingMinVolumeStep = value;
ReConfigure();
}
/**
* Get Minimum Required Profit Per Volume Step for Hedging ...
* 0 => Ignore ...
*
* @return ( double )
*/
double HedgeingMinRequiredProfitPerVolumeStep()
{
return mHedgeingMinRequiredProfitPerVolumeStep;
}
/**
* Set Minimum Required Profit Per Volume Step for Hedging ...
*
* @param value: Double ...
* 0 => Ignore ...
*/
void HedgeingMinRequiredProfitPerVolumeStep(double value)
{
//
if (value < 0)
{
value = 0;
}
//
mHedgeingMinRequiredProfitPerVolumeStep = value;
ReConfigure();
}
//
// Actions ...
/**
* Handle OnSignalRecieved Event ...
*
* @param signal: XSignal instance ...
* @param conditions: X121SMCStrategyConditions instance ...
*/
void HandleOnSignalRecieved(
XSignal &signal,
X121SMCStrategyConditions &conditions //
)
{
//
// Check Signal and Conditions Validations ...
//
if (!signal.IsValid())
{
return;
}
//
if (!conditions.IsValid())
{
return;
}
//
bool isLong = IsLong(signal.type);
//
// Notify When a Raw (Unfiltered) Signal Recieved
// if it's Provided ...
bool mAlertRawSignals = false;
if (mAlertRawSignals)
{
//
string msg = "Raw " + (IsLong(signal.type) ? "Long" : "Short") +
" Signal Recieved: (" + signal.provider + "," +
signal.symbol + "," +
ToString(signal.period) +
") ...";
//
Alert(msg);
}
//
// Apply Volume On Signal ...
ApplyVolumeOnSignal(signal);
//
// Chekc Signalling Enable or not ...
bool canContinue =
isLong
? AllowLong()
: AllowShort();
if (!canContinue)
{
return;
}
//
// TODO: Apply Filtering On Signal ...
bool isFiltered = false;
if (isFiltered)
{
//
mTradeHandler.Remove(signal);
return;
}
//
// Attach Conditions Summary to Signal ...
string conditionsSummary = conditions.GenerateSummary(
false,
false,
true,
false //
);
//
// TODO: Retrieve Conditions Summary based on Filter ...
signal.conditions = conditionsSummary;
//
datetime currentTime = TimeCurrent();
//
// Chack Allow Trades ...
bool allowTrade = AllowTrade();
if (allowTrade)
{
//
string startTime = StartTradeAt();
string endTime = StopTradeAt();
bool isTimePassed = IsTimeInRange(
TimeCurrent(),
startTime,
endTime //
);
//
if (isTimePassed)
{
//
// Execute Signal Using Trade Handler ...
ENUM_X_SIGNAL_EXECUTION_RESULT state;
bool isExecuted = mTradeHandler.ExecuteSignal(
signal,
conditions,
state,
false // ignore Policies ...
);
}
else
{
//
string msg = "Failed To Execute " +
(IsLong(signal.type)
? "Long"
: "Short") +
" Signal Recieved: (" +
signal.provider + "," +
signal.symbol + "," +
ToString(signal.period) +
") due Trading offTime ...";
//
Alert(msg);
}
}
else
{
//
// Only Alert Signals ...
string msg = (IsLong(signal.type)
? "Long"
: "Short") +
" Signal Recieved: (" +
signal.provider + "," +
signal.symbol + "," +
ToString(signal.period) +
") ...";
//
Alert(msg);
}
//
signal.Clean();
conditions.Clean();
}
//
// Override Actions ...
/**
* Apply Default Configurations ...
*/
void DefaultConfigure() override
{
//
// Commons ...
Slippage(10);
TagPrefix("");
MagicNumber(1694056);
//
// Symbol ...
SetSymbol(_Symbol);
SetPeriod(_Period);
MultiSymbol(false);
Symbols("EURUSDb,GBPUSDb,USDJPYb,USDCHFb,DowJones30,XAUUSDb");
//
// Signalling ...
Disabled(false);
AllowLong(true);
AllowShort(true);
//
string tag = GetTag();
//
// Alert ...
SetAlertPrefix(tag);
SetAlertLogAlerts(true);
SetAlertPushAlerts(true);
SetAlertMailAlerts(false);
SetAlertEnableAlerts(true);
SetAlertTerminalAlerts(false);
//
// Reports ...
ReportNewDays(true);
ReportNewWeeks(false);
ReportNewHours(false);
ReportNewMonths(false);
//
R2R(1);
//
// Volume Default Configurations ...
Volume(0.01);
UseDynamicVolume(false);
DynamicVolumeStep(0.01);
DynamicVolumeBalanceFactor(200);
//
RiskPercentPerBalance(0);
DynamicRiskManagement(false);
}
/**
* Vaslidate Inputs ...
*
* @return ( bool )
*/
bool ValidateInputs() override
{
//
bool result = false;
//
string errMessage = "";
//
bool isCommonValid = (
//
Slippage() > 0 &&
MagicNumber() > 0
//
);
if (!isCommonValid)
{
//
errMessage += "common configurations error;" + "\n";
}
//
// Checking Volume ...
bool isVolumeValid = true;
if (UseDynamicVolume())
{
//
isVolumeValid =
DynamicVolumeStep() > 0 &&
DynamicVolumeBalanceFactor() > 0;
if (!isVolumeValid)
{
errMessage += "Dynamic Volume configurations error;" + "\n";
}
}
isVolumeValid = isVolumeValid &&
Volume() > 0;
if (!isVolumeValid)
{
errMessage += "Static Volume configurations error;" + "\n";
}
//
result =
//
// Common ...
isCommonValid &&
//
// Volume Coniguration ...
isVolumeValid &&
//
// Otere ...
true
//
;
//
if (!result)
{
//
// Since here Logger not Initiallized, we Use Raw Print Command ...
errMessage = " Errors: \n" + errMessage;
Alert(errMessage);
}
//
return result;
}
//
// Initializers and DeInitializers ...
/**
* Initial EA Requirements ...
*
* @return ( bool )
*/
bool InitEA() override
{
//
bool result = true;
//
// Initialize Indicator Helpers ...
//
X121XCCInputs xccInputs;
xccInputs.Default();
xccInputs.showCandles = mShowCandles;
xccHelper = new XCX121XCCHelper();
result = xccHelper.Init(
_Symbol,
_Period,
xccInputs //
);
if (!result)
{
return result;
}
//
X121XCTInputs xctInputs;
xctInputs.Default();
xctHelper = new XCX121XCTHelper();
result = xctHelper.Init(
_Symbol,
_Period,
xctInputs //
);
if (!result)
{
return result;
}
//
// Configure Alerts ...
SetAlertPrefix(GetTag());
SetAlertEnableAlerts(GetAlertEnableAlerts());
SetAlertLogAlerts(GetAlertLogAlerts());
SetAlertMailAlerts(GetAlertMailAlerts());
SetAlertPushAlerts(GetAlertPushAlerts());
SetAlertTerminalAlerts(GetAlertTerminalAlerts());
//
// Create Trader Instance and Configure it ...
mTrader = new XCTrade(
Slippage(),
MagicNumber() //
);
mTrader.AddOnStopLossEventHandler(OnPositionSLEventListener);
mTrader.AddOnTakeProfitEventHandler(OnPositionTPEventListener);
mTrader.AddOnDealsChangedEventHandler(OnDealsChangedEventListener);
mTrader.AddOnOrdersChangedEventHandler(OnOrdersChangedEventListener);
mTrader.AddOnModifyPositionEventHandler(OnPositionModifiedEventListener);
mTrader.AddOnPositionsChangedEventHandler(OnPositionsChangedEventListener);
mTrader.AddOnForceClosePositionEventHandler(OnPositionForceCloseEventListener);
mTrader.AddOnPartialClosePositionEventHandler(OnPositionPartialCloseEventListener);
//
// Initialize Trade Handler ...
mTradeHandler = new XC121SMCTradeHandler(mTrader);
mTradeHandler.SaveTrades(false);
mTradeHandler.SaveSignals(false);
mTradeHandler.SaveConditions(false);
mTradeHandler.MaxAllowedSpread(MaxAllowedSpread());
//
ReConfigureTradeHandler();
//
// Parsers ...
XSymbolParser _symbolParser;
//
// Single Symbol ...
if (!MultiSymbol())
{
//
// Register Strategy ...
//
// Create Class Instance ...
XCX121SMCBaseStrategy *iX121SMCStrategy;
iX121SMCStrategy = new XCX121SMCStrategy(
_Symbol,
_Period //
);
//
iX121SMCStrategy.AddXSignalEventHandler(OnSignalEventListener);
//
ConfigureStrategy(iX121SMCStrategy);
RegisterStrategy(iX121SMCStrategy);
}
//
// Multi Symbol ...
else
{
//
// Parse Symbols ...
string symbols[];
int symbolsCount = SplitContent(
symbols,
Symbols() //
);
result = IsValidSize(symbolsCount);
if (!result)
{
return result;
}
//
for (int i = 0; i < symbolsCount; i++)
{
//
// Select Symbol ...
string iSymbol = symbols[i];
//
// Register Strategy Based On Symbol ...
//
// Parse Symbol ...
bool isEURUSD = _symbolParser.IsEURUSD(_Symbol);
bool isGBPUSD = _symbolParser.IsGBPUSD(_Symbol);
bool isEURGBP = _symbolParser.IsEURGBP(_Symbol);
bool isUSDCHF = _symbolParser.IsUSDCHF(_Symbol);
bool isEURCHF = _symbolParser.IsEURCHF(_Symbol);
bool isUSDJPY = _symbolParser.IsUSDJPY(_Symbol);
bool isEURJPY = _symbolParser.IsEURJPY(_Symbol);
bool isUSDCAD = _symbolParser.IsUSDCAD(_Symbol);
bool isEURCAD = _symbolParser.IsEURCAD(_Symbol);
bool isAUDUSD = _symbolParser.IsAUDUSD(_Symbol);
bool isEURAUD = _symbolParser.IsEURAUD(_Symbol);
bool isNZDUSD = _symbolParser.IsNZDUSD(_Symbol);
bool isEURNZD = _symbolParser.IsEURNZD(_Symbol);
//
// Check Symbol Can Register or not ...
bool canRegisterStrategy = true;
//
if (canRegisterStrategy)
{
//
// Create Class Instance ...
XCX121SMCBaseStrategy *iX121SMCStrategy;
iX121SMCStrategy = new XCX121SMCStrategy(
iSymbol,
_Period //
);
//
iX121SMCStrategy.AddXSignalEventHandler(OnSignalEventListener);
//
// Register Strategy ...
ConfigureStrategy(iX121SMCStrategy);
RegisterStrategy(iX121SMCStrategy);
}
}
//
Clean(symbols);
}
//
return result;
}
/**
* Destroy all Initialized EA Requirements ...
*/
void DestroyEA() override
{
//
ZeroMemory(xccHelper);
ZeroMemory(xctHelper);
ZeroMemory(mTradeHandler);
//
delete xccHelper;
delete xctHelper;
delete mTradeHandler;
//
Clean(mStrategies);
}
/**
* Call all Registered Strategies On Tick ...
*/
void HandleStrategiesOnTick() override
{
//
// Check Force Close ...
string forceCloseTimeStr = CloseAllTradesAt();
if (IsValid(forceCloseTimeStr))
{
//
datetime forceCloseTime = ParseDateTimeFromTimeString(forceCloseTimeStr);
bool canForceClose = IsTimeInRange(
TimeCurrent(),
forceCloseTime //
) &&
!mIsForceCloseAtTime;
if (canForceClose)
{
mIsForceCloseAtTime = mTradeHandler.ForceClose();
}
}
//
// Update Positions Data ...
mTradeHandler.UpdateData();
//
// Protect Positions ...
mTradeHandler.HandleProtection();
//
int count = ArraySize(mStrategies);
if (!IsValidSize(count))
{
return;
}
//
for (int i = 0; i < count; i++)
{
//
// Call Tick Handler Function ...
mStrategies[i].HandleTick();
}
}
/**
* Handle Strategies Guards ...
*/
void HandleStrategiesGuard() override
{
//
int count = ArraySize(mStrategies);
if (!IsValidSize(count))
{
return;
}
//
XPosition positions[];
int positionsCount = mTrader.GetPositions(
positions, // Result ...
NULL, // Symbol ...
NULL, // Provider ...
NULL, // Period ...
X_POSITION_TYPE_ALL // All Types ...
);
if (!IsValidSize(positionsCount))
{
return;
}
//
for (int i = 0; i < count; i++)
{
//
// Call Tick Handler Function ...
X121SMCGuard iGuards[];
bool hasGuards = mStrategies[i].HandleGuard(
iGuards,
positions //
);
if (hasGuards)
{
HandleGuards(iGuards);
}
}
//
Clean(positions);
}
//
// Event Handlers ...
/**
* Calls When a Deals Changed Triggered ...
*
* @param count: Integer, Number of Changes ...
*/
void HandleOnDealsChanged(int count) override
{
}
/**
* Calls When a Order Changed Triggered ...
*
* @param count: Integer, Number of Changes ...
*/
void HandleOnOrdersChanged(int count) override
{
}
/**
* Calls When a Positions Changed Triggered ...
*
* @param count: Integer, Number of Changes ...
*/
void HandleOnPositionsChanged(int count) override
{
//
if (IsValidSize(count))
{
mTradeHandler.HandleNewPosition();
}
}
/**
* Calls When a Position's SL Triggered ...
*
* @param deal: XDeal instance ...
*/
void HandleOnStopLossTriggered(const XDeal &deal) override
{
//
// Finish ...
mTradeHandler.Finish(deal);
//
HandleReportBalance();
}
/**
* Calls When a Position's TP Triggered ...
*
* @param deal: XDeal instance ...
*/
void HandleOnTakeProfitTriggered(const XDeal &deal) override
{
//
// Finish ...
mTradeHandler.Finish(deal);
//
bool useDynamicRiskManagement = DynamicRiskManagement();
if (useDynamicRiskManagement)
{
mTradeHandler.ResetSymbolInfo(deal.symbol);
}
//
HandleReportBalance();
}
/**
* Handle Force Close a Position ...
*
* @param ticket: Position Ticket ...
* @param position: XPosition ...
* @param comment: Closing Comment ...
*/
void HandleOnPositionForceClosed(
const ulong ticket,
const XPosition &position,
const string comment //
) override
{
//
// Finish ...
mTradeHandler.Finish(
ticket,
position,
comment //
);
//
HandleReportBalance();
}
/**
* Reset All Paused Symbols on Each New Days ...
*/
void HandleOnNewDay() override
{
//
mIsForceCloseAtTime = false;
mTradeHandler.ResumePausedSymbols();
}
/**
* Re Configure Materials on Properties Changed ...
*/
void ReConfigure() override
{
//
ReConfigureTradeHandler();
ReConfigureAllStrategies();
}
/**
* Generate Identifier Tag ...
*
* @return ( string )
*/
string GetTag() override
{
//
string result = NULL;
//
string tagPrefix = TagPrefix();
if (IsValid(tagPrefix))
{
result = tagPrefix;
}
else
{
result = "";
}
//
result =
XC121SMCExpertToken + result;
//
return result;
}
//
protected:
//
//
// Props ...
//
XC121SMCTradeHandler *mTradeHandler; // Trade Handler ...
XCX121SMCBaseStrategy *mStrategies[]; // Registere Strategies in EA ...
//
// Actions ...
/**
* Apply Volume Based On Configurations on Signal ...
*
* @param signal: XSignal instance
*/
void ApplyVolumeOnSignal(XSignal &signal)
{
//
if (signal.ignoreEAVolume)
{
return;
}
//
double staticVolume = Volume();
double fVolume = staticVolume > 0
? staticVolume
: 0.01;
//
double staticBalance = StaticBalance();
double accountBalance = mTrader.mAccount.GetBalance();
double balance = staticBalance > 0
? staticBalance
: accountBalance;
//
bool useDynamicVolume = UseDynamicVolume();
double balancePerTrade = BalancePerTrade();
double dynamicVolumeStep = DynamicVolumeStep();
double riskPercentPerBalance = RiskPercentPerBalance();
bool allowDynamicRiskManagement = DynamicRiskManagement();
double dynamicVolumeBalanceFactor = DynamicVolumeBalanceFactor();
//
// Apply Static Volume ...
bool allowStaticVolume = staticVolume > 0;
//
// Apply Dynamic Volume ...
bool aloowApplyDynamicVolume = useDynamicVolume &&
dynamicVolumeStep &&
dynamicVolumeBalanceFactor;
//
// Apply Risk Per Trade Volume ...
bool allowApplyRiskPerTradeVolume =
!aloowApplyDynamicVolume &&
riskPercentPerBalance > 0;
//
// Apply Balance Per Trade Volume ...
bool allowApplyBalacePerTradeVolume =
!aloowApplyDynamicVolume &&
!allowApplyRiskPerTradeVolume &&
balancePerTrade > 0;
//
// First Check Dynamic Volume ...
if (aloowApplyDynamicVolume)
{
//
// Dynamic Volume ...
double dVolume = mTrader.GetDynamicVolume(
signal.symbol,
dynamicVolumeBalanceFactor,
dynamicVolumeStep //
);
if (dVolume < fVolume)
{
dVolume = fVolume;
}
//
signal.volume = dVolume;
}
else if (allowApplyRiskPerTradeVolume)
{
//
double riskAmountPerBalance = (riskPercentPerBalance * balance) / 100;
//
double risk = signal.GetRisk();
double points = GetPoints(signal.symbol);
double riskInPoints = risk / points;
//
double volume = mTrader.mAccount.CalculateVolume(
signal.symbol,
riskAmountPerBalance,
riskInPoints //
);
if (volume <= 0)
{
volume = fVolume;
}
//
// Check Dynamic Risk Management ...
bool allowDynamicRiskManagement = DynamicRiskManagement();
if (allowDynamicRiskManagement)
{
//
// Calculate Dynamic Additional Risk Management Volume Multiplier ...
double mAdditionalRiskMultiplier = CalculateAdditionalVolumeMultiplier(signal);
if (mAdditionalRiskMultiplier < 1)
{
mAdditionalRiskMultiplier = 1;
}
//
volume *= mAdditionalRiskMultiplier;
}
//
signal.volume = volume;
}
else if (allowApplyBalacePerTradeVolume)
{
//
double risk = signal.GetRisk();
double points = GetPoints(signal.symbol);
double riskInPoints = risk / points;
//
double volume = mTrader.mAccount.CalculateVolume(
signal.symbol,
balancePerTrade,
riskInPoints //
);
if (volume <= 0)
{
volume = fVolume;
}
//
signal.volume = volume;
}
else if (allowStaticVolume)
{
signal.volume = staticVolume;
}
else
{
signal.volume = fVolume;
}
//
// Normalize Signal Volume ...
signal.volume = NormalizeVolume(
signal.volume,
signal.symbol //
);
}
/**
* Configure Startegy ...
*/
void ConfigureStrategy(XCX121SMCBaseStrategy *&strategy)
{
//
if (strategy == NULL)
{
return;
}
//
// Configure Alerts ...
strategy.SetAlertPrefix(GetTag());
strategy.SetAlertLogAlerts(GetAlertLogAlerts());
strategy.SetAlertMailAlerts(GetAlertMailAlerts());
strategy.SetAlertPushAlerts(GetAlertPushAlerts());
strategy.SetAlertEnableAlerts(GetAlertEnableAlerts());
strategy.SetAlertTerminalAlerts(GetAlertTerminalAlerts());
//
// Confiugre Signalling ...
//
strategy.R2R(R2R());
strategy.AllowLong(AllowLong());
strategy.AllowShort(AllowShort());
//
if (Disabled())
{
strategy.Disable();
}
else
{
strategy.Enable();
}
//
}
/**
* Register an Strategy in EA ...
*
* @param strategy: XCX121SMCBaseStrategy instance ...
*/
void RegisterStrategy(XCX121SMCBaseStrategy *strategy)
{
//
if (strategy == NULL)
{
return;
}
//
ArrayResize(
mStrategies,
ArraySize(mStrategies) + 1 //
);
//
mStrategies[ArraySize(mStrategies) - 1] = strategy;
}
/**
* Re Configure All Registered Strategies ...
*/
void ReConfigureAllStrategies()
{
//
int count = ArraySize(mStrategies);
if (!IsValidSize(count))
{
return;
}
//
for (int i = 0; i < count; i++)
{
//
ConfigureStrategy(mStrategies[i]);
}
}
/**
* Re Configure Trade Handler ...
*/
void ReConfigureTradeHandler()
{
//
if (mTradeHandler == NULL)
{
return;
}
//
// Configure Alerts ...
mTradeHandler.SetAlertPrefix(GetTag());
mTradeHandler.SetAlertEnableAlerts(GetAlertEnableAlerts());
mTradeHandler.SetAlertLogAlerts(GetAlertLogAlerts());
mTradeHandler.SetAlertMailAlerts(GetAlertMailAlerts());
mTradeHandler.SetAlertPushAlerts(GetAlertPushAlerts());
mTradeHandler.SetAlertTerminalAlerts(GetAlertTerminalAlerts());
//
mTradeHandler.AllowLong(AllowLong());
mTradeHandler.AllowShort(AllowShort());
mTradeHandler.MaxAllowedLongs(MaxAllowedLongs());
mTradeHandler.MaxAllowedShorts(MaxAllowedShorts());
mTradeHandler.UseMaxAllowedSignalsPerSymbol(UseMaxAllowedSignalsPerSymbol());
mTradeHandler.LastPositionProfitForAcceptNextInPoint(LastPositionProfitForAcceptNextInPoint());
mTradeHandler.DelaysBetweenTwoSignalsInBar(DelaysBetweenTwoSignalsInBar());
mTradeHandler.MaxAllowedSpread(MaxAllowedSpread());
mTradeHandler.MaxAllowedDrawdownToOpenTrades(MaxAllowedDrawdownToOpenTrades());
mTradeHandler.MaxAllowedSLToPauseSignallingPerSymbol(MaxAllowedSLToPauseSignallingPerSymbol());
mTradeHandler.PauseSignallingAfterReachesMaxAllowedSLInSecconds(PauseSignallingAfterReachesMaxAllowedSLInSecconds());
mTradeHandler.AllowHedging(AllowHedging());
mTradeHandler.MinOpenTradesFroHedging(MinOpenTradesFroHedging());
mTradeHandler.HedgingMinVolumeStep(HedgingMinVolumeStep());
mTradeHandler.HedgeingMinRequiredProfitPerVolumeStep(HedgeingMinRequiredProfitPerVolumeStep());
}
//
private:
//
//
// Props ...
//
bool mShowCandles; // Show Candles ...
//
// Signalling Props ...
bool mAllowLong; // Allow Long Signals ...
bool mAllowShort; // Allow Short Signals ...
int mMaxAllowedLongs; // Max Allowed Long Signals ...
int mMaxAllowedShorts; // Max Allowed Short Signals ...
bool mUseMaxAllowedSignalsPerSymbol; // Use Max Allowed Signal Types Per Symbol ...
double mLastPositionProfitForAcceptNextInPoint; // Last Position Profit In Points for Accept new Signal ...
int mDelaysBetweenTwoSignalsInBar; // Delay between two Signals in Bars ...
double mMaxAllowedSpread; // Max Allowed Spread for Signalling ...
//
// Trade ...
bool mAllowTrade; // Allow Open Trade On Signals ...
string mStartTradeAt; // Enable Trade on Signals on Time ...
string mStopTradeAt; // Enable Trade on Signals on Time ...
string mCloseAllTradesAt; // Enable Close All Trades on Signals on Time ...
//
bool mIsForceCloseAtTime;
//
// Risk Management Props ...
double mR2R; // Signallers Risk to Reward Ratio ...
double mVolume; // Static Volume ...
double mStaticBalance; // Static Balance for Calculate Trade Volume ...
double mBalancePerTrade; // Balance Used in Each Trade ...
double mRiskPercentPerBalance; // Risk Percent Per Balance in Each Trade ...
bool mDynamicRiskManagement; // Dynamic Risk Management ...
bool mUseDynamicVolume; // Use Dynamic Volume ...
double mDynamicVolumeStep; // Increase Volume Step ...
double mDynamicVolumeBalanceFactor; // Balance Factor for Generate Dynamic Volume ...
double mMaxAllowedDrawdownToOpenTrades; // Max Allowed Drawdown for Open Trades ...
int mMaxAllowedSLToPauseSignallingPerSymbol; // Max Allowed SL for Pause Signalling Per Symbol ...
int mPauseSignallingAfterReachesMaxAllowedSLInSecconds; // Pause Signalling Per Symbol afte Max Allowed SL Reached In Seconds ...
//
// Protection Props ...
bool mAllowHedging; // Allow Hedge Positions ...
int mMinOpenTradesFroHedging; // Minimum Open Positions for Hedging ...
double mHedgingMinVolumeStep; // Minimum Volume Step for Hedging ...
double mHedgeingMinRequiredProfitPerVolumeStep; // Minimum Required Profit Per Volume Step for Hedging ...
//
double CalculateAdditionalVolumeMultiplier(XSignal &signal)
{
//
double result = 0;
//
if (!signal.IsValid())
{
return result;
}
//
X121SMCSymbolPositionInfo info;
bool hasInfo = mTradeHandler.GetSymbolInfo(
signal.symbol,
info //
);
if (!hasInfo)
{
return result;
}
//
if (info.countedSLs >= 2)
{
result = (info.countedSLs / 2) + 1;
}
//
return result;
}
/**
* Handle Guard Actions ...
*
* @param guards: X121SMCGuard instance Collection ...
*/
void HandleGuards(X121SMCGuard &guards[])
{
//
int count = ArraySize(guards);
if (!HasChild(guards))
{
return;
}
//
for (int i = 0; i < count; i++)
{
//
X121SMCGuard iGuard = guards[i];
//
if (!iGuard.IsValid())
{
continue;
}
//
// Here we Have to Handle Guard Actions ...
//
// Close ...
bool canClose =
NotEmpty(iGuard.ticket) &&
iGuard.action == X_121_SMC_GUARD_ACTION_CLOSE;
//
// Close All ...
bool canCloseAll = iGuard.action == X_121_SMC_GUARD_ACTION_CLOSE_ALL;
//
// Close Longs ...
bool canCloseLongs = iGuard.action == X_121_SMC_GUARD_ACTION_CLOSE_LONGS;
//
// Close Shorts ...
bool canCloseShorts = iGuard.action == X_121_SMC_GUARD_ACTION_CLOSE_SHORTS;
//
// Partial Close ...
bool canPartialClose =
NotEmpty(iGuard.ticket) &&
iGuard.volumeMultiplier > 0 &&
iGuard.action == X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE;
//
// Trail Stop ...
bool canTrailStop =
iGuard.sl > 0 &&
NotEmpty(iGuard.ticket) &&
iGuard.action == X_121_SMC_GUARD_ACTION_TRAIL_STOP;
//
// Trail Target ...
bool canTrailTarget =
iGuard.tp > 0 &&
NotEmpty(iGuard.ticket) &&
iGuard.action == X_121_SMC_GUARD_ACTION_TRAIL_TARGET;
//
// Hedge ...
bool canHedge = iGuard.action == X_121_SMC_GUARD_ACTION_HEDGE;
//
// Check is Guard Valid ...
bool isValidGuardAction =
canHedge ||
canClose ||
canCloseAll ||
canTrailStop ||
canCloseLongs ||
canTrailTarget ||
canCloseShorts ||
canPartialClose;
if (!isValidGuardAction)
{
continue;
}
//
// Now we Sure to Have a Valid Guard ...
// Start to o Guard Actions ...
//
// Close All ...
if (canCloseAll)
{
//
XPosition positions[];
int positionsCount =
mTrader
.GetPositions(
positions, // Result ...
iGuard.symbol,
iGuard.provider,
NULL, // Period ...
X_POSITION_TYPE_ALL, // All Types ...
true // Filter by Magic ...
);
if (IsValidSize(positionsCount))
{
//
string comment = "Guard Close All ...";
string message = "Guard Close All (" + ToString(positionsCount) + ") Positions Successfully ...";
int forceClosed = mTradeHandler.ForceClose(
positions,
comment,
message //
);
//
if (forceClosed)
{
RestEA(120 * 60);
}
}
}
//
// Close Longs ...
if (canCloseLongs)
{
//
XPosition longPositions[];
XPosition shortPositions[];
mTrader
.GetPositions(
longPositions, // Result ...
shortPositions, // Result ...
iGuard.symbol,
iGuard.provider,
NULL, // Period ...
true // Filter by Magic ...
);
//
int longPositionsCount = ArraySize(longPositions);
bool hasLongPositions = IsValidSize(longPositionsCount);
//
int shortPositionsCount = ArraySize(shortPositions);
bool hasShortPositions = IsValidSize(shortPositionsCount);
//
if (hasLongPositions)
{
//
string comment = "Guard Close Longs ...";
string message = "Guard Close (" + ToString(longPositionsCount) + ") Long Positions Successfully ...";
bool isClosed = mTradeHandler.ForceClose(
longPositions,
comment,
message //
);
//
if (isClosed)
{
RestEA(120 * 60);
}
}
}
//
// Close Shorts ...
if (canCloseShorts)
{
//
XPosition longPositions[];
XPosition shortPositions[];
mTrader
.GetPositions(
longPositions, // Result ...
shortPositions, // Result ...
iGuard.symbol,
iGuard.provider,
NULL, // Period ...
true // Filter by Magic ...
);
//
int longPositionsCount = ArraySize(longPositions);
bool hasLongPositions = IsValidSize(longPositionsCount);
//
int shortPositionsCount = ArraySize(shortPositions);
bool hasShortPositions = IsValidSize(shortPositionsCount);
//
if (hasShortPositions)
{
//
string comment = "Guard Close Shorts ...";
string message = "Guard Close (" + ToString(shortPositionsCount) + ") Short Positions Successfully ...";
bool isClosed = mTradeHandler.ForceClose(
shortPositions,
comment,
message //
);
//
if (isClosed)
{
RestEA(120 * 60);
}
}
}
//
// Close ...
if (canClose)
{
//
XPosition iPosition;
bool hasPosition = mTrader.GetPosition(
iGuard.ticket,
iPosition //
);
//
bool isLong = IsLong(iPosition.type);
//
if (hasPosition)
{
//
XPosition positions[];
AddRef(
iPosition,
positions //
);
//
string comment = "Guard Close ...";
string message = "Guard Close " + (isLong ? "Long" : "Short") + " Position: (" + ToString(iGuard.ticket) + ") Successfully ...";
bool isClosed = mTradeHandler.ForceClose(
positions,
comment,
message //
);
//
if (isClosed)
{
RestEA(120 * 60);
}
}
}
//
// Partial Close ...
if (canPartialClose)
{
//
XPosition iPosition;
bool hasPosition = mTrader.GetPosition(
iGuard.ticket,
iPosition //
);
//
bool isLong = IsLong(iPosition.type);
//
if (hasPosition)
{
//
// Normalize Volume Multiplier ...
double vMult = iGuard.volumeMultiplier;
if (vMult > 0.5)
{
vMult = 0.5;
}
if (vMult < 0)
{
vMult = 0.5;
}
//
// Calculate and Normalize Volume ...
double volume = iPosition.volume * iGuard.volumeMultiplier;
volume = NormalizeVolume(
volume,
iPosition.symbol //
);
//
string comment = "Guard Partially Closed: " + ToString(volume) + " ...";
string message = "Guard Partially Closed " + (isLong ? "Long" : "Short") + ": " + ToString(volume) + " Successfully ...";
bool isModified = mTrader.ClosePartial(
iPosition.ticket,
volume,
comment //
);
if (isModified)
{
//
mTradeHandler.Alert(message);
//
if (volume == iPosition.volume)
{
//
mTradeHandler.Finish(
iPosition.ticket,
iPosition,
comment //
);
//
RestEA(120 * 60);
}
}
}
}
//
// Hedge ...
if (canHedge)
{
//
XPosition positions[];
int positionsCount =
mTrader
.GetPositions(
positions, // Result ...
iGuard.symbol,
iGuard.provider,
NULL, // Period ...
X_POSITION_TYPE_ALL, // All Types ...
true // Filter by Magic ...
);
if (IsValidSize(positionsCount))
{
//
int longs = 0;
double longProfits = 0;
double longVolumes = 0;
//
int shorts = 0;
double shortProfits = 0;
double shortVolumes = 0;
CountPositions(
positions,
longs,
longProfits,
longVolumes,
shorts,
shortProfits,
shortVolumes //
);
//
int count = longs + shorts;
double profits = longProfits + shortProfits;
double volumes = longVolumes + shortVolumes;
//
bool canDoHedge =
count > 0 &&
profits > 0 &&
volumes > 0;
if (canDoHedge)
{
//
string comment = "Guard Hedge ...";
string message = "Guard Hedge (" + ToString(count) + ") Positions by: (" + ToString(profits) + ") Successfully ...";
bool isClosed = mTradeHandler.ForceClose(
positions,
comment,
message //
);
//
if (isClosed)
{
RestEA(120 * 60);
}
}
}
}
//
// Trail Stop ...
if (canTrailStop)
{
//
XPosition iPosition;
bool hasPosition = mTrader.GetPosition(
iGuard.ticket,
iPosition //
);
//
bool isLong = IsLong(iPosition.type);
//
bool canDoTrail =
hasPosition &&
iPosition.profit > 0 &&
isLong
? iPosition.price > iGuard.sl &&
(iPosition.sl == 0 ||
iPosition.sl < iGuard.sl)
: iPosition.price < iGuard.sl &&
(iPosition.sl == 0 ||
iPosition.sl > iGuard.sl);
if (canDoTrail)
{
//
string comment = "Guard Trail Stop ...";
string message = "Guard Trail " + (isLong ? "Long" : "Short") + " Position: (" + ToString(iGuard.ticket) + ") Stop Successfully ...";
bool isModified = mTrader.Modify(
iPosition.ticket,
iGuard.sl,
iPosition.tp,
comment //
);
if (isModified)
{
mTradeHandler.Alert(message);
}
}
}
//
// Trail Target ...
if (canTrailTarget)
{
//
XPosition iPosition;
bool hasPosition = mTrader.GetPosition(
iGuard.ticket,
iPosition //
);
//
bool isLong = IsLong(iPosition.type);
//
bool canDoTrail =
hasPosition &&
iGuard.tp != iPosition.tp &&
isLong
? iGuard.tp > iPosition.price
: iGuard.tp < iPosition.price;
if (canDoTrail)
{
//
string comment = "Guard Trail Target ...";
string message = "Guard Trail " + (isLong ? "Long" : "Short") + " Position: (" + ToString(iGuard.ticket) + ") Target Successfully ...";
bool isModified = mTrader.Modify(
iPosition.ticket,
iPosition.sl,
iGuard.tp,
comment //
);
if (isModified)
{
mTradeHandler.Alert(message);
}
}
}
}
//
Clean(guards);
Clean(guards);
}
//
void RestEA(int seconds)
{
//
}
//
};
//