/////////////////////////////////////////////////////// // // 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 (!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) { // } // }; //