2458 lines
60 KiB
Plaintext
2458 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()
|
|
{
|
|
}
|
|
|
|
//
|
|
// 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();
|
|
}
|
|
|
|
/**
|
|
* Get Minimum Spread Verification for Signalling ...
|
|
* 0 => Ignore ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int MinRequiredVerificationForSpreadPass()
|
|
{
|
|
return mMinRequiredVerificationForSpreadPass;
|
|
}
|
|
|
|
/**
|
|
* Set Minimum Spread Verification for Signalling ...
|
|
*
|
|
* @param value: Integer ...
|
|
* 0 => Ignore ...
|
|
*/
|
|
void MinRequiredVerificationForSpreadPass(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mMinRequiredVerificationForSpreadPass = 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
|
|
{
|
|
//
|
|
// 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();
|
|
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);
|
|
|
|
//
|
|
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());
|
|
strategy.MaxAllowedSpread(20);
|
|
// strategy.MaxAllowedSaveTicks(150);
|
|
// strategy.MinRequiredTicksForSpreadPass(100);
|
|
|
|
//
|
|
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 ...
|
|
|
|
//
|
|
// 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 ...
|
|
int mMinRequiredVerificationForSpreadPass; // Minimum Spread Verification 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 (!IsValidSize(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)
|
|
{
|
|
//
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
// |