diff --git a/Classes/x-saherelm.x-chart.helper.class.mq5 b/Classes/x-saherelm.x-chart.helper.class.mq5 index 0f120152..b5c3325f 100644 --- a/Classes/x-saherelm.x-chart.helper.class.mq5 +++ b/Classes/x-saherelm.x-chart.helper.class.mq5 @@ -33,11 +33,30 @@ class XCChartHelper : public XCBase // // Constructor ... - XCChartHelper(ulong _chartId = 0) + XCChartHelper( + ulong _chartId = 0, + string _symbol = NULL, + ENUM_TIMEFRAMES _period = NULL) { // - // Normalize Chart ID ... - mChartID = NormalizeChartId(_chartId); + bool canSetSymbolPeriod = + IsSpecifiedValid(_symbol) && + IsSpecifiedValid(_period); + + // + // Normalize ... + if (!canSetSymbolPeriod) + { + // + mChartID = NormalizeChartId(_chartId); + mSymbol = NormalizeSymbol(_symbol); + mPeriod = NormalizePeriod(_period); + } + else + { + // + SetSymbolPeriod(mSymbol, mPeriod); + } } // @@ -181,7 +200,16 @@ class XCChartHelper : public XCBase ENUM_TIMEFRAMES period // ) { - return (ChartSetSymbolPeriod(mChartID, symbol, period)); + bool result = (ChartSetSymbolPeriod(mChartID, symbol, period)); + if (result) + { + // + mSymbol = symbol; + mPeriod = period; + } + + // + return result; } /** @@ -644,6 +672,23 @@ class XCChartHelper : public XCBase return has; } + ulong Open() + { + // + mChartID = ChartOpen(mSymbol, mPeriod); + return (mChartID); + } + + void Close() + { + // + if (mChartID != -1 && mChartID != 0) + { + ChartClose(mChartID); + mChartID = 0; + } + } + // // Properties ... @@ -819,7 +864,9 @@ class XCChartHelper : public XCBase // Props ... // - ulong mChartID; // Chart ID ... + ulong mChartID; // Chart ID ... + string mSymbol; // Chart Symbol ... + ENUM_TIMEFRAMES mPeriod; // Chart Period ... }; // \ No newline at end of file diff --git a/Classes/x-saherelm.x-expert.class.mq5 b/Classes/x-saherelm.x-expert.class.mq5 new file mode 100644 index 00000000..ab3942bb --- /dev/null +++ b/Classes/x-saherelm.x-expert.class.mq5 @@ -0,0 +1,2816 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class +// ------------------------------------------------- +// Name: XCBaseExpret ... +// Description: Base Expert Class ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm Base Expert Class" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Classes/x-saherelm.x-alert.class.mq5" +#include "../Classes/x-saherelm.x-chart.helper.class.mq5" +#include "../Classes/x-saherelm.x-guard.class.mq5" +#include "../Classes/x-saherelm.x-signaller.class.mq5" +#include "../Classes/x-saherelm.x-trade-manager.class.mq5" +#include "../Classes/x-saherelm.x-volume.class.mq5" + +// +// Import Chart Objects ... +#include +#include +#include +#include + +// +// Definitions ... + +// +// Implementation ... +class XCBaseExpert : public XCBase +{ + // + // Public ... + public: + // + // Props ... + + // + // Common ... + long eaMagicNumber; // Magic Number + int eaSlippage; // Slippgae + string eaLogSuffix; // Log Suffix + + // + // Symbol Configurations ... + string eaSymbolConfiguration; // Symbol Configurations ... + + // + // Management ... + bool eaAllowGuards; // Allow Guards + bool eaAllowTrade; // Allow Trade on Signals + bool eaAllowLongs; // Allow Long Trades + bool eaAllowShorts; // Allow Short Trades + double eaMaxAllowedDrawdownFactor; // Max Allowed DrawDown for Trade + + // + // Volume ... + ENUM_X_VOLUME_SELECT_TYPE eaVolumeSelect; // Volume Applying Type + double eaStaticVoluem; // Static Volume + double eaDynamicVolumeStepBalance; // Step of Balance for Increase Volume + double eaDynamicVolumeStepVolume; // Step of Volume Increasing + double eaConstantRiskBalance; // Constant Risk Balance per Trade + double eaConstantPercent; // Constant Percent of Balance Per Trade + double eaConstantBalance; // Constant Balance for Calculations + + // + // Alert ... + bool eaEnableAlerts; // Enable Alerts + bool eaSaveAlerts; // Save Alerts + bool eaLogAlerts; // Log Alerts + bool eaMailAlerts; // Mail Alerts + bool eaPushAlerts; // Push Alerts + bool eaTerminalAlerts; // Terminal Alerts + + // + // Reports ... + bool eaReportNewMonths; // Report New Month + bool eaReportNewWeeks; // Report New Weeks + bool eaReportNewDays; // Report New Days + bool eaReportNewHours; // Report New Hours + bool eaReportTrades; // Report Trades + bool eaReportSignals; // Report Signals + bool eaReportProtector; // Report Protector Actions + bool eaReportRestrictions; // Report Restrictions + bool eaReportAfterTradesBalance; // Report Balance after a Trade Finished + + // + // Collector ... + bool eaSaveTrades; // Save Trades + bool eaSaveSignals; // Save Signals + bool eaSaveWins; // Save Winning Conditions + bool eaSaveLosts; // Save Lost Conditions + bool eaSaveRestrictions; // Save Restriction Reports + + // + // GUI Management Panel ... + bool eaShowPanel; // Show Management Panel + double eaPanelAllowedTPSLStep; // Value for Change TP/SL in Each Step + double eaPanelMinAllowedRiskInPoint; // Min Allowed Risk in Point + double eaPanelRiskInPoint; // Risk in Point per Trades + double eaPanelRiskToRewardRatio; // Risk To Reward per Trades + double eaPanelVolume; // Default volume Per Trade + + // + // Requirements ... + + // + XCAlert *eaAlert; // EA Scope Alert Handler ... + XCVolume *eaVolume; // EA Scope Voluem Handler ... + XCGuard *eaGuard; // EA Scope Guard Handler ... + XCTrade *eaTrader; // EA Scope Trade Handler ... + XCTradeManager *eaTradeManager; // EA Scope Trade Handler ... + XTimeTracker eaTimeTracker; // EA Scope Time Tracker ... + + // + // Specified Event Handlers ... + TOnGuarded onGuardedEventHandler; + TCanAnalyse canAnalyseEventHandler; + TCheckForGuard checkForGuardEventHandler; + + // + // Tools / Actions / Handlers ... + + // + // Expert Advisor Event Handlers ... + + /** + * Handle Initialization of Expert ... + * + * @return ( bool ) + */ + bool HandleOnInit() + { + // + bool result = false; + + // + // Validate Inputs ... + result = ValidateInputs(); + if (!result) + { + return result; + } + + // + int count = 0; + bool has = false; + + // + // Initialize Alert Handler ... + eaAlert = new XCAlert(); + eaAlert.SetPrefix(eaLogSuffix); + eaAlert.SetLogAlerts(eaLogAlerts); + eaAlert.SetMailAlerts(eaMailAlerts); + eaAlert.SetPushAlerts(eaPushAlerts); + eaAlert.SetSaveAlerts(eaSaveAlerts); + eaAlert.SetEnableAlerts(eaEnableAlerts); + eaAlert.SetTerminalAlerts(eaTerminalAlerts); + + // + // Initialize Volume Manager ... + eaVolume = new XCVolume(); + result = eaVolume.Init( + eaVolumeSelect, + eaStaticVoluem, + eaDynamicVolumeStepBalance, + eaDynamicVolumeStepVolume, + eaConstantRiskBalance, + eaConstantPercent, + eaConstantBalance // + ); + if (!result) + { + return result; + } + + // + // Initialize Trader ... + eaTrader = new XCTrade( + eaSlippage, + eaMagicNumber, + 0, + 0, + eaMaxAllowedDrawdownFactor // + ); + + // + // Trade Handler Attachments ... + + // + // Position Modifiy Event Handlers ... + count = ArraySize(mOnModifyEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnModifyPositionEventHandler(mOnModifyEventHandlers[i]); + } + } + + // + // Position Stop Loss Event Handlers ... + count = ArraySize(mStopLossEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnStopLossEventHandler(mStopLossEventHandlers[i]); + } + } + + // + // Position Take Profit Event Handlers ... + count = ArraySize(mTakeProfitEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnTakeProfitEventHandler(mTakeProfitEventHandlers[i]); + } + } + + // + // Position Force Close Event Handlers ... + count = ArraySize(mOnForceCloseEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnForceClosePositionEventHandler(mOnForceCloseEventHandlers[i]); + } + } + + // + // Deals Changed Event Handlers ... + count = ArraySize(mDealsChangedEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnDealsChangedEventHandler(mDealsChangedEventHandlers[i]); + } + } + + // + // Orders Changed Event Handlers ... + count = ArraySize(mOrdersChangedEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnOrdersChangedEventHandler(mOrdersChangedEventHandlers[i]); + } + } + + // + // Positions Changed Event Handlers ... + count = ArraySize(mPositionsChangedEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnPositionsChangedEventHandler(mPositionsChangedEventHandlers[i]); + } + } + + // + // Trade Changed Event Handlers ... + count = ArraySize(mTradeStateChangedEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnTradeStateChangedEventHandler(mTradeStateChangedEventHandlers[i]); + } + } + + // + // Postion Partially Close Event Handlers ... + count = ArraySize(mOnPartialCloseEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnPartialClosePositionEventHandler(mOnPartialCloseEventHandlers[i]); + } + } + + // + // Initialize Guard Handler ... + eaGuard = new XCGuard( + eaAlert, + eaTrader // + ); + + // + // Attach Event Handler ... + eaGuard.onGuardEventListener = onGuardedEventHandler; + + // + // Initialize Trae Manager ... + eaTradeManager = new XCTradeManager( + eaAlert, + eaTrader, + eaVolume, + eaGuard // + ); + + // + // Configuring Trade Manager ... + + // + // Attache Check For Guard Event Listener ... + eaTradeManager.checkForGuardEventListener = checkForGuardEventHandler; + + // + eaTradeManager.SaveWins(eaSaveWins); + eaTradeManager.SaveLosts(eaSaveLosts); + eaTradeManager.SaveTrades(eaSaveTrades); + eaTradeManager.SaveSignals(eaSaveSignals); + eaTradeManager.SaveRestrictions(eaSaveRestrictions); + + // + // Setting Trade Reports ... + eaTradeManager + .SetTradeReports( + eaReportTrades, + eaReportSignals, + eaReportProtector, + eaReportRestrictions, + eaReportAfterTradesBalance // + ); + + // + // Setting Trade Permissions ... + eaTradeManager + .SetTradePermissions( + eaAllowTrade, + eaAllowLongs, + eaAllowShorts // + ); + + // + // Setting Symbol Configuration ... + XSymbolTradeConfig symbolConfigurations[]; + eaTradeManager.SetSymbolConfigurations(eaSymbolConfiguration); + count = eaTradeManager.FillSymbolConfigurations(symbolConfigurations); + has = IsValidSize(count); + if (has) + { + // + // Configure Signallers ... + for (int i = 0; i < count; i++) + { + // + // Register Signallers ... + PrepareSignallers(symbolConfigurations[i]); + } + } + SpecifiedClean(symbolConfigurations); + + // + result = InitPanel(); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Handle De Initialization of Expert ... + */ + void HandleOnDeInit() + { + // + DestroyPanel(); + + // + delete eaTrader; + ZeroMemory(eaTrader); + + // + delete eaGuard; + ZeroMemory(eaGuard); + + // + delete eaVolume; + ZeroMemory(eaVolume); + + // + delete eaTradeManager; + ZeroMemory(eaTradeManager); + + // + eaTimeTracker.Clean(); + + // + SpecifiedClean(eaSignallers); + SpecifiedClean(mOnSignalEventHandlers); + SpecifiedClean(mOnModifyEventHandlers); + SpecifiedClean(mStopLossEventHandlers); + SpecifiedClean(mTakeProfitEventHandlers); + SpecifiedClean(mOnForceCloseEventHandlers); + SpecifiedClean(mDealsChangedEventHandlers); + SpecifiedClean(mOrdersChangedEventHandlers); + SpecifiedClean(mOnPartialCloseEventHandlers); + SpecifiedClean(mPositionsChangedEventHandlers); + SpecifiedClean(mTradeStateChangedEventHandlers); + + // + string message = "DeInitialized Successfully ..."; + eaAlert.SendAlert(message); + + // + delete eaAlert; + ZeroMemory(eaAlert); + } + + /** + * Handle Tick ... + */ + void HandleOnTick() + { + // + // Update GUI Panel ... + UpdatePanel(); + + // + // Time Report ... + HandleTimeReport(); + + // + // Manage Trades ... + eaTradeManager.Manage(); + + // + int count = ArraySize(eaSignallers); + bool has = IsValidSize(count); + if (!has) + { + return; + } + + // + // Loop through Signallers ... + for (int i = 0; i < count; i++) + { + // + // Calling Process Ticks on Signaller ... + eaSignallers[i].OnTick(0); + } + + // + HandleOnTickAdditional(); + } + + /** + * Handle Trade ... + */ + void HandleOnTrade() + { + eaTrader.HandleOnTrade(); + } + + /** + * Handle Timer ... + */ + void virtual HandleOnTimer() + { + } + + /** + * Handle Chart Event ... + * + * @param id: int, Event id ... + * @param lparam: long, Event Long Parameter ... + * @param dparam: double, Event Double Parameter ... + * @param sparam: string, Event String Parameter ... + */ + void virtual HandleOnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // + ) + { + } + + // + // Event Triggered Listeners ... + + /** + * Handle New Signal Recieved ... + * + * @param signal: XSignal, Recieved Signal ... + */ + void HandleOnSignalTriggered(XSignal &signal) + { + eaTradeManager.HandleSignal(signal); + } + + /** + * Check For Guard Event Handler ... + * + * @param guards: XGuard[] + * + * @return ( int ) + */ + int CheckForGuardTriggered(XGuard &guards[]) + { + // + int result = 0; + + // + if (!HasChild(eaSignallers)) + { + return result; + } + + // + int count = ArraySize(eaSignallers); + for (int i = 0; i < count; i++) + { + // + XGuard iGuards[]; + int iGuardsCount = eaSignallers[i].CheckForGuard(iGuards); + if (IsValidSize(iGuardsCount)) + { + // + Copy( + iGuards, + guards, + false // + ); + } + + // + SpecifiedClean(iGuards); + } + + // + result = ArraySize(guards); + + // + return result; + } + + /** + * Handle Guard Events ... + * + * @param action: ENUM_X_GUARD_ACTIONS + * @param positions: XPosition[] + */ + void OnGuardedTriggered( + ENUM_X_GUARD_ACTIONS action, + XPosition &positions[] // + ) + { + eaTradeManager.HandleGuardEvent(action, positions); + } + + /** + * Check Can Analyse Market based on Time ... + * + * @param symbol: string, Specified Symbol ... + * @param period: ENUM_TIMEFRAMES, Specified Period ... + * @param time: datetime, Specified Time ... + * + * @return ( bool ) + */ + bool HandleCanAnalyseEventTriggered( + string symbol, + ENUM_TIMEFRAMES period, + datetime time // + ) + { + // + return eaTradeManager.CanAnalyse( + symbol, + period, + time // + ); + } + + // + // Trade Event Handlers ... + + /** + * Handle Stop Loss Event Triggered ... + * + * @param deal: XDeal instance refrence, provides Triggered Deal info ... + */ + void virtual HandleOnStopLossTriggered(const XDeal &deal) + { + // + eaTradeManager.HandleSL(deal); + UpdatePanelPositionButtons(); + } + + /** + * Handle Take Profit Event Triggered ... + * + * @param deal: XDeal instance refrence, provides Triggered Deal info ... + */ + void virtual HandleOnTakeProfitTriggered(const XDeal &deal) + { + // + eaTradeManager.HandleTP(deal); + UpdatePanelPositionButtons(); + } + + /** + * Handle Position Force Closed Event ... + * + * @param ticket: ulong, triggered Positions ticket ... + * @param position: XPosition instance refrence, Triggered Position ... + * @param comment: string, Comment ... + */ + void virtual HandleOnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // + ) + { + // + eaTradeManager.HandleForceClose(position); + UpdatePanelPositionButtons(); + } + + /** + * Handle Position Partially Closed Event ... + * + * @param ticket: ulong, triggered Positions ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ + void virtual HandleOnPositionPartialClosed( + const ulong ticket, + const double profit, + const string comment // + ) + { + // + eaTradeManager.HandlePartiallyClosed( + ticket, + profit, + comment // + ); + } + + /** + * Handle Deals Changed ... + * + * @param count: int, number of changes ... + * if the count is positive, means new added ... + * if the count is negative, means removed ... + */ + void virtual HandleOnDealsChanged(int count) + { + } + + /** + * Handle Orders Changed ... + * + * @param count: int, number of changes ... + * if the count is positive, means new added ... + * if the count is negative, means removed ... + */ + void virtual HandleOnOrdersChanged(int count) + { + } + + /** + * Handle Positions Changed ... + * + * @param count: int, number of changes ... + * if the count is positive, means new added ... + * if the count is negative, means removed ... + */ + void virtual HandleOnPositionsChanged(int count) + { + UpdatePanelPositionButtons(); + } + + /** + * Handle Position Modified Event ... + * + * @param ticket: ulong, triggered Positions ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ + void virtual HandleOnPositionModified( + const ulong ticket, + const double profit, + const string comment // + ) + { + } + + /** + * Handle all Trades States Changed Event ... + * + * @param state: XOnTradeHandlerState instance refrence, Changed Trade State data ... + */ + void virtual HandleOnTradeStateChanged(const XOnTradeHandlerState &state) + { + } + + // + // Validators ... + + /** + * Validate Inputs ... + * + * @return ( bool ) + */ + bool virtual ValidateInputs() + { + // + bool result = false; + + // + // TODO: Handle this ... + result = true; + + // + return result; + } + + // + // Viruals ... + + /** + * Prepare Signallers per Symbol Config ... + * + * @param symbolConfig: XSymbolTradeConfig, Symbol Trade Configurations ... + */ + void virtual PrepareSignallers(XSymbolTradeConfig &symbolConfig) + { + } + + /** + * Additional On Tick Processing if Required ... + * + * @param barIndex: int, Specified Bar Index ... + */ + void virtual HandleOnTickAdditional(int barIndex = 0) + { + } + + // + // Signal Event Handlers ... + + // + void AddOnSignalEventHandler(TOnSignal handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnSignalEventHandlers // + ); + } + + // + // Trade Event Handlers ... + + // + void AddOnStopLossEventHandler(TOnStopLoss handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mStopLossEventHandlers + // + ); + } + + // + void AddOnTakeProfitEventHandler(TOnTakeProfit handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mTakeProfitEventHandlers + // + ); + } + + // + void AddOnDealsChangedEventHandler(TOnDealsChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mDealsChangedEventHandlers + // + ); + } + + // + void AddOnOrdersChangedEventHandler(TOnOrdersChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOrdersChangedEventHandlers + // + ); + } + + // + void AddOnModifyPositionEventHandler(TOnModify handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnModifyEventHandlers + // + ); + } + + // + void AddOnPositionsChangedEventHandler(TOnPositionsChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mPositionsChangedEventHandlers + // + ); + } + + // + void AddOnTradeStateChangedEventHandler(TOnTradeStateChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mTradeStateChangedEventHandlers + // + ); + } + + // + void AddOnForceClosePositionEventHandler(TOnForceClose handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnForceCloseEventHandlers + // + ); + } + + // + void AddOnPartialClosePositionEventHandler(TOnPartialClose handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnPartialCloseEventHandlers + // + ); + } + + // + // Protected ... + protected: + // + // Props ... + + // + // Actions and Tools ... + + /** + * Report Time Changes based on Given Configurations ... + */ + void HandleTimeReport() + { + // + if (eaAlert == NULL) + { + return; + } + + // + // Monthly Report .... + if (eaReportNewMonths && + eaTimeTracker.IsNewMonth()) + { + // + string msg = "New Month ..."; + + // + eaAlert.SendAlert(msg); + } + + // + // Weekly Report .... + if (eaReportNewWeeks && + eaTimeTracker.IsNewWeek()) + { + // + string msg = "New Week ..."; + + // + eaAlert.SendAlert(msg); + } + + // + // Daily Report .... + if (eaReportNewDays && + eaTimeTracker.IsNewDay()) + { + // + string msg = "New Day ..."; + + // + eaAlert.SendAlert(msg); + } + + // + // Hourly Report .... + if (eaReportNewHours && + eaTimeTracker.IsNewHour()) + { + // + string msg = "New Hour ..."; + + // + eaAlert.SendAlert(msg); + } + } + + /** + * Register Signaller ... + */ + void RegisterSignaller(XCBaseSignaller *signaller) + { + // + // Validate Signaller ... + if (signaller == NULL) + { + return; + } + + // + // Attach Signaller OnSignal Event Handlers if Exists ... + int count = ArraySize(mOnSignalEventHandlers); + bool has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + signaller.AddOnSignalEventHandler(mOnSignalEventHandlers[i]); + } + } + + // + // Attach Can Analyse Event Handler ... + signaller.canAnalyseEventListener = canAnalyseEventHandler; + + // + // Register Signaller ... + Add( + signaller, + eaSignallers // + ); + } + + // + // Private ... + private: + // + // Props ... + + // + // Specified Event Handlers ... + TOnModify mOnModifyEventHandlers[]; + TOnSignal mOnSignalEventHandlers[]; + TOnStopLoss mStopLossEventHandlers[]; + TOnTakeProfit mTakeProfitEventHandlers[]; + TOnForceClose mOnForceCloseEventHandlers[]; + TOnDealsChanged mDealsChangedEventHandlers[]; + TOnOrdersChanged mOrdersChangedEventHandlers[]; + TOnPartialClose mOnPartialCloseEventHandlers[]; + TOnPositionsChanged mPositionsChangedEventHandlers[]; + TOnTradeStateChanged mTradeStateChangedEventHandlers[]; + + // + XCBaseSignaller *eaSignallers[]; // All Registered Signallers ... + + // + // Panel Support ... + + // + XCChartHelper *eaChartHelper; // Chart Helper Class ... + + // + string objSuffix; + + // + CButton btnBuy; + CButton btnSell; + CButton btnClose; + CButton btnCloseAll; + CEdit lblPositionId; + + // + CButton lblTP; + CButton lblSL; + CButton btnSLPlus; + CButton btnTPPlus; + CButton btnSLMinus; + CButton btnTPMinus; + CButton btnSLPlusPlus; + CButton btnTPPlusPlus; + CButton btnSLMinusMinus; + CButton btnTPMinusMinus; + + // + CArrayObj posArray; + CButton *btnSelectedPosInfo; + CArrayObj selectedPosInfoArr; + + // + ulong selectedPositionID; + bool showSelectedPositionInfo; + + /** + * Initial Management GUI Panel ... + * + * @return ( bool ) + */ + bool InitPanel() + { + // + bool result = false; + + // + result = !eaShowPanel; + if (result) + { + return result; + } + + // + // Check Default Symbol and Period ... + + // + int subWindow = 0; + ulong chartId = ChartID(); + objSuffix = eaLogSuffix + "_"; + + // + // Initial Chart Class Instance ... + eaChartHelper = new XCChartHelper(chartId); + + // + int startX = 5; + int startY = 25; + + // + int defaultGap = 5; + int defaultWidth = 100; + int defaultHeight = 30; + + // + // Buy ... + int btnBuyX1 = startX; + int btnBuyX2 = startX + defaultWidth; + int btnBuyY1 = startY; + int btnBuyY2 = startY + defaultHeight; + string btnBuyName = objSuffix + "BTN_BUY"; + result = btnBuy.Create( + chartId, + btnBuyName, + subWindow, + btnBuyX1, + btnBuyY1, + btnBuyX2, + btnBuyY2 // + ); + if (result) + { + // + // Apply Buy Button Style ... + + // + btnBuy.Text("Buy"); + btnBuy.Color(clrYellow); + btnBuy.ColorBackground(clrGreen); + } + + // + // Sell ... + int btnSellX1 = btnBuyX1 + btnBuyX2; + int btnSellX2 = btnSellX1 + defaultWidth; + int btnSellY1 = btnBuyY1; + int btnSellY2 = btnBuyY2; + string btnSellName = objSuffix + "BTN_SELL"; + result = btnSell.Create( + chartId, + btnSellName, + subWindow, + btnSellX1, + btnSellY1, + btnSellX2, + btnSellY2 // + ); + if (result) + { + // + // Apply Sell Button Style ... + + // + btnSell.Text("Sell"); + btnSell.Color(clrYellow); + btnSell.ColorBackground(clrDarkRed); + } + + // + // LABEL Position ID ... + int lblPositionIdX1 = btnBuyX1; + int lblPositionIdX2 = lblPositionIdX1 + defaultWidth; + int lblPositionIdY1 = btnSellY2 + defaultGap; + int lblPositionIdY2 = lblPositionIdY1 + defaultHeight; + string lblPositionIdName = objSuffix + "LBL_POS_ID"; + result = lblPositionId.Create( + chartId, + lblPositionIdName, + subWindow, + lblPositionIdX1, + lblPositionIdY1, + lblPositionIdX2, + lblPositionIdY2 // + ); + if (result) + { + // + // Apply Label Position ID Style ... + lblPositionId.ReadOnly(true); + lblPositionId.Text("Pos ID: "); + lblPositionId.Color(clrYellow); + lblPositionId.ColorBackground(clrDarkGray); + } + + // + // Close ... + int btnCloseX1 = startX; + int btnCloseX2 = btnCloseX1 + defaultWidth; + int btnCloseY1 = lblPositionIdY2 + defaultGap; + int btnCloseY2 = btnCloseY1 + defaultHeight; + string btnCloseName = objSuffix + "BTN_CLOSE"; + result = btnClose.Create( + chartId, + btnCloseName, + subWindow, + btnCloseX1, + btnCloseY1, + btnCloseX2, + btnCloseY2 // + ); + if (result) + { + // + // Apply Close Button Style ... + + // + btnClose.Text("Close"); + btnClose.Color(clrYellow); + btnClose.ColorBackground(clrDarkOrange); + } + + // + // Close All ... + int btnCloseAllX1 = btnCloseX2 + defaultGap; + int btnCloseAllX2 = btnCloseAllX1 + defaultWidth; + int btnCloseAllY1 = lblPositionIdY2 + defaultGap; + int btnCloseAllY2 = btnCloseAllY1 + defaultHeight; + string btnCloseAllName = objSuffix + "BTN_CLOSE_ALL"; + result = btnCloseAll.Create( + chartId, + btnCloseAllName, + subWindow, + btnCloseAllX1, + btnCloseAllY1, + btnCloseAllX2, + btnCloseAllY2 // + ); + if (result) + { + // + // Apply Close Button Style ... + + // + btnCloseAll.Text("Close All"); + btnCloseAll.Color(clrYellow); + btnCloseAll.ColorBackground(clrDarkRed); + } + + // + int minusPlusWidth = 20; + + // + // TP Label ... + int lblTPX1 = btnCloseX1; + int lblTPX2 = lblTPX1 + defaultWidth; + int lblTPY1 = btnCloseY2 + defaultGap; + int lblTPY2 = lblTPY1 + defaultHeight; + string lblTPName = objSuffix + "LBL_TP"; + result = lblTP.Create( + chartId, + lblTPName, + subWindow, + lblTPX1, + lblTPY1, + lblTPX2, + lblTPY2 // + ); + if (result) + { + // + // Apply Style ... + lblTP.Disable(); + lblTP.Text("TP"); + lblTP.Color(clrWhite); + lblTP.ColorBackground(clrGreen); + } + + // + // TP Plus ... + int btnTPPlusX1 = lblTPX1; + int btnTPPlusX2 = btnTPPlusX1 + minusPlusWidth; + int btnTPPlusY1 = lblTPY2 + defaultGap; + int btnTPPlusY2 = btnTPPlusY1 + defaultHeight; + string btnTPPlusName = objSuffix + "BTN_TP_PLUS"; + result = btnTPPlus.Create( + chartId, + btnTPPlusName, + subWindow, + btnTPPlusX1, + btnTPPlusY1, + btnTPPlusX2, + btnTPPlusY2 // + ); + if (result) + { + // + // Apply Style ... + btnTPPlus.Text("+"); + btnTPPlus.Color(clrYellow); + btnTPPlus.ColorBackground(clrGreen); + } + + // + // TP Plus Plus ... + int btnTPPlusPlusX1 = btnTPPlusX2 + defaultGap; + int btnTPPlusPlusX2 = btnTPPlusPlusX1 + minusPlusWidth; + int btnTPPlusPlusY1 = lblTPY2 + defaultGap; + int btnTPPlusPlusY2 = btnTPPlusPlusY1 + defaultHeight; + string btnTPPlusPlusName = objSuffix + "BTN_TP_PLUSPLUS"; + result = btnTPPlusPlus.Create( + chartId, + btnTPPlusPlusName, + subWindow, + btnTPPlusPlusX1, + btnTPPlusPlusY1, + btnTPPlusPlusX2, + btnTPPlusPlusY2 // + ); + if (result) + { + // + // Apply Style ... + btnTPPlusPlus.Text("++"); + btnTPPlusPlus.Color(clrYellow); + btnTPPlusPlus.ColorBackground(clrGreen); + } + + // + // TP Minus ... + int btnTPMinusX1 = lblTPX2 - minusPlusWidth; + int btnTPMinusX2 = btnTPMinusX1 + minusPlusWidth; + int btnTPMinusY1 = lblTPY2 + defaultGap; + int btnTPMinusY2 = btnTPMinusY1 + defaultHeight; + string btnTPMinusName = objSuffix + "BTN_TP_MINUS"; + result = btnTPMinus.Create( + chartId, + btnTPMinusName, + subWindow, + btnTPMinusX1, + btnTPMinusY1, + btnTPMinusX2, + btnTPMinusY2 // + ); + if (result) + { + // + // Apply Style ... + btnTPMinus.Text("-"); + btnTPMinus.Color(clrYellow); + btnTPMinus.ColorBackground(clrDarkRed); + } + + // + // TP Minus Minus ... + int btnTPMinusMinusX1 = btnTPMinusX1 - minusPlusWidth - defaultGap; + int btnTPMinusMinusX2 = btnTPMinusMinusX1 + minusPlusWidth; + int btnTPMinusMinusY1 = lblTPY2 + defaultGap; + int btnTPMinusMinusY2 = btnTPMinusY1 + defaultHeight; + string btnTPMinusMinusName = objSuffix + "BTN_TP_MINUSMINUS"; + result = btnTPMinusMinus.Create( + chartId, + btnTPMinusMinusName, + subWindow, + btnTPMinusMinusX1, + btnTPMinusMinusY1, + btnTPMinusMinusX2, + btnTPMinusMinusY2 // + ); + if (result) + { + // + // Apply Style ... + btnTPMinusMinus.Text("--"); + btnTPMinusMinus.Color(clrYellow); + btnTPMinusMinus.ColorBackground(clrDarkRed); + } + + // + // SL Label ... + int lblSLX1 = btnCloseAllX1; + int lblSLX2 = lblSLX1 + defaultWidth; + int lblSLY1 = btnCloseAllY2 + defaultGap; + int lblSLY2 = lblTPY1 + defaultHeight; + string lblSLName = objSuffix + "LBL_SL"; + result = lblSL.Create( + chartId, + lblSLName, + subWindow, + lblSLX1, + lblSLY1, + lblSLX2, + lblSLY2 // + ); + if (result) + { + // + // Apply Style ... + lblSL.Disable(); + lblSL.Text("SL"); + lblSL.Color(clrWhite); + lblSL.ColorBackground(clrDarkRed); + } + + // + // SL Plus ... + int btnSLPlusX1 = lblSLX1; + int btnSLPlusX2 = btnSLPlusX1 + minusPlusWidth; + int btnSLPlusY1 = lblSLY2 + defaultGap; + int btnSLPlusY2 = btnSLPlusY1 + defaultHeight; + string btnSLPlusName = objSuffix + "BTN_SL_PLUS"; + result = btnSLPlus.Create( + chartId, + btnSLPlusName, + subWindow, + btnSLPlusX1, + btnSLPlusY1, + btnSLPlusX2, + btnSLPlusY2 // + ); + if (result) + { + // + // Apply Style ... + btnSLPlus.Text("+"); + btnSLPlus.Color(clrYellow); + btnSLPlus.ColorBackground(clrGreen); + } + + // + // SL Plus Plus ... + int btnSLPlusPlusX1 = btnSLPlusX2 + defaultGap; + int btnSLPlusPlusX2 = btnSLPlusPlusX1 + minusPlusWidth; + int btnSLPlusPlusY1 = lblSLY2 + defaultGap; + int btnSLPlusPlusY2 = btnSLPlusPlusY1 + defaultHeight; + string btnSLPlusPlusName = objSuffix + "BTN_SL_PLUSPLUS"; + result = btnSLPlusPlus.Create( + chartId, + btnSLPlusPlusName, + subWindow, + btnSLPlusPlusX1, + btnSLPlusPlusY1, + btnSLPlusPlusX2, + btnSLPlusPlusY2 // + ); + if (result) + { + // + // Apply Style ... + btnSLPlusPlus.Text("++"); + btnSLPlusPlus.Color(clrYellow); + btnSLPlusPlus.ColorBackground(clrGreen); + } + + // + // SL Minus ... + int btnSLMinusX1 = lblSLX2 - minusPlusWidth; + int btnSLMinusX2 = btnSLMinusX1 + minusPlusWidth; + int btnSLMinusY1 = lblSLY2 + defaultGap; + int btnSLMinusY2 = btnSLMinusY1 + defaultHeight; + string btnSLMinusName = objSuffix + "BTN_SL_MINUS"; + result = btnSLMinus.Create( + chartId, + btnSLMinusName, + subWindow, + btnSLMinusX1, + btnSLMinusY1, + btnSLMinusX2, + btnSLMinusY2 // + ); + if (result) + { + // + // Apply Style ... + btnSLMinus.Text("-"); + btnSLMinus.Color(clrYellow); + btnSLMinus.ColorBackground(clrDarkRed); + } + + // + // SL Minus Minus ... + int btnSLMinusMinusX1 = btnSLMinusX1 - minusPlusWidth - defaultGap; + int btnSLMinusMinusX2 = btnSLMinusMinusX1 + minusPlusWidth; + int btnSLMinusMinusY1 = lblSLY2 + defaultGap; + int btnSLMinusMinusY2 = btnSLMinusY1 + defaultHeight; + string btnSLMinusMinusName = objSuffix + "BTN_SL_MINUSMINUS"; + result = btnSLMinusMinus.Create( + chartId, + btnSLMinusMinusName, + subWindow, + btnSLMinusMinusX1, + btnSLMinusMinusY1, + btnSLMinusMinusX2, + btnSLMinusMinusY2 // + ); + if (result) + { + // + // Apply Style ... + btnSLMinusMinus.Text("--"); + btnSLMinusMinus.Color(clrYellow); + btnSLMinusMinus.ColorBackground(clrDarkRed); + } + + // + UpdatePanelState(); + + // + return result; + } + + /** + * Listen For Panel Controls Events and + * Update State of GUI Panel ... + */ + void UpdatePanel() + { + // + if (!eaShowPanel) + { + return; + } + + // + UpdatePanelState(); + + // + // Buy Button Pressed ... + if (btnBuy.Pressed()) + { + // + HandleBuyTrade(); + btnBuy.Pressed(false); + } + + // + // Sell Button Pressed ... + if (btnSell.Pressed()) + { + // + HandleSellTrade(); + btnSell.Pressed(false); + } + + // + // Close Button Pressed ... + if (btnClose.Pressed()) + { + // + if (btnClose.IsEnabled()) + { + // + if (selectedPositionID > 0) + { + HandleCloseTrade(selectedPositionID); + } + } + + // + btnClose.Pressed(false); + } + + // + // Close All Button Pressed ... + if (btnCloseAll.Pressed()) + { + // + if (btnCloseAll.IsEnabled()) + { + HandleCloseTrade(0); + } + + // + btnCloseAll.Pressed(false); + } + + // + // Check Show Hide Selected Position Info ... + if (btnSelectedPosInfo != NULL) + { + // + if (btnSelectedPosInfo.Pressed()) + { + // + // Check Enable ... + if (btnSelectedPosInfo.IsEnabled()) + { + // + // Handle Toggle Show/Hide lblSelectedPositionInfo ... + CEdit *iLbl = NULL; + bool isVisible = showSelectedPositionInfo; + int count = selectedPosInfoArr.Total(); + if (IsValidSize(count)) + { + // + // Loop Through Labels ... + for (int i = 0; i < count; i++) + { + // + iLbl = (CEdit *)selectedPosInfoArr.At(i); + isVisible = iLbl.IsVisible(); + if (isVisible) + { + iLbl.Hide(); + } + else + { + iLbl.Show(); + } + } + + // + // Update Button Text ... + isVisible = showSelectedPositionInfo; + string btnText = isVisible + ? "Hide Info" + : "Show Info"; + btnSelectedPosInfo.Text(btnText); + showSelectedPositionInfo = !showSelectedPositionInfo; + } + + // + ZeroMemory(iLbl); + } + + // + btnSelectedPosInfo.Pressed(false); + } + } + + // + // TP Managing ... + + // + // TP Plus ... + if (btnTPPlus.Pressed()) + { + // + if (btnTPPlus.IsEnabled()) + { + HandleTPChange(X_DIRECTION_BULLISH); + } + + // + btnTPPlus.Pressed(false); + } + + // + // TP Plus Plus ... + if (btnTPPlusPlus.Pressed()) + { + // + if (btnTPPlusPlus.IsEnabled()) + { + HandleTPChange(X_DIRECTION_BULLISH, 2); + } + + // + btnTPPlusPlus.Pressed(false); + } + + // + // TP Minus ... + if (btnTPMinus.Pressed()) + { + // + if (btnTPMinus.IsEnabled()) + { + HandleTPChange(X_DIRECTION_BEARISH); + } + + // + btnTPMinus.Pressed(false); + } + + // + // TP Minus Minus ... + if (btnTPMinusMinus.Pressed()) + { + // + if (btnTPMinusMinus.IsEnabled()) + { + HandleTPChange(X_DIRECTION_BEARISH, 2); + } + + // + btnTPMinusMinus.Pressed(false); + } + + // + // SL Managing ... + + // + // SL Plus ... + if (btnSLPlus.Pressed()) + { + // + if (btnSLPlus.IsEnabled()) + { + HandleSLChange(X_DIRECTION_BULLISH); + } + + // + btnSLPlus.Pressed(false); + } + + // + // SL Plus Plus ... + if (btnSLPlusPlus.Pressed()) + { + // + if (btnSLPlusPlus.IsEnabled()) + { + HandleSLChange(X_DIRECTION_BULLISH, 2); + } + + // + btnSLPlusPlus.Pressed(false); + } + + // + // SL Minus ... + if (btnSLMinus.Pressed()) + { + // + if (btnSLMinus.IsEnabled()) + { + HandleSLChange(X_DIRECTION_BEARISH); + } + + // + btnSLMinus.Pressed(false); + } + + // + // SL Minus Minus ... + if (btnSLMinusMinus.Pressed()) + { + // + if (btnSLMinusMinus.IsEnabled()) + { + HandleSLChange(X_DIRECTION_BEARISH, 2); + } + + // + btnSLMinusMinus.Pressed(false); + } + + // + // Check Positions Buttons ... + int posCount = posArray.Total(); + bool has = IsValidSize(posCount); + if (has) + { + // + for (int i = 0; i < posCount; i++) + { + // + CButton *iBtn = (CButton *)posArray.At(i); + + // + if (iBtn.Pressed()) + { + // + if (iBtn.IsEnabled()) + { + // + ulong posID = ExtractPositionIDFromButtonName(iBtn.Name()); + if (posID > 0 && selectedPositionID != posID) + { + selectedPositionID = posID; + UpdatePanelState(); + } + } + + // + iBtn.Pressed(false); + } + + // + ZeroMemory(iBtn); + } + } + } + + /** + * Update GUI Panels Controls States ... + */ + void UpdatePanelState() + { + // + if (!eaShowPanel) + { + return; + } + // + // Update States Of Position Select Buttons ... + int count = posArray.Total(); + bool has = IsValidSize(count) && selectedPositionID > 0; + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + CButton *iBtn = (CButton *)posArray.At(i); + + // + ulong posID = ExtractPositionIDFromButtonName(iBtn.Name()); + + // + // Select Position ... + XPosition iPos; + bool hasPosition = eaTrader.GetPosition( + posID, + iPos // + ); + string iTooltip = + !hasPosition + ? "" + : IsLong(iPos.type) + ? "Long" + : "Short"; + + // + if (posID == selectedPositionID) + { + // + iBtn.Disable(); + iBtn.ColorBackground(clrDarkGray); + } + else + { + // + iBtn.Enable(); + + // + color iBtnBG = IsLong(iPos.type) + ? clrGreen + : clrDarkRed; + + // + iBtn.ColorBackground(iBtnBG); + } + + // + ZeroMemory(iBtn); + } + } + + // + // Update State of Close All ... + if (has && count > 1) + { + // + btnCloseAll.Enable(); + btnCloseAll.ColorBackground(clrDarkRed); + } + else + { + // + btnCloseAll.Disable(); + btnCloseAll.ColorBackground(clrDarkGray); + } + + // + // Update Selected Position Info Button State ... + if (has) + { + // + // Reading Global Chart Info ... + int subWindow = 0; + int chartWidth = eaChartHelper.Width(); + ulong chartId = eaChartHelper.ChartId(); + + // + // Read Selected Position ... + XPosition selectedPosition; + bool hasPosition = eaTrader.GetPosition( + selectedPositionID, + selectedPosition // + ); + + // + // Read All Positions ... + double profits = 0; + XPosition positions[]; + string positionsInfo = ""; + int positionsCount = eaTrader.GetPositions(positions); + has = IsValidSize(positionsCount); + if (has) + { + // + for (int i = 0; i < positionsCount; i++) + { + profits += positions[i].profit; + } + + // + if (positionsCount > 1) + { + positionsInfo = "Positions Count: " + ToXString(positionsCount) + ", Profits: " + ToXString(profits); + } + } + + // + if (hasPosition) + { + // + // Preparing Position Info ... + string posTicket = "Ticket: " + ToXString(selectedPosition.ticket); + string posType = "Type: " + ToXString(selectedPosition.type); + string posSymbolPeriod = + "Symbol: " + selectedPosition.symbol + ", " + + "Period: " + ToXString(selectedPosition.period); + string posProfit = "Profit: " + ToXString(selectedPosition.profit); + string posRiskToRewardRatio = "RiskToReward: " + ToXString(selectedPosition.GetRiskRewardRatio()); + string accountInfo = + "Balance: " + ToXString(eaTrader.mAccount.GetBalance()) + ", " + + "Equity: " + ToXString(eaTrader.mAccount.GetEquity()); + + // + string posInfos[]; + + // + // Ticket ... + Add( + posTicket, + posInfos // + ); + + // + // Type ... + Add( + posType, + posInfos // + ); + + // + // Symbol Period ... + Add( + posSymbolPeriod, + posInfos // + ); + + // + // Profit ... + Add( + posProfit, + posInfos // + ); + + // + // Risk to Reward Ratio ... + Add( + posRiskToRewardRatio, + posInfos // + ); + + // + // Add Positions Info if Exists ... + if (IsSpecifiedValid(positionsInfo)) + { + // + Add( + positionsInfo, + posInfos // + ); + + // + // Clear Info Array ... + selectedPosInfoArr.Clear(); + } + + // + // Adding Account Info ... + Add( + accountInfo, + posInfos // + ); + + // + // Create Button If Not Exists ... + if (btnSelectedPosInfo == NULL) + { + // + btnSelectedPosInfo = new CButton(); + + // + string name = objSuffix + "BTN_TOOGLE_SPOS_INFO"; + + // + CRect iRect = btnTPPlus.Rect(); + + // + int x1 = iRect.left; + int x2 = x1 + 200 + 5; + + // + int y1 = iRect.bottom + 5; + int y2 = y1 + iRect.Height(); + + // + bool isCreated = btnSelectedPosInfo.Create( + chartId, + name, + subWindow, + x1, + y1, + x2, + y2 // + ); + if (!isCreated) + { + // + delete btnSelectedPosInfo; + ZeroMemory(btnSelectedPosInfo); + } + else + { + // + // Apply Styles ... + btnSelectedPosInfo.Color(clrYellow); + btnSelectedPosInfo.ColorBackground(clrDarkBlue); + } + } + + // + // Check Btn Exists ... + has = btnSelectedPosInfo != NULL; + if (has) + { + // + int posInfoCount = ArraySize(posInfos); + int lblInfoCount = selectedPosInfoArr.Total(); + has = IsValidSize(lblInfoCount) && lblInfoCount == posInfoCount; + + // + // Create info Labels ... + if (!has) + { + // + selectedPosInfoArr.Clear(); + has = IsValidSize(posInfoCount); + if (has) + { + // + // Creat Info Control ... + + // + string name = objSuffix + "LBL_SPOS_INFO"; + + // + int lblHeight = 25; + int lblWidth = 450; + + // + int startX = chartWidth - lblWidth - 5; + int sizeX = startX + lblWidth; + + // + int startY = 5; + int sizeY = startY + lblHeight; + + // + // Loop through Position Info's Array to Create Label Controls ... + for (int i = 0; i < posInfoCount; i++) + { + // + string iText = posInfos[i]; + string iTextMD5 = ToMD5(iText); + + // + string iName = name + "_" + iTextMD5; + + // + int iX1 = startX; + int iX2 = sizeX; + + // + int iY1 = startY; + int iY2 = startY + lblHeight; + + // + CEdit *iLbl = new CEdit(); + bool isCreated = iLbl.Create( + chartId, + iName, + subWindow, + iX1, + iY1, + iX2, + iY2 // + ); + if (isCreated) + { + // + iLbl.Text(iText); + iLbl.Color(clrYellow); + iLbl.ColorBorder(clrDarkSlateGray); + iLbl.ColorBackground(clrDarkSlateGray); + + // + if (showSelectedPositionInfo) + { + iLbl.Show(); + } + else + { + iLbl.Hide(); + } + + // + selectedPosInfoArr.Add(iLbl); + + // + startY = iY2; + } + } + } + } + + // + // Update Info Labels ... + lblInfoCount = selectedPosInfoArr.Total(); + has = IsValidSize(lblInfoCount); + if (has) + { + // + CEdit *iLbl = NULL; + + // + // Loop Through Infos ... + for (int i = 0; i < lblInfoCount; i++) + { + // + iLbl = (CEdit *)selectedPosInfoArr.At(i); + + // + iLbl.Text(posInfos[i]); + } + + // + bool isVisible = showSelectedPositionInfo; + string btnText = isVisible + ? "Hide Info" + : "Show Info"; + btnSelectedPosInfo.Text(btnText); + + // + ZeroMemory(iLbl); + } + } + + // + ZeroMemory(posInfos); + } + + // + SpecifiedClean(positions); + } + else + { + // + // Toggle Selected Position Btn ... + if (btnSelectedPosInfo != NULL) + { + // + btnSelectedPosInfo.Destroy(); + + // + delete btnSelectedPosInfo; + ZeroMemory(btnSelectedPosInfo); + } + + // + // Selected Position Lbls ... + selectedPosInfoArr.Clear(); + } + + // + // Update State of BtnClose and BtnClose All ... + if (selectedPositionID == 0) + { + // + btnClose.Disable(); + btnClose.ColorBackground(clrDarkGray); + + // + lblTP.Disable(); + lblTP.ColorBackground(clrDarkGray); + + // + btnTPPlus.Disable(); + btnTPPlus.ColorBackground(clrDarkGray); + + // + btnTPPlusPlus.Disable(); + btnTPPlusPlus.ColorBackground(clrDarkGray); + + // + btnTPMinus.Disable(); + btnTPMinus.ColorBackground(clrDarkGray); + + // + btnTPMinusMinus.Disable(); + btnTPMinusMinus.ColorBackground(clrDarkGray); + + // + lblSL.Disable(); + lblSL.ColorBackground(clrDarkGray); + + // + btnSLPlus.Disable(); + btnSLPlus.ColorBackground(clrDarkGray); + + // + btnSLPlusPlus.Disable(); + btnSLPlusPlus.ColorBackground(clrDarkGray); + + // + btnSLMinus.Disable(); + btnSLMinus.ColorBackground(clrDarkGray); + + // + btnSLMinusMinus.Disable(); + btnSLMinusMinus.ColorBackground(clrDarkGray); + } + else + { + // + btnClose.Enable(); + btnClose.ColorBackground(clrDarkOrange); + + // + lblTP.Enable(); + lblTP.ColorBackground(clrGreen); + + // + btnTPPlus.Enable(); + btnTPPlus.ColorBackground(clrGreen); + + // + btnTPPlusPlus.Enable(); + btnTPPlusPlus.ColorBackground(clrGreen); + + // + btnTPMinus.Enable(); + btnTPMinus.ColorBackground(clrDarkRed); + + // + btnTPMinusMinus.Enable(); + btnTPMinusMinus.ColorBackground(clrDarkRed); + + // + lblSL.Enable(); + lblSL.ColorBackground(clrDarkRed); + + // + btnSLPlus.Enable(); + btnSLPlus.ColorBackground(clrGreen); + + // + btnSLPlusPlus.Enable(); + btnSLPlusPlus.ColorBackground(clrGreen); + + // + btnSLMinus.Enable(); + btnSLMinus.ColorBackground(clrDarkRed); + + // + btnSLMinusMinus.Enable(); + btnSLMinusMinus.ColorBackground(clrDarkRed); + } + } + + /** + * Update Panel's Position Selector Buttons ... + */ + void UpdatePanelPositionButtons() + { + // + if (!eaShowPanel) + { + return; + } + + // + // Retrieve Positions ... + XPosition positions[]; + int count = eaTrader.GetPositions( + positions // + ); + bool has = IsValidSize(count); + if (!has) + { + // + posArray.Clear(); + selectedPositionID = 0; + UpdatePanelState(); + return; + } + + // + posArray.Clear(); + + // + // Selected Position ID ... + bool isSelectdPositionIDExists = false; + if (has && selectedPositionID > 0) + { + // + for (int i = 0; i < count; i++) + { + // + if (!isSelectdPositionIDExists && + positions[i].ticket == selectedPositionID) + { + // + isSelectdPositionIDExists = true; + break; + } + } + } + if (!isSelectdPositionIDExists || + selectedPositionID == 0) + { + // + XPosition youngest; + int youngestIDX = GetXYoungest(youngest, positions); + bool hasYoungest = IsValidIndex(youngestIDX) && + youngest.IsValid(); + if (hasYoungest) + { + selectedPositionID = youngest.ticket; + } + + // + youngest.Clean(); + } + + // + int subWindow = 0; + ulong chartId = eaChartHelper.ChartId(); + + // + int btnWidth = 25; + int btnHeight = 25; + + // + CRect iRect = lblPositionId.Rect(); + + // + int lastX = iRect.left + iRect.Width() + 5; + int lastSizeX = lastX + btnWidth; + + // + int lastY = iRect.top; + int lastSizeY = lastY + iRect.Height(); + + // + for (int i = 0; i < count; i++) + { + // + XPosition iPos = positions[i]; + + // + string posTypeStr = IsLong(iPos.type) + ? "LONG" + : "SHORT"; + + // + int iPosBtnX = lastX; + int iPosBtnSizeX = iPosBtnX + btnWidth; + string iPosBtnName = objSuffix + "_" + posTypeStr + "_POS_SELECT_BTN_" + ToXString(iPos.ticket); + + // + CButton *iPosBtn = new CButton(); + has = iPosBtn.Create( + chartId, + iPosBtnName, + subWindow, + iPosBtnX, + lastY, + iPosBtnSizeX, + lastSizeY // + ); + if (has) + { + // + // Apply Styles ... + string iPosBtnText = ToXString(iPos.ticket); + + // + iPosBtn.Text(iPosBtnText); + iPosBtn.Color(clrWhite); + + // + color iPosBtnBG = IsLong(iPos.type) + ? clrGreen + : clrDarkRed; + iPosBtn.ColorBackground(iPosBtnBG); + + // + lastX = iPosBtnSizeX + 5; + + // + if (selectedPositionID == iPos.ticket) + { + iPosBtn.Disable(); + } + + // + posArray.Add(iPosBtn); + } + + // + iPos.Clean(); + } + + // + ZeroMemory(positions); + UpdatePanelState(); + + // + } + + /** + * Destroy Management GUI Panel ... + */ + void DestroyPanel() + { + // + delete eaChartHelper; + ZeroMemory(eaChartHelper); + + // + delete btnSelectedPosInfo; + ZeroMemory(btnSelectedPosInfo); + } + + // + void NormalizePanelProps() + { + // + if (eaPanelVolume < 0.01) + { + eaPanelVolume = 0.01; + } + + // + if (eaPanelRiskInPoint < 0) + { + eaPanelRiskInPoint = 50; + } + + // + if (eaPanelAllowedTPSLStep < 5) + { + eaPanelAllowedTPSLStep = 5; + } + + // + if (eaPanelRiskToRewardRatio < 0.5) + { + eaPanelRiskToRewardRatio = 2; + } + + // + if (eaPanelMinAllowedRiskInPoint < 10) + { + eaPanelMinAllowedRiskInPoint = 10; + } + } + + // + ulong ExtractPositionIDFromButtonName(string name) + { + // + ulong result = 0; + + // + string nameParts[]; + int namePartsCount = SplitContent(nameParts, name, "_"); + bool has = IsValidSize(namePartsCount); + if (has) + { + // + string lastPart = nameParts[namePartsCount - 1]; + StringReplace(lastPart, "_", ""); + result = (long)lastPart; + } + + // + ZeroMemory(nameParts); + + // + return result; + } + + // + // Management Panel Event Handlers ... + + // + void HandleBuyTrade() + { + HandleTrade(X_DIRECTION_BULLISH); + } + + // + void HandleSellTrade() + { + HandleTrade(X_DIRECTION_BEARISH); + } + + // + void HandleTrade(ENUM_X_DIRECTION dir) + { + // + if (!HasDirection(dir)) + { + return; + } + + // + NormalizePanelProps(); + + // + bool isBullish = IsSpecifiedBullish(dir); + + // + double _volume = eaPanelVolume; + double r2r = eaPanelRiskToRewardRatio; + double _riskInPoints = eaPanelRiskInPoint; + double point = GetPoints(eaChartHelper.Symbol()); + double entry = GetEntry(eaChartHelper.Symbol(), dir); + + // + double risk = _riskInPoints * point; + double reward = risk * r2r; + + // + double sl = isBullish + ? entry - risk + : entry + risk; + double tp = isBullish + ? entry + reward + : entry - reward; + + // + string comment = eaLogSuffix + "_POS_" + ToXString(dir); + + // + if (isBullish) + { + // + eaTrader.Buy( + eaChartHelper.Symbol(), + eaChartHelper.Period(), + _volume, + entry, + sl, + tp, + comment // + ); + } + else + { + // + eaTrader.Sell( + eaChartHelper.Symbol(), + eaChartHelper.Period(), + _volume, + entry, + sl, + tp, + comment // + ); + } + } + + // + void HandleCloseTrade(ulong positionID) + { + // + if (positionID == 0) + { + // + XPosition positions[]; + int count = eaTrader.GetPositions( + positions // + ); + bool has = IsValidSize(count); + if (has) + { + // + int closedCount = eaTrader.Close(positions); + has = IsValidSize(closedCount); + } + } + else + { + // + XPosition position; + bool has = eaTrader.GetPosition( + positionID, + position // + ); + if (has) + { + // + has = eaTrader.Close(positionID); + } + } + } + + // + void HandleTPChange( + ENUM_X_DIRECTION dir, + int multiplier = 1 // + ) + { + // + // Validate ... + if (selectedPositionID == 0 || !HasDirection(dir)) + { + return; + } + + // + NormalizePanelProps(); + + // + // Normalize Multiplier ... + multiplier = NormalizeInt(multiplier, 1, 2); + + // + // Select Position ... + XPosition position; + bool has = eaTrader.GetPosition( + selectedPositionID, + position // + ); + if (!has) + { + // + position.Clean(); + return; + } + + // + bool isLong = IsLong(position.type); + bool isBullish = IsSpecifiedBullish(dir); + + // + double point = GetPoints(position.symbol); + double stepValue = multiplier * (point * eaPanelAllowedTPSLStep); + + // + bool mustIncrease = + isBullish + ? isLong + : !isLong; + + // + double tp = position.tp; + tp = + mustIncrease + ? tp + stepValue + : tp - stepValue; + bool isModified = eaTrader.Modify( + position.ticket, + position.sl, + tp, + objSuffix + "Change TP" // + ); + if (isModified) + { + UpdatePanelState(); + } + + // + position.Clean(); + } + + // + void HandleSLChange( + ENUM_X_DIRECTION dir, + int multiplier = 1 // + ) + { + // + // Validate ... + if (selectedPositionID == 0 || !HasDirection(dir)) + { + return; + } + + // + NormalizePanelProps(); + + // + // Normalize Multiplier ... + multiplier = NormalizeInt(multiplier, 1, 2); + + // + // Select Position ... + XPosition position; + bool has = eaTrader.GetPosition( + selectedPositionID, + position // + ); + if (!has) + { + // + position.Clean(); + return; + } + + // + bool isLong = IsLong(position.type); + bool isBullish = IsSpecifiedBullish(dir); + + // + double point = GetPoints(position.symbol); + double stepValue = multiplier * (point * eaPanelAllowedTPSLStep); + + // + bool mustIncrease = + isBullish + ? !isLong + : isLong; + + // + double risk = position.GetRiskInPoint(); + if (risk <= eaPanelMinAllowedRiskInPoint) + { + // + position.Clean(); + return; + } + + // + double sl = position.sl; + sl = + mustIncrease + ? sl + stepValue + : sl - stepValue; + bool isModified = eaTrader.Modify( + position.ticket, + sl, + position.tp, + objSuffix + "Change SL" // + ); + if (isModified) + { + UpdatePanelState(); + } + + // + position.Clean(); + } + + // +}; + +// \ No newline at end of file diff --git a/Classes/x-saherelm.x-signaller.class.mq5 b/Classes/x-saherelm.x-signaller.class.mq5 index 90e09ef2..13ca2611 100644 --- a/Classes/x-saherelm.x-signaller.class.mq5 +++ b/Classes/x-saherelm.x-signaller.class.mq5 @@ -2,7 +2,7 @@ // // SaherElm IT Center MQL5 Class // ------------------------------------------------- -// Name: XCXBaseSignaller ... +// Name: XCBaseSignaller ... // Description: Base Signaller Class ... // // - Create an Instance based on this ... @@ -18,7 +18,7 @@ // // - also Whenever you want you can call PrepareSignal Action to // provide a Signal based on Current Market State ... -// +// // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) @@ -41,23 +41,9 @@ // // Definitions ... -// -// a Event Listener for Checking Can Analyse Market or not ... -// Usually for Time Based Session Handling ... -typedef bool (*TXCSignallerCanAnalyse)( - string _symbol, - ENUM_TIMEFRAMES _period, - datetime _time // -); - -// -// a Event Listener for Notifying a Signal ... -// Usually for Time Based Session Handling ... -typedef bool (*TXCSignallerOnSignalEvent)(XSignal &signal); - // // Implementations ... -class XCXBaseSignaller : public XCBase +class XCBaseSignaller : public XCBase { // // Public ... @@ -69,11 +55,11 @@ class XCXBaseSignaller : public XCBase ENUM_TIMEFRAMES period; // Period ... // - TXCSignallerCanAnalyse canAnalyseEventListener; + TCanAnalyse canAnalyseEventListener; // // Constructor ... - XCXBaseSignaller( + XCBaseSignaller( string _name, // Name ... string _symbol, // Symbol ... ENUM_TIMEFRAMES _period, // Period ... @@ -110,7 +96,7 @@ class XCXBaseSignaller : public XCBase // // Deconstructor ... - ~XCXBaseSignaller() + ~XCBaseSignaller() { // // Cleanup Event Listeners ... @@ -123,9 +109,9 @@ class XCXBaseSignaller : public XCBase /** * Add On Signal Event Listener ... * - * @param listener: TXCSignallerOnSignalEvent instance ... + * @param listener: TOnSignal instance ... */ - void AddOnSignalEventListener(TXCSignallerOnSignalEvent listener) + void AddOnSignalEventHandler(TOnSignal listener) { // // Validate ... @@ -392,7 +378,7 @@ class XCXBaseSignaller : public XCBase /** * Preparing Default Signal ... - * + * * @param signal: XSignal, holding result Signal ... * @param forDir: ENUM_X_DIRECTION * @return ( bool ) @@ -473,7 +459,7 @@ class XCXBaseSignaller : public XCBase // // Event Listeners ... - TXCSignallerOnSignalEvent onSignalEventListeners[]; + TOnSignal onSignalEventListeners[]; }; // diff --git a/Experts/x-saherelm.backtester.ea.mq5 b/Experts/x-saherelm.backtester.ea.mq5 index 2c66bbac..e757bb8c 100644 --- a/Experts/x-saherelm.backtester.ea.mq5 +++ b/Experts/x-saherelm.backtester.ea.mq5 @@ -15,6 +15,7 @@ #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://saherelm.ir" #property version "1.00" +#property icon "../Images/SaherElm_Logo_Color.ico" #property description "SaherElm XBackTester" #property strict diff --git a/Experts/x-saherelm.rr.tools.mq5 b/Experts/x-saherelm.rr.tools.mq5 index 37aa2466..c55572a9 100644 --- a/Experts/x-saherelm.rr.tools.mq5 +++ b/Experts/x-saherelm.rr.tools.mq5 @@ -15,6 +15,7 @@ #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://saherelm.ir" #property version "1.00" +#property icon "../Images/SaherElm_Logo_Color.ico" #property description "SaherElm XRRToolsEA" #property strict diff --git a/Experts/x-saherelm.x-expert.ea.mq5 b/Experts/x-saherelm.x-expert.ea.mq5 new file mode 100644 index 00000000..363634e9 --- /dev/null +++ b/Experts/x-saherelm.x-expert.ea.mq5 @@ -0,0 +1,608 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XBaseEA +// Description: Base Expert Advisor as Template ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property icon "../Images/SaherElm_Logo_Color.ico" +#property description "SaherElm Based Expert Advisor" +#property strict + +// +#define ShortName "XBaseEA" + +// +// Importts ... +#include "../Classes/x-saherelm.x-expert.class.mq5" + +// +// Inputs ... + +// +// Common ... +input group "Common"; +input long eaMagicNumber = 1694056; // Magic Number +input int eaSlippage = 10; // Slippgae +input string eaLogSuffix = ""; // Log Suffix + +// +// Symbols +// [ +// Symbol| +// period| +// (ST_04:00_08:30),(TL_10:30_12:00),(NY_16:00_20:00)| +// maxAllowedSpread| +// maxAllowedPosition| +// ( +// restrictionsPeriod, +// restrictionsMultiplier, +// maxAllowedTPs, +// maxAllowedSLs, +// maxAllowedTrades, +// closeAllOpenTradesAt +// ) +// ] +// +// +// [XAUUSDb|M5|(ST_04:00_08:30),(TL_10:30_12:00),(NY_16:00_20:00)|25.0|5|(XTRADE_RESTRICATION_DAILY,1,0,2,0)] +input string eaSymbolConfiguration = "[XAUUSDb|M5|(ST_04:00_08:30),(TL_10:30_12:00),(NY_16:00_20:00)|25.0|5|(XTRADE_RESTRICATION_DAILY,3,0,2,0)]"; // Symbol Configurations + +// +// Management ... +input group "Management"; +input bool eaAllowGuards = false; // Allow Guards +input bool eaAllowTrade = true; // Allow Trade on Signals +input bool eaAllowLongs = true; // Allow Long Trades +input bool eaAllowShorts = true; // Allow Short Trades +input double eaMaxAllowedDrawdownFactor = 0.3; // Max Allowed DrawDown for Trade + +// +// Volume ... +input group "Volume"; +input ENUM_X_VOLUME_SELECT_TYPE eaVolumeSelect = X_VOLUME_CONSTANT; // Volume Applying Type +input double eaStaticVoluem = 0.0; // Static Volume +input double eaDynamicVolumeStepBalance = 0.0; // Step of Balance for Increase Volume +input double eaDynamicVolumeStepVolume = X_MIN_VOLUME; // Step of Volume Increasing +input double eaConstantRiskBalance = 0.0; // Constant Risk Balance per Trade +input double eaConstantPercent = 1; // Constant Percent of Balance Per Trade +input double eaConstantBalance = 1000.0; // Constant Balance for Calculations + +// +// Alert ... +input group "Alert"; +input bool eaEnableAlerts = true; // Enable Alerts +input bool eaSaveAlerts = true; // Save Alerts +input bool eaLogAlerts = true; // Log Alerts +input bool eaMailAlerts = false; // Mail Alerts +input bool eaPushAlerts = true; // Push Alerts +input bool eaTerminalAlerts = false; // Terminal Alerts + +// +// Reports ... +input group "Reports"; +input bool eaReportNewMonths = false; // Report New Month +input bool eaReportNewWeeks = false; // Report New Weeks +input bool eaReportNewDays = true; // Report New Days +input bool eaReportNewHours = false; // Report New Hours +input bool eaReportTrades = true; // Report Trades +input bool eaReportSignals = true; // Report Signals +input bool eaReportRestrictions = true; // Report Restrictions +input bool eaReportProtector = true; // Report Protector Actions +input bool eaReportAfterTradesBalance = true; // Report Balance after a Trade Finished + +// +// Collector ... +input group "Collector"; +input bool eaSaveTrades = true; // Save Trades +input bool eaSaveSignals = true; // Save Signals +input bool eaSaveWins = true; // Save Winning Conditions +input bool eaSaveLosts = true; // Save Lost Conditions +input bool eaSaveRestrictions = true; // Save Restriction Reports + +// +// Management Panel ... +input group "Management Panel"; +input bool eaShowPanel = false; // Show Management Panel +double eaPanelAllowedTPSLStep = 10; // Value for Change TP/SL in Each Step +double eaPanelMinAllowedRiskInPoint = 20; // Min Allowed Risk in Point +double eaPanelRiskInPoint = 50; // Risk in Point per Trades +double eaPanelRiskToRewardRatio = 2.0; // Risk To Reward per Trades +double eaPanelVolume = X_MIN_VOLUME; // Default volume Per Trade + +// +// Variables ... + +// +XCBaseExpert *eaExpert; + +// +// Event Handlers ... + +/** + * Initialize EA Process ... + * + * @return ( int ) + */ +int OnInit() +{ + // + // Preparing Tags ... + string eaTag = + (IsValid(eaLogSuffix) + ? eaLogSuffix + "_" + : "") + + ShortName; + + // + // Validate Inputs and Required Parameters ... + + // for EA to Works fine ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Timer ... + if (!InitTimer()) + { + return INIT_FAILED; + } + + // + // Configure EA Expert Class ... + eaExpert = new XCBaseExpert(); + + // + // Setting All Inputs to Expert Adviser Class ... + + // + // Common ... + eaExpert.eaMagicNumber = eaMagicNumber; + eaExpert.eaSlippage = eaSlippage; + eaExpert.eaLogSuffix = eaTag; + + // + // Symbols ... + eaExpert.eaSymbolConfiguration = eaSymbolConfiguration; + + // + // Management ... + eaExpert.eaAllowGuards = eaAllowGuards; + eaExpert.eaAllowTrade = eaAllowTrade; + eaExpert.eaAllowLongs = eaAllowLongs; + eaExpert.eaAllowShorts = eaAllowShorts; + eaExpert.eaMaxAllowedDrawdownFactor = eaMaxAllowedDrawdownFactor; + + // + // Volume ... + eaExpert.eaVolumeSelect = eaVolumeSelect; + eaExpert.eaStaticVoluem = eaStaticVoluem; + eaExpert.eaDynamicVolumeStepBalance = eaDynamicVolumeStepBalance; + eaExpert.eaDynamicVolumeStepVolume = eaDynamicVolumeStepVolume; + eaExpert.eaConstantRiskBalance = eaConstantRiskBalance; + eaExpert.eaConstantPercent = eaConstantPercent; + eaExpert.eaConstantBalance = eaConstantBalance; + + // + // Alert ... + eaExpert.eaEnableAlerts = eaEnableAlerts; + eaExpert.eaSaveAlerts = eaSaveAlerts; + eaExpert.eaLogAlerts = eaLogAlerts; + eaExpert.eaMailAlerts = eaMailAlerts; + eaExpert.eaPushAlerts = eaPushAlerts; + eaExpert.eaTerminalAlerts = eaTerminalAlerts; + + // + // Reports ... + eaExpert.eaReportNewMonths = eaReportNewMonths; + eaExpert.eaReportNewWeeks = eaReportNewWeeks; + eaExpert.eaReportNewDays = eaReportNewDays; + eaExpert.eaReportNewHours = eaReportNewHours; + eaExpert.eaReportTrades = eaReportTrades; + eaExpert.eaReportSignals = eaReportSignals; + eaExpert.eaReportRestrictions = eaReportRestrictions; + eaExpert.eaReportProtector = eaReportProtector; + eaExpert.eaReportAfterTradesBalance = eaReportAfterTradesBalance; + + // + // Collector ... + eaExpert.eaSaveTrades = eaSaveTrades; + eaExpert.eaSaveSignals = eaSaveSignals; + eaExpert.eaSaveWins = eaSaveWins; + eaExpert.eaSaveLosts = eaSaveLosts; + eaExpert.eaSaveRestrictions = eaSaveRestrictions; + + // + // Management Panel ... + eaExpert.eaShowPanel = eaShowPanel; + eaExpert.eaPanelAllowedTPSLStep = eaPanelAllowedTPSLStep; + eaExpert.eaPanelMinAllowedRiskInPoint = eaPanelMinAllowedRiskInPoint; + eaExpert.eaPanelRiskInPoint = eaPanelRiskInPoint; + eaExpert.eaPanelRiskToRewardRatio = eaPanelRiskToRewardRatio; + eaExpert.eaPanelVolume = eaPanelVolume; + + // + // Attach Event Handlers ... + eaExpert.AddOnSignalEventHandler(OnSignalTriggered); + eaExpert.onGuardedEventHandler = OnGuardedTriggered; + eaExpert.AddOnDealsChangedEventHandler(OnDealsChanged); + eaExpert.AddOnStopLossEventHandler(OnStopLossTriggered); + eaExpert.AddOnOrdersChangedEventHandler(OnOrdersChanged); + eaExpert.canAnalyseEventHandler = CanAnalyseEventTriggered; + eaExpert.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); + eaExpert.checkForGuardEventHandler = CheckForGuardTriggered; + eaExpert.AddOnModifyPositionEventHandler(OnPositionModified); + eaExpert.AddOnPositionsChangedEventHandler(OnPositionsChanged); + eaExpert.AddOnTradeStateChangedEventHandler(OnTradeStateChanged); + eaExpert.AddOnForceClosePositionEventHandler(OnPositionForceClosed); + eaExpert.AddOnPartialClosePositionEventHandler(OnPositionPartialClosed); + + // + // Try to Initialize eaExpert ... + bool isInited = eaExpert.HandleOnInit(); + if (!isInited) + { + // + Print(ShortName, ": Initialization Failed ..."); + return INIT_FAILED; + } + + // + Print(ShortName, ": Initialized Successfully ..."); + return INIT_SUCCEEDED; +} + +/** + * De Initialize Expert ... + * + * @param reason: int, DeInitialization Reason ... + * + * REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + * REASON_REMOVE 1 Program removed from a chart + * REASON_RECOMPILE 2 Program recompiled + * REASON_CHARTCHANGE 3 A symbol or a chart period is changed + * REASON_CHARTCLOSE 4 Chart closed + * REASON_PARAMETERS 5 Inputs changed by a user + * REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + * REASON_TEMPLATE 7 Another chart template applied + * REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + * REASON_CLOSE 9 Terminal closed + * + */ +void OnDeinit(const int reason) +{ + // + // Destroy Timer ... + // If Initialized ... + + // + // De Init Expert Class Instance ... + eaExpert.HandleOnDeInit(); + + // + // Cleanup Resources ... + delete eaExpert; + ZeroMemory(eaExpert); +} + +/** + * Handle Tick for Processing ... + */ +void OnTick() +{ + eaExpert.HandleOnTick(); +} + +/** + * Handle On Trade Processing ... + */ +void OnTrade() +{ + eaExpert.HandleOnTrade(); +} + +/** + * Handle On Timer Processing ... + */ +void OnTimer() +{ + eaExpert.HandleOnTimer(); +} + +/** + * Handle On Chart Event Processing ... + + * @param id: int, Specified Event ID ... + * @param lparam: long, type event parameter + * @param dparam: double, type event parameter + * @param sparam: string, type event parameter + */ +void OnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // +) +{ + eaExpert.HandleOnChartEvent(id, lparam, dparam, sparam); +} + +// +// Event Listeners ... + +/** + * Handle CanAnalyse Event Triggered ... + * + * @param symbol: Symbol ... + * @param period: Period ... + * @param time: Analysing Time ... + * + * @return ( bool ) + */ +bool CanAnalyseEventTriggered( + string symbol, + ENUM_TIMEFRAMES period, + datetime time // +) +{ + return eaExpert.HandleCanAnalyseEventTriggered( + symbol, + period, + time // + ); +} + +/** + * Check For Guard Event Handler ... + * + * @param guards: XGuard[] + * + * @return ( int ) + */ +int CheckForGuardTriggered(XGuard &guards[]) +{ + return eaExpert.CheckForGuardTriggered(guards); +} + +/** + * Handle Guard Events ... + * + * @param action: ENUM_X_GUARD_ACTIONS + * @param positions: XPosition[] + */ +void OnGuardedTriggered( + ENUM_X_GUARD_ACTIONS action, + XPosition &positions[] // +) +{ + eaExpert.OnGuardedTriggered(action, positions); +} + +/** + * Trigger OnSignal Event ... + * + * @param signal: XSignal + */ +void OnSignalTriggered(XSignal &signal) +{ + eaExpert.HandleOnSignalTriggered(signal); +} + +/** + * Handle StopLoss Triggered Positions ... + * + * @param deal: XDeal instance ... + */ +void OnStopLossTriggered(const XDeal &deal) +{ + eaExpert.HandleOnStopLossTriggered(deal); +} + +/** + * Handle Take Profit Triggered Positions ... + * + * @param deal: XDeal instance ... + */ +void OnTakeProfitTriggered(const XDeal &deal) +{ + eaExpert.HandleOnTakeProfitTriggered(deal); +} + +/** + * Handle Force Close a Position ... + * + * @param ticket: ULONG ... + * @param position: XPosition instance ... + * @param comment: String ... + */ +void OnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // +) +{ + // + eaExpert.HandleOnPositionForceClosed( + ticket, + position, + comment // + ); +} + +/** + * Handle Deals Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnDealsChanged(int count) +{ + eaExpert.HandleOnDealsChanged(count); +} + +/** + * Handle Orders Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnOrdersChanged(int count) +{ + eaExpert.HandleOnOrdersChanged(count); +} + +/** + * Handle Positions Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnPositionsChanged(int count) +{ + eaExpert.HandleOnPositionsChanged(count); +} + +/** + * Handle Position Modified ... + * + * @param ticket: ulong, Position Ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ +void OnPositionModified( + const ulong ticket, + const double profit, + const string comment // +) +{ + // + eaExpert.HandleOnPositionModified( + ticket, + profit, + comment // + ); +} + +/** + * Handle Position Partial Closed ... + * + * @param ticket: ulong, Position Ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ +void OnPositionPartialClosed( + const ulong ticket, + const double profit, + const string comment // +) +{ + // + eaExpert.HandleOnPositionPartialClosed( + ticket, + profit, + comment // + ); +} + +/** + * Handle Trade State Changed ... + * + * @param state: XOnTradeHandlerState instance ... + */ +void OnTradeStateChanged(const XOnTradeHandlerState &state) +{ + eaExpert.HandleOnTradeStateChanged(state); +} + +// +// Custom Functions ... + +/** + * Validate all Inputs of Expert Adviser ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + string errMessage = ""; + + // + bool isCommonValid = ( + // + eaSlippage > 0 && + eaMagicNumber > 0 + // + ); + if (!isCommonValid) + { + // + errMessage += "common configurations error;" + "\n"; + } + + // + result = + // + // Common ... + isCommonValid && + // + // Otere ... + true + // + ; + + // + if (!result) + { + // + // Since here Logger not Initiallized, we Use Raw Print Command ... + Print(ShortName + " Errors: \n", errMessage); + } + + // + return result; +} + +/** + * Initialize Timer ... + * + * @return ( bool ) + */ +bool InitTimer() +{ + // + bool result = false; + + // + // TODO: Initialize Timer if necessary ... + // result = EventSetTimer(1); + // result = EventSetMillisecondTimer(100); + result = true; + + // + return result; +} + +/** + * Destroy Timer ... + */ +void DestroyTimer() +{ + // + // TODO: Use This ... + // EventKillTimer(); +} + +// \ No newline at end of file diff --git a/Experts/x-saherelm.x121.xcatb.ea.mq5 b/Experts/x-saherelm.x121.xcatb.ea.mq5 index dbcdd4e0..a4e82ec4 100644 --- a/Experts/x-saherelm.x121.xcatb.ea.mq5 +++ b/Experts/x-saherelm.x121.xcatb.ea.mq5 @@ -15,6 +15,7 @@ #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://saherelm.ir" #property version "1.00" +#property icon "../Images/SaherElm_Logo_Color.ico" #property description "SaherElm X121XCATB based Expert Advisor" #property strict diff --git a/Experts/x-saherelm.xfima.ea.mq5 b/Experts/x-saherelm.xfima.ea.mq5 new file mode 100644 index 00000000..0a43a8f2 --- /dev/null +++ b/Experts/x-saherelm.xfima.ea.mq5 @@ -0,0 +1,613 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XFIMAEA +// Description: Base Expert Advisor as Template ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property icon "../Images/SaherElm_Logo_Color.ico" +#property description "SaherElm XFIMA Expert Advisor" +#property strict + +// +#define ShortName "XFIMAEA" + +// +// Importts ... +#include "../XFIMA/Classes/x-saherelm.xfima.expert.class.mq5" + +// +// Inputs ... + +// +// Common ... +input group "Common"; +input long eaMagicNumber = 1694056; // Magic Number +input int eaSlippage = 10; // Slippgae +input string eaLogSuffix = ""; // Log Suffix + +// +// Symbols +// [ +// Symbol| +// period| +// (ST_04:00_08:30),(TL_10:30_12:00),(NY_16:00_20:00)| +// maxAllowedSpread| +// maxAllowedPosition| +// ( +// restrictionsPeriod, +// restrictionsMultiplier, +// maxAllowedTPs, +// maxAllowedSLs, +// maxAllowedTrades, +// closeAllOpenTradesAt +// ) +// ] +// +// +// [EURUSDb|M5||25.0|5|] +// [XAUUSDb|M5|(ST_04:00_08:30),(TL_10:30_12:00),(NY_16:00_20:00)|25.0|5|(XTRADE_RESTRICATION_DAILY,1,0,2,0)] +// [XAUUSDb|M5|(ST_04:00_08:30),(TL_10:30_12:00),(NY_16:00_20:00)|25.0|5|(XTRADE_RESTRICATION_DAILY,3,0,2,0)] +input string eaSymbolConfiguration = "[EURUSDb|M5||25.0|5|]"; // Symbol Configurations + +// +// Management ... +input group "Management"; +input bool eaAllowGuards = false; // Allow Guards +input bool eaAllowTrade = true; // Allow Trade on Signals +input bool eaAllowLongs = true; // Allow Long Trades +input bool eaAllowShorts = true; // Allow Short Trades +input double eaMaxAllowedDrawdownFactor = 0.3; // Max Allowed DrawDown for Trade + +// +// Volume ... +input group "Volume"; +input ENUM_X_VOLUME_SELECT_TYPE eaVolumeSelect = X_VOLUME_CONSTANT; // Volume Applying Type +input double eaStaticVoluem = 0.0; // Static Volume +input double eaDynamicVolumeStepBalance = 0.0; // Step of Balance for Increase Volume +input double eaDynamicVolumeStepVolume = X_MIN_VOLUME; // Step of Volume Increasing +input double eaConstantRiskBalance = 0.0; // Constant Risk Balance per Trade +input double eaConstantPercent = 1; // Constant Percent of Balance Per Trade +input double eaConstantBalance = 1000.0; // Constant Balance for Calculations + +// +// Alert ... +input group "Alert"; +input bool eaEnableAlerts = true; // Enable Alerts +input bool eaSaveAlerts = true; // Save Alerts +input bool eaLogAlerts = true; // Log Alerts +input bool eaMailAlerts = false; // Mail Alerts +input bool eaPushAlerts = true; // Push Alerts +input bool eaTerminalAlerts = false; // Terminal Alerts + +// +// Reports ... +input group "Reports"; +input bool eaReportNewMonths = false; // Report New Month +input bool eaReportNewWeeks = false; // Report New Weeks +input bool eaReportNewDays = true; // Report New Days +input bool eaReportNewHours = false; // Report New Hours +input bool eaReportTrades = true; // Report Trades +input bool eaReportSignals = true; // Report Signals +input bool eaReportRestrictions = true; // Report Restrictions +input bool eaReportProtector = true; // Report Protector Actions +input bool eaReportAfterTradesBalance = true; // Report Balance after a Trade Finished + +// +// Collector ... +input group "Collector"; +input bool eaSaveTrades = true; // Save Trades +input bool eaSaveSignals = true; // Save Signals +input bool eaSaveWins = true; // Save Winning Conditions +input bool eaSaveLosts = true; // Save Lost Conditions +input bool eaSaveRestrictions = true; // Save Restriction Reports + +// +// Management Panel ... +input group "Management Panel"; +input bool eaShowPanel = false; // Show Management Panel +double eaPanelAllowedTPSLStep = 10; // Value for Change TP/SL in Each Step +double eaPanelMinAllowedRiskInPoint = 20; // Min Allowed Risk in Point +double eaPanelRiskInPoint = 50; // Risk in Point per Trades +double eaPanelRiskToRewardRatio = 2.0; // Risk To Reward per Trades +double eaPanelVolume = X_MIN_VOLUME; // Default volume Per Trade + +// +// Variables ... + +// +XCXFIMAExpret *eaExpert; + +// +// Event Handlers ... + +/** + * Initialize EA Process ... + * + * @return ( int ) + */ +int OnInit() +{ + // + // Preparing Tags ... + string eaTag = + (IsValid(eaLogSuffix) + ? eaLogSuffix + "_" + : "") + + ShortName; + + // + // Validate Inputs and Required Parameters ... + + // for EA to Works fine ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Timer ... + if (!InitTimer()) + { + return INIT_FAILED; + } + + // + // Configure EA Expert Class ... + eaExpert = new XCXFIMAExpret(); + + // + // Setting All Inputs to Expert Adviser Class ... + + // + // Common ... + eaExpert.eaMagicNumber = eaMagicNumber; + eaExpert.eaSlippage = eaSlippage; + eaExpert.eaLogSuffix = eaTag; + + // + // Symbols ... + eaExpert.eaSymbolConfiguration = eaSymbolConfiguration; + + // + // Management ... + eaExpert.eaAllowGuards = eaAllowGuards; + eaExpert.eaAllowTrade = eaAllowTrade; + eaExpert.eaAllowLongs = eaAllowLongs; + eaExpert.eaAllowShorts = eaAllowShorts; + eaExpert.eaMaxAllowedDrawdownFactor = eaMaxAllowedDrawdownFactor; + + // + // Volume ... + eaExpert.eaVolumeSelect = eaVolumeSelect; + eaExpert.eaStaticVoluem = eaStaticVoluem; + eaExpert.eaDynamicVolumeStepBalance = eaDynamicVolumeStepBalance; + eaExpert.eaDynamicVolumeStepVolume = eaDynamicVolumeStepVolume; + eaExpert.eaConstantRiskBalance = eaConstantRiskBalance; + eaExpert.eaConstantPercent = eaConstantPercent; + eaExpert.eaConstantBalance = eaConstantBalance; + + // + // Alert ... + eaExpert.eaEnableAlerts = eaEnableAlerts; + eaExpert.eaSaveAlerts = eaSaveAlerts; + eaExpert.eaLogAlerts = eaLogAlerts; + eaExpert.eaMailAlerts = eaMailAlerts; + eaExpert.eaPushAlerts = eaPushAlerts; + eaExpert.eaTerminalAlerts = eaTerminalAlerts; + + // + // Reports ... + eaExpert.eaReportNewMonths = eaReportNewMonths; + eaExpert.eaReportNewWeeks = eaReportNewWeeks; + eaExpert.eaReportNewDays = eaReportNewDays; + eaExpert.eaReportNewHours = eaReportNewHours; + eaExpert.eaReportTrades = eaReportTrades; + eaExpert.eaReportSignals = eaReportSignals; + eaExpert.eaReportRestrictions = eaReportRestrictions; + eaExpert.eaReportProtector = eaReportProtector; + eaExpert.eaReportAfterTradesBalance = eaReportAfterTradesBalance; + + // + // Collector ... + eaExpert.eaSaveTrades = eaSaveTrades; + eaExpert.eaSaveSignals = eaSaveSignals; + eaExpert.eaSaveWins = eaSaveWins; + eaExpert.eaSaveLosts = eaSaveLosts; + eaExpert.eaSaveRestrictions = eaSaveRestrictions; + + // + // Management Panel ... + eaExpert.eaShowPanel = eaShowPanel; + eaExpert.eaPanelAllowedTPSLStep = eaPanelAllowedTPSLStep; + eaExpert.eaPanelMinAllowedRiskInPoint = eaPanelMinAllowedRiskInPoint; + eaExpert.eaPanelRiskInPoint = eaPanelRiskInPoint; + eaExpert.eaPanelRiskToRewardRatio = eaPanelRiskToRewardRatio; + eaExpert.eaPanelVolume = eaPanelVolume; + + // + // Attach Event Handlers ... + eaExpert.AddOnSignalEventHandler(OnSignalTriggered); + eaExpert.onGuardedEventHandler = OnGuardedTriggered; + eaExpert.AddOnDealsChangedEventHandler(OnDealsChanged); + eaExpert.AddOnStopLossEventHandler(OnStopLossTriggered); + eaExpert.AddOnOrdersChangedEventHandler(OnOrdersChanged); + eaExpert.canAnalyseEventHandler = CanAnalyseEventTriggered; + eaExpert.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); + eaExpert.checkForGuardEventHandler = CheckForGuardTriggered; + eaExpert.AddOnModifyPositionEventHandler(OnPositionModified); + eaExpert.AddOnPositionsChangedEventHandler(OnPositionsChanged); + eaExpert.AddOnTradeStateChangedEventHandler(OnTradeStateChanged); + eaExpert.AddOnForceClosePositionEventHandler(OnPositionForceClosed); + eaExpert.AddOnPartialClosePositionEventHandler(OnPositionPartialClosed); + + // + // TODO: Attach other Requirements if necessary ... + + // + // Try to Initialize eaExpert ... + bool isInited = eaExpert.HandleOnInit(); + if (!isInited) + { + // + Print(ShortName, ": Initialization Failed ..."); + return INIT_FAILED; + } + + // + Print(ShortName, ": Initialized Successfully ..."); + return INIT_SUCCEEDED; +} + +/** + * De Initialize Expert ... + * + * @param reason: int, DeInitialization Reason ... + * + * REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + * REASON_REMOVE 1 Program removed from a chart + * REASON_RECOMPILE 2 Program recompiled + * REASON_CHARTCHANGE 3 A symbol or a chart period is changed + * REASON_CHARTCLOSE 4 Chart closed + * REASON_PARAMETERS 5 Inputs changed by a user + * REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + * REASON_TEMPLATE 7 Another chart template applied + * REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + * REASON_CLOSE 9 Terminal closed + * + */ +void OnDeinit(const int reason) +{ + // + // Destroy Timer ... + // If Initialized ... + + // + // De Init Expert Class Instance ... + eaExpert.HandleOnDeInit(); + + // + // Cleanup Resources ... + delete eaExpert; + ZeroMemory(eaExpert); +} + +/** + * Handle Tick for Processing ... + */ +void OnTick() +{ + eaExpert.HandleOnTick(); +} + +/** + * Handle On Trade Processing ... + */ +void OnTrade() +{ + eaExpert.HandleOnTrade(); +} + +/** + * Handle On Timer Processing ... + */ +void OnTimer() +{ + eaExpert.HandleOnTimer(); +} + +/** + * Handle On Chart Event Processing ... + + * @param id: int, Specified Event ID ... + * @param lparam: long, type event parameter + * @param dparam: double, type event parameter + * @param sparam: string, type event parameter + */ +void OnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // +) +{ + eaExpert.HandleOnChartEvent(id, lparam, dparam, sparam); +} + +// +// Event Listeners ... + +/** + * Handle CanAnalyse Event Triggered ... + * + * @param symbol: Symbol ... + * @param period: Period ... + * @param time: Analysing Time ... + * + * @return ( bool ) + */ +bool CanAnalyseEventTriggered( + string symbol, + ENUM_TIMEFRAMES period, + datetime time // +) +{ + return eaExpert.HandleCanAnalyseEventTriggered( + symbol, + period, + time // + ); +} + +/** + * Check For Guard Event Handler ... + * + * @param guards: XGuard[] + * + * @return ( int ) + */ +int CheckForGuardTriggered(XGuard &guards[]) +{ + return eaExpert.CheckForGuardTriggered(guards); +} + +/** + * Handle Guard Events ... + * + * @param action: ENUM_X_GUARD_ACTIONS + * @param positions: XPosition[] + */ +void OnGuardedTriggered( + ENUM_X_GUARD_ACTIONS action, + XPosition &positions[] // +) +{ + eaExpert.OnGuardedTriggered(action, positions); +} + +/** + * Trigger OnSignal Event ... + * + * @param signal: XSignal + */ +void OnSignalTriggered(XSignal &signal) +{ + eaExpert.HandleOnSignalTriggered(signal); +} + +/** + * Handle StopLoss Triggered Positions ... + * + * @param deal: XDeal instance ... + */ +void OnStopLossTriggered(const XDeal &deal) +{ + eaExpert.HandleOnStopLossTriggered(deal); +} + +/** + * Handle Take Profit Triggered Positions ... + * + * @param deal: XDeal instance ... + */ +void OnTakeProfitTriggered(const XDeal &deal) +{ + eaExpert.HandleOnTakeProfitTriggered(deal); +} + +/** + * Handle Force Close a Position ... + * + * @param ticket: ULONG ... + * @param position: XPosition instance ... + * @param comment: String ... + */ +void OnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // +) +{ + // + eaExpert.HandleOnPositionForceClosed( + ticket, + position, + comment // + ); +} + +/** + * Handle Deals Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnDealsChanged(int count) +{ + eaExpert.HandleOnDealsChanged(count); +} + +/** + * Handle Orders Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnOrdersChanged(int count) +{ + eaExpert.HandleOnOrdersChanged(count); +} + +/** + * Handle Positions Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnPositionsChanged(int count) +{ + eaExpert.HandleOnPositionsChanged(count); +} + +/** + * Handle Position Modified ... + * + * @param ticket: ulong, Position Ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ +void OnPositionModified( + const ulong ticket, + const double profit, + const string comment // +) +{ + // + eaExpert.HandleOnPositionModified( + ticket, + profit, + comment // + ); +} + +/** + * Handle Position Partial Closed ... + * + * @param ticket: ulong, Position Ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ +void OnPositionPartialClosed( + const ulong ticket, + const double profit, + const string comment // +) +{ + // + eaExpert.HandleOnPositionPartialClosed( + ticket, + profit, + comment // + ); +} + +/** + * Handle Trade State Changed ... + * + * @param state: XOnTradeHandlerState instance ... + */ +void OnTradeStateChanged(const XOnTradeHandlerState &state) +{ + eaExpert.HandleOnTradeStateChanged(state); +} + +// +// Custom Functions ... + +/** + * Validate all Inputs of Expert Adviser ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + string errMessage = ""; + + // + bool isCommonValid = ( + // + eaSlippage > 0 && + eaMagicNumber > 0 + // + ); + if (!isCommonValid) + { + // + errMessage += "common configurations error;" + "\n"; + } + + // + result = + // + // Common ... + isCommonValid && + // + // Otere ... + true + // + ; + + // + if (!result) + { + // + // Since here Logger not Initiallized, we Use Raw Print Command ... + Print(ShortName + " Errors: \n", errMessage); + } + + // + return result; +} + +/** + * Initialize Timer ... + * + * @return ( bool ) + */ +bool InitTimer() +{ + // + bool result = false; + + // + // TODO: Initialize Timer if necessary ... + // result = EventSetTimer(1); + // result = EventSetMillisecondTimer(100); + result = true; + + // + return result; +} + +/** + * Destroy Timer ... + */ +void DestroyTimer() +{ + // + // TODO: Use This ... + // EventKillTimer(); +} + +// \ No newline at end of file diff --git a/Experts/x-saherelm.xom1.ea.mq5 b/Experts/x-saherelm.xom1.ea.mq5 index 473dbabb..e8b759ea 100644 --- a/Experts/x-saherelm.xom1.ea.mq5 +++ b/Experts/x-saherelm.xom1.ea.mq5 @@ -15,6 +15,7 @@ #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://saherelm.ir" #property version "1.00" +#property icon "../Images/SaherElm_Logo_Color.ico" #property description "SaherElm XOM1 based Expert Advisor" #property strict diff --git a/XFIMA/Classes/x-saherelm.xfima.expert.class.mq5 b/XFIMA/Classes/x-saherelm.xfima.expert.class.mq5 new file mode 100644 index 00000000..c23be68d --- /dev/null +++ b/XFIMA/Classes/x-saherelm.xfima.expert.class.mq5 @@ -0,0 +1,117 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class +// ------------------------------------------------- +// Name: XCXFIMAExpret ... +// Description: XFIMA Expert Class ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XFIMA Expert Class" +#property strict + +// +// Imports ... +#include "../../Classes/x-saherelm.x-expert.class.mq5" +#include "../Classes/x-saherelm.xfima.signaller.class.mq5" + +// +// Definitions ... + +// +// Implementation ... +class XCXFIMAExpret : public XCBaseExpert +{ + // + // Public ... + public: + // + + // + // Overrides ... + + /** + * Prepare Signallers per Symbol Config ... + * + * @param symbolConfig: XSymbolTradeConfig, Symbol Trade Configurations ... + */ + void PrepareSignallers(XSymbolTradeConfig &symbolConfig) override + { + // + // Validate ... + if (!symbolConfig.IsValid()) + { + return; + } + + // + // Instantiate Signaller ... + + // + // XFIMA Inputs ... + + // + XFIMAInputs fimaInputs; + fimaInputs.Default(); + fimaInputs.Hide(); + + // + // Instantiate Signaller Class ... + XCXFIMAStrategy1Signaller *fima1Signaller = new XCXFIMAStrategy1Signaller( + symbolConfig.symbol, + symbolConfig.period, + fimaInputs, + false // Process All Ticks ... + ); + if (!fima1Signaller.IsValid()) + { + // + fima1Signaller.Destroy(); + delete fima1Signaller; + ZeroMemory(fima1Signaller); + return; + } + + // + // Register Signaller ... + RegisterSignaller((XCBaseSignaller *)fima1Signaller); + + // + // Cleanup Resources ... + fimaInputs.Clean(); + ZeroMemory(fima1Signaller); + } + + /** + * Additional On Tick Processing if Required ... + * + * @param barIndex: int, Specified Bar Index ... + */ + void virtual HandleOnTickAdditional(int barIndex = 0) + { + // + // Implement this if required ... + } + + // + // Protected ... + protected: + // + + // + // Private ... + private: + // +}; + +// \ No newline at end of file diff --git a/XFIMA/Classes/x-saherelm.xfima.signaller.class.mq5 b/XFIMA/Classes/x-saherelm.xfima.signaller.class.mq5 index 6b41f5b7..a1ea45b9 100644 --- a/XFIMA/Classes/x-saherelm.xfima.signaller.class.mq5 +++ b/XFIMA/Classes/x-saherelm.xfima.signaller.class.mq5 @@ -5,7 +5,7 @@ // Name: XCXFIMASignaller ... // Description: XFIMA Signaller Class ... // -// +// // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) @@ -17,8 +17,341 @@ #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://saherelm.ir" #property version "1.00" -#property description "SaherElm Base Signaller Class" +#property description "SaherElm XFIMA Signaller Class" #property strict // // Imports ... +#include "../../Classes/x-saherelm.x-signaller.class.mq5" +#include "../../Helpers/x-saherelm.xfima.helper.mq5" + +// +// Implementation ... + +// +// Base XFIMA base Signaller ... +class XCXFIMABaseSignaller : public XCBaseSignaller +{ + // + // Public ... + public: + // + // Props ... + + // + XFIMAInputs fimaInputs; // XFIMA Inputs ... + XCXFIMAHelper *fimaHelper; // XFIMA Indicator Helper ... + + // + // Constructor ... + XCXFIMABaseSignaller( + string _name, // Name ... + string _symbol, // Symbol ... + ENUM_TIMEFRAMES _period, // Period ... + XFIMAInputs &_fimaInputs, // XFIMAInputs ... + bool _processAllTicks = false, // Process All Ticks ... + double _defaultSignalR2R = 1.5, // Default Signal Risk To Reward Ratio ... + double _defaultSignalRiskInPoint = 50, // Default Signal Risk In Point ... + double _defaultSignalVolume = 0.01 // Default Signal Volume ... + ) : XCBaseSignaller(_name, + _symbol, + _period, + _processAllTicks, + _defaultSignalR2R, + _defaultSignalRiskInPoint, + _defaultSignalVolume // + ) + { + // + // Instantiating XFIMA Indicator Helper Class ... + if (_fimaInputs.IsValid()) + { + // + fimaHelper = new XCXFIMAHelper(); + bool isInited = fimaHelper.Init( + _symbol, + _period, + _fimaInputs // + ); + if (isInited) + { + fimaInputs = _fimaInputs; + } + else + { + // + delete fimaHelper; + ZeroMemory(fimaHelper); + } + } + } + + // + // Deconstructor ... + ~XCXFIMABaseSignaller() + { + Destroy(); + } + + // + // Overrides ... + + // + // Actions ... + + /** + * Destroy ... + */ + void Destroy() + { + // + BeforeDestroy(); + + // + fimaInputs.Clean(); + + // + delete fimaHelper; + ZeroMemory(fimaHelper); + } + + // + // Virtuals ... + + /** + * Before Destroy ... + */ + void virtual BeforeDestroy() + { + } + + /** + * Processing Tick ... + * + * @param barIndex: int, Specified Bar Index ... + */ + virtual void ProcessTick(int barIndex = 0) + { + } + + /** + * Processing New Bar ... + * + * @param barIndex: int, Specified Bar Index ... + */ + virtual void ProcessNewBar(int barIndex = 0) + { + } + + /** + * Check Guards Based on MarketConditions ... + * + * @param guards: XGuard[] + * @param barIndex: int + * + * @return ( int ) + */ + int virtual CheckForGuard( + XGuard &guards[], + int barIndex = 0 // + ) + { + // + int result = 0; + + // + SpecifiedClean(guards); + + // + result = ArraySize(guards); + + // + return result; + } + + /** + * Check Additional Validations on Childs Instances ... + * + * @return ( bool virtual ) + */ + bool virtual CheckAdditionslSignallerValidations() + { + // + bool result = false; + + // + // Validate Fima Helper Requirements ... + result = fimaInputs.IsValid() && + fimaHelper != NULL; + + // + return result; + } + + // + // Protected ... + protected: + // + + // + // Private ... + private: + // +}; + +// +// XFIMA Strategy 1 Signaller Class ... +class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructor ... + XCXFIMAStrategy1Signaller( + string _symbol, // Symbol ... + ENUM_TIMEFRAMES _period, // Period ... + XFIMAInputs &_fimaInputs, // XFIMAInputs ... + bool _processAllTicks = false, // Process All Ticks ... + double _defaultSignalR2R = 1.5, // Default Signal Risk To Reward Ratio ... + double _defaultSignalRiskInPoint = 50, // Default Signal Risk In Point ... + double _defaultSignalVolume = 0.01 // Default Signal Volume ... + ) : XCXFIMABaseSignaller("XFIMA1", + _symbol, + _period, + _fimaInputs, + _processAllTicks, + _defaultSignalR2R, + _defaultSignalRiskInPoint, + _defaultSignalVolume // + ) + { + } + + // + // Overrides ... + + /** + * Processing Tick ... + * + * @param barIndex: int, Specified Bar Index ... + */ + virtual void ProcessTick(int barIndex = 0) + { + } + + /** + * Processing New Bar ... + * + * @param barIndex: int, Specified Bar Index ... + */ + virtual void ProcessNewBar(int barIndex = 0) + { + // + // Normalize ... + barIndex = NormalizeInt(barIndex, 0); + + // + // Update Helper ... + fimaHelper.Update(barIndex); + + // + XOHCL bar; + XSignal signal; + bool has = false; + ENUM_X_DIRECTION signalDir = X_DIRECTION_NONE; + + // + // Initialize Bar ... + has = bar.Init( + symbol, + period, + barIndex // + ); + if (!has) + { + // + bar.Clean(); + return; + } + + // + // Retrieve Conditions ... + XFIMAConditions fimaConditions; + has = fimaHelper.GetConditions( + fimaConditions, + barIndex, + 10 // Loopback ... + ); + if (!has) + { + // + bar.Clean(); + fimaConditions.Clean(); + + // + return; + } + + // + // Analyse Conditions for Finding Signal ... + + // + // Check Signal Founded ... + has = HasDirection(signalDir); + if (has) + { + // + // Prepare Founded Signal ... + has = PrepareSignal( + signal, + signalDir // + ); + if (has) + { + // + // Notify On Signal Event ... + NotifySignalEventListeners(signal); + } + } + + // + // Cleanup Resources ... + bar.Clean(); + signal.Clean(); + fimaConditions.Clean(); + } + + /** + * Check Guards Based on MarketConditions ... + * + * @param guards: XGuard[] + * @param barIndex: int + * + * @return ( int ) + */ + int virtual CheckForGuard( + XGuard &guards[], + int barIndex = 0 // + ) + { + // + int result = 0; + + // + SpecifiedClean(guards); + + // + result = ArraySize(guards); + + // + return result; + } + + // +}; + +// \ No newline at end of file