From 9e2f375fbe21a9bb4e7ad9585949f577af4d05a7 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Mon, 15 Sep 2025 13:18:25 +0330 Subject: [PATCH] last ... --- .../x-saherelm.x-backtester.expert.class.mq5 | 1696 +++++++++++++++++ Classes/x-saherelm.x-chart.helper.class.mq5 | 609 +++++- Documents/BKP/backtester.temp.mq5 | 1484 +++++++++++++++ Experts/x-saherelm.backtester.mq5 | 1255 +----------- Experts/x-saherelm.xom1.ea.mq5 | 6 + 5 files changed, 3802 insertions(+), 1248 deletions(-) create mode 100644 Classes/x-saherelm.x-backtester.expert.class.mq5 create mode 100644 Documents/BKP/backtester.temp.mq5 diff --git a/Classes/x-saherelm.x-backtester.expert.class.mq5 b/Classes/x-saherelm.x-backtester.expert.class.mq5 new file mode 100644 index 00000000..5f153bc8 --- /dev/null +++ b/Classes/x-saherelm.x-backtester.expert.class.mq5 @@ -0,0 +1,1696 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XCBackTesterEA +// Description: Back Tester 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://www.saherelm.ir" +#property version "1.00" +#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-trade.class.mq5" +#include "../Classes/x-saherelm.x-volume.class.mq5" + +// +// Import Chart Objects ... +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Definitions ... + +// +// Implementation ... +class XCBackTesterEA : public XCBase +{ + // + // Public ... + public: + // + + // + // Common ... + long eaMagicNumber; // Magic Number + int eaSlippage; // Slippgae + string eaLogSuffix; // Log Suffix + + // + // Symbol / Period ... + string symbol; // Symbol + ENUM_TIMEFRAMES period; // Period + + // + // Alert ... + bool eaEnableAlerts; // Enable Alerts + bool eaLogAlerts; // Log Alerts + bool eaMailAlerts; // Mail Alerts + bool eaPushAlerts; // Push Alerts + bool eaTerminalAlerts; // Terminal Alerts + + // + // Constructor ... + XCBackTesterEA() + { + selectedPositionID = 0; + } + + // + // Deconstructor ... + ~XCBackTesterEA() + { + } + + // + // 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.SetEnableAlerts(eaEnableAlerts); + eaAlert.SetTerminalAlerts(eaTerminalAlerts); + + // + // Initialize Trader ... + eaTrader = new XCTrade( + eaSlippage, + eaMagicNumber, + 0, + 0, + 0 // + ); + + // + // 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]); + } + } + + // + // Initial GUI ... + result = InitGUI(); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Handle De Initialization of Expert ... + */ + void HandleOnDeInit() + { + // + delete eaTrader; + ZeroMemory(eaTrader); + + // + SpecifiedClean(mOnModifyEventHandlers); + SpecifiedClean(mStopLossEventHandlers); + SpecifiedClean(mTakeProfitEventHandlers); + SpecifiedClean(mOnForceCloseEventHandlers); + SpecifiedClean(mDealsChangedEventHandlers); + SpecifiedClean(mOrdersChangedEventHandlers); + SpecifiedClean(mOnPartialCloseEventHandlers); + SpecifiedClean(mPositionsChangedEventHandlers); + SpecifiedClean(mTradeStateChangedEventHandlers); + + // + DestroyGUI(); + + // + string message = "DeInitialized Successfully ..."; + eaAlert.SendAlert(message); + + // + delete eaAlert; + ZeroMemory(eaAlert); + } + + /** + * Handle Tick ... + */ + void HandleOnTick() + { + UpdateGUI(); + } + + /** + * Handle Trade ... + */ + void HandleOnTrade() + { + } + + /** + * Handle Timer ... + */ + void 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 HandleOnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // + ) + { + } + + // + // Validators ... + + /** + * Validate Inputs ... + * + * @return ( bool ) + */ + bool ValidateInputs() + { + // + bool result = false; + + // + // TODO: Handle this ... + result = true; + + // + return result; + } + + // + // Trade Event Handlers ... + + /** + * Handle Stop Loss Event Triggered ... + * + * @param deal: XDeal instance refrence, provides Triggered Deal info ... + */ + void HandleOnStopLossTriggered(const XDeal &deal) + { + // + // Update Position Buttons ... + UpdatePositionButtons(); + } + + /** + * Handle Take Profit Event Triggered ... + * + * @param deal: XDeal instance refrence, provides Triggered Deal info ... + */ + void HandleOnTakeProfitTriggered(const XDeal &deal) + { + // + // Update Position Buttons ... + UpdatePositionButtons(); + } + + /** + * Handle Position Force Closed Event ... + * + * @param ticket: ulong, triggered Positions ticket ... + * @param position: XPosition instance refrence, Triggered Position ... + * @param comment: string, Comment ... + */ + void HandleOnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // + ) + { + // + // Update Position Buttons ... + UpdatePositionButtons(); + } + + /** + * Handle Position Partially Closed Event ... + * + * @param ticket: ulong, triggered Positions ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ + void HandleOnPositionPartialClosed( + const ulong ticket, + const double profit, + const string 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 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 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 HandleOnPositionsChanged(int count) + { + // + // Update Position Buttons ... + UpdatePositionButtons(); + } + + /** + * Handle Position Modified Event ... + * + * @param ticket: ulong, triggered Positions ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ + void 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 HandleOnTradeStateChanged(const XOnTradeHandlerState &state) + { + } + + // + // Props and Setter / Getter (s) ... + + // + // Trade Event Listeners ... + + // + 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: + // + // Private ... + private: + // + // Props ... + + // + XCAlert *eaAlert; // EA Scope Alert Handler ... + XCTrade *eaTrader; // EA Scope Trade Handler ... + + // + // Trade Event Listeners ... + TOnModify mOnModifyEventHandlers[]; + TOnStopLoss mStopLossEventHandlers[]; + TOnTakeProfit mTakeProfitEventHandlers[]; + TOnForceClose mOnForceCloseEventHandlers[]; + TOnDealsChanged mDealsChangedEventHandlers[]; + TOnOrdersChanged mOrdersChangedEventHandlers[]; + TOnPartialClose mOnPartialCloseEventHandlers[]; + TOnPositionsChanged mPositionsChangedEventHandlers[]; + TOnTradeStateChanged mTradeStateChangedEventHandlers[]; + + // + XCChartHelper *mChartHelper; // Chart Helper Class ... + + // + // Object Props ... + + // + string objSuffix; + + // + CButton btnBuy; + CButton btnSell; + CButton btnClose; + CButton btnCloseAll; + CEdit lblPositionId; + + // + CArrayObj posArray; + CButton *btnSelectedPosInfo; + CArrayObj selectedPosInfoArr; + + // + int btnCloseSizeX; + int btnCloseSizeY; + int btnCloseStartX; + int btnCloseStartY; + int lblPositionIdSizeX; + int lblPositionIdSizeY; + int lblPositionIdStartX; + int lblPositionIdStartY; + + // + ulong selectedPositionID; + + // + // GUI Event(s) ... + + /** + * Initialize all GUI Requirements for EA ... + * + * @return ( bool ) + */ + bool InitGUI() + { + // + bool result = false; + + // + int subWindow = 0; + ulong chartId = ChartID(); + objSuffix = eaLogSuffix + "_"; + + // + // Initial Chart Class Instance ... + mChartHelper = new XCChartHelper(chartId); + + // + int startX = 5; + int startY = 25; + + // + int defaultGap = 5; + int defaultWidth = 100; + int defaultHeight = 30; + + // + // Buy ... + int btnBuyStartX = startX; + int btnBuySizeX = startX + defaultWidth; + int btnBuyStartY = startY; + int btnBuySizeY = startY + defaultHeight; + string btnBuyName = objSuffix + "BTN_BUY"; + result = btnBuy.Create( + chartId, + btnBuyName, + subWindow, + btnBuyStartX, + btnBuyStartY, + btnBuySizeX, + btnBuySizeY // + ); + if (result) + { + // + // Apply Buy Button Style ... + + // + btnBuy.Text("Buy"); + btnBuy.Color(clrYellow); + btnBuy.ColorBackground(clrGreen); + } + + // + // Sell ... + int btnSellStartX = btnBuyStartX + btnBuySizeX; + int btnSellSizeX = btnSellStartX + defaultWidth; + int btnSellStartY = btnBuyStartY; + int btnSellSizeY = btnBuySizeY; + string btnSellName = objSuffix + "BTN_SELL"; + result = btnSell.Create( + chartId, + btnSellName, + subWindow, + btnSellStartX, + btnSellStartY, + btnSellSizeX, + btnSellSizeY // + ); + if (result) + { + // + // Apply Sell Button Style ... + + // + btnSell.Text("Sell"); + btnSell.Color(clrYellow); + btnSell.ColorBackground(clrDarkRed); + } + + // + // LABEL Position ID ... + lblPositionIdStartX = btnBuyStartX; + lblPositionIdSizeX = lblPositionIdStartX + defaultWidth; + lblPositionIdStartY = btnSellSizeY + defaultGap; + lblPositionIdSizeY = lblPositionIdStartY + defaultHeight; + string lblPositionIdName = objSuffix + "LBL_POS_ID"; + result = lblPositionId.Create( + chartId, + lblPositionIdName, + subWindow, + lblPositionIdStartX, + lblPositionIdStartY, + lblPositionIdSizeX, + lblPositionIdSizeY // + ); + if (result) + { + // + // Apply Label Position ID Style ... + lblPositionId.ReadOnly(true); + lblPositionId.Text("Pos ID: "); + lblPositionId.Color(clrYellow); + lblPositionId.ColorBackground(clrDarkGray); + } + + // + // Close ... + btnCloseStartX = startX; + btnCloseSizeX = btnCloseStartX + defaultWidth; + btnCloseStartY = lblPositionIdSizeY + defaultGap; + btnCloseSizeY = lblPositionIdSizeY + defaultHeight; + string btnCloseName = objSuffix + "BTN_CLOSE"; + result = btnClose.Create( + chartId, + btnCloseName, + subWindow, + btnCloseStartX, + btnCloseStartY, + btnCloseSizeX, + btnCloseSizeY // + ); + if (result) + { + // + // Apply Close Button Style ... + + // + btnClose.Text("Close"); + btnClose.Color(clrYellow); + btnClose.ColorBackground(clrDarkOrange); + } + + // + // Close All ... + int btnCloseAllStartX = btnCloseSizeX + defaultGap; + int btnCloseAllSizeX = btnCloseAllStartX + defaultWidth; + int btnCloseAllStartY = lblPositionIdSizeY + defaultGap; + int btnCloseAllSizeY = lblPositionIdSizeY + defaultHeight; + string btnCloseAllName = objSuffix + "BTN_CLOSE_ALL"; + result = btnCloseAll.Create( + chartId, + btnCloseAllName, + subWindow, + btnCloseAllStartX, + btnCloseAllStartY, + btnCloseAllSizeX, + btnCloseAllSizeY // + ); + if (result) + { + // + // Apply Close Button Style ... + + // + btnCloseAll.Text("Close All"); + btnCloseAll.Color(clrYellow); + btnCloseAll.ColorBackground(clrDarkRed); + } + + // + UpdateGUIState(); + + // + return result; + } + + /** + * Update GUI based on Each Ticks ... + */ + void UpdateGUI() + { + // + UpdateGUIState(); + + // + // 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 = false; + 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 = iLbl.IsVisible(); + string btnText = isVisible + ? "Hide Info" + : "Show Info"; + btnSelectedPosInfo.Text(btnText); + } + + // + ZeroMemory(iLbl); + } + + // + btnSelectedPosInfo.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; + UpdateGUIState(); + } + } + + // + iBtn.Pressed(false); + } + + // + ZeroMemory(iBtn); + } + } + } + + /** + * Destroy all Initialized GUi Requirements ... + */ + void DestroyGUI() + { + // + delete mChartHelper; + ZeroMemory(mChartHelper); + + // + delete btnSelectedPosInfo; + ZeroMemory(btnSelectedPosInfo); + } + + /** + * Update GUI Element Styles ... + */ + void UpdateGUIState() + { + // + // 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 = mChartHelper.Width(); + ulong chartId = mChartHelper.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"; + + // + int btnStartX = btnCloseStartX; + int btnSizeX = btnStartX + 200 + 5; + + // + int btnStartY = btnCloseSizeY + 5; + int btnSizeY = btnStartY + 50; + + // + bool isCreated = btnSelectedPosInfo.Create( + chartId, + name, + subWindow, + btnStartX, + btnStartY, + btnSizeX, + btnSizeY // + ); + 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); + + // + 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 = iLbl.IsVisible(); + 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); + } + else + { + // + btnClose.Enable(); + btnClose.ColorBackground(clrDarkOrange); + } + } + + /** + * Update Position's Selector Buttons ... + */ + void UpdatePositionButtons() + { + // + // Retrieve Positions ... + XPosition positions[]; + int count = eaTrader.GetPositions( + positions // + ); + bool has = IsValidSize(count); + if (!has) + { + // + posArray.Clear(); + selectedPositionID = 0; + UpdateGUIState(); + 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 = mChartHelper.ChartId(); + + // + int btnWidth = 25; + + // + int lastX = lblPositionIdSizeX + 5; + int lastSizeX = lastX + btnWidth; + + // + int lastY = lblPositionIdStartY; + int lastSizeY = lblPositionIdSizeY; + + // + 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); + UpdateGUIState(); + } + + // + // GUI Event Handlers ... + + // + void HandleBuyTrade() + { + HandleTrade(X_DIRECTION_BULLISH); + } + + // + void HandleSellTrade() + { + HandleTrade(X_DIRECTION_BEARISH); + } + + // + void HandleTrade(ENUM_X_DIRECTION dir) + { + // + if (!HasDirection(dir)) + { + return; + } + + // + bool isBullish = IsSpecifiedBullish(dir); + + // + double r2r = 1.5; + double volume = 0.01; + double riskInPoints = 100; + double point = GetPoints(symbol); + double entry = GetEntry(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 = ShortName + "_POS_" + ToXString(dir); + + // + if (isBullish) + { + // + eaTrader.Buy( + symbol, + period, + volume, + entry, + sl, + tp, + comment // + ); + } + else + { + // + eaTrader.Sell( + symbol, + 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); + } + } + } + + // + // Custom Tools ... + + // + 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; + } +}; + +// \ No newline at end of file diff --git a/Classes/x-saherelm.x-chart.helper.class.mq5 b/Classes/x-saherelm.x-chart.helper.class.mq5 index 43156c89..0f120152 100644 --- a/Classes/x-saherelm.x-chart.helper.class.mq5 +++ b/Classes/x-saherelm.x-chart.helper.class.mq5 @@ -66,8 +66,8 @@ class XCChartHelper : public XCBase * @return ( bool ) */ bool Navigate( - const ENUM_CHART_POSITION position, - const int shift // + ENUM_CHART_POSITION position, + int shift // ) { return (ChartNavigate(mChartID, position, shift)); @@ -80,11 +80,110 @@ class XCChartHelper : public XCBase * * @return ( bool ) */ - bool ApplyTemplate(const string filename) const + bool ApplyTemplate(string filename) { return (ChartApplyTemplate(mChartID, filename)); } + /** + * Add Specified Indicator to Chart ... + * + * @param subWindow: int ... + * @param handle: int ... + * + * @return ( bool ) + */ + bool IndicatorAdd(int subWindow, int handle) + { + // + // Normalize Subwindow ... + if (subWindow <= 0) + { + subWindow = 0; + } + + // + return (ChartIndicatorAdd(mChartID, subWindow, handle)); + } + + /** + * Delete Specified Indicator from Chart ... + * + * @param subWindow: int ... + * @param name: string ... + * + * @return ( bool ) + */ + bool IndicatorDelete(int subWindow, string name) + { + // + // Normalize Subwindow ... + if (subWindow <= 0) + { + subWindow = 0; + } + + // + return (ChartIndicatorDelete(mChartID, subWindow, name)); + } + + /** + * Count all Charts Indicator ... + * + * @param subWindow: int ... + * + * @return ( int ) + */ + int IndicatorsTotal(int subWindow) + { + // + // Normalize Subwindow ... + if (subWindow <= 0) + { + subWindow = 0; + } + + // + return (ChartIndicatorsTotal(mChartID, subWindow)); + } + + /** + * Get Specified Indexed Indicator's Name ... + * + * @param subWindow: int ... + * @param index: int ... + * + * @return ( string ) + */ + string IndicatorName(int subWindow, int index) + { + // + // Normalize Subwindow ... + if (subWindow <= 0) + { + subWindow = 0; + } + + // + return (ChartIndicatorName(mChartID, subWindow, index)); + } + + /** + * Set Chart Symbol, Period ... + * + * @param symbol: string ... + * @param period: ENUM_TIMEFRAMES ... + * + * @return ( bool ) + */ + bool SetSymbolPeriod( + string symbol, + ENUM_TIMEFRAMES period // + ) + { + return (ChartSetSymbolPeriod(mChartID, symbol, period)); + } + /** * Take an Screenshot of Chart ... * @@ -113,88 +212,436 @@ class XCChartHelper : public XCBase // string work_str; int work_int; - //--- check + + // + bool has = false; + + // + // Validate ... if (file_handle == INVALID_HANDLE || mChartID == -1) - return (false); - //--- write start marker - 0xFFFFFFFFFFFFFFFF - if (FileWriteLong(file_handle, -1) != sizeof(long)) - return (false); - //--- write chart type - if (FileWriteInteger(file_handle, Type(), INT_VALUE) != INT_VALUE) - return (false); - //--- write chart symbol + { + return has; + } + + // + // Write start marker - 0xFFFFFFFFFFFFFFFF ... + has = FileWriteLong(file_handle, -1) == sizeof(long); + if (!has) + { + return has; + } + + // + // Write chart type ... + has = FileWriteInteger(file_handle, Type(), INT_VALUE) == INT_VALUE; + if (!has) + { + return has; + } + + // + // Write chart symbol ... work_str = Symbol(); work_int = StringLen(work_str); - if (FileWriteInteger(file_handle, work_int, INT_VALUE) != INT_VALUE) - return (false); + has = FileWriteInteger(file_handle, work_int, INT_VALUE) == INT_VALUE; + if (!has) + { + return has; + } if (work_int != 0) - if (FileWriteString(file_handle, work_str, work_int) != work_int) - return (false); - //--- write period of chart - if (FileWriteInteger(file_handle, Period(), INT_VALUE) != sizeof(int)) - return (false); - //--- write value of the "Mode" property - if (FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_MODE), INT_VALUE) != sizeof(int)) - return (false); - //--- write value of the "Foreground" property - if (FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_FOREGROUND), CHAR_VALUE) != sizeof(char)) - return (false); - //--- write value of the "Shift" property - if (FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHIFT), CHAR_VALUE) != sizeof(char)) - return (false); - //--- write value of the "ShiftSize" property - if (FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHIFT), INT_VALUE) != sizeof(int)) - return (false); - //--- write value of the "AutoScroll" property - if (FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_AUTOSCROLL), CHAR_VALUE) != sizeof(char)) - return (false); - //--- write value of the "Scale" property - if (FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SCALE), INT_VALUE) != sizeof(int)) - return (false); - //--- write value of the "ScaleFix" property - if (FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SCALEFIX), CHAR_VALUE) != sizeof(char)) - return (false); - //--- write value of the "ScaleFix_11" property - if (FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SCALEFIX_11), CHAR_VALUE) != sizeof(char)) - return (false); - //--- write value of the "FixedMax" property - if (FileWriteDouble(file_handle, ChartGetDouble(mChartID, CHART_FIXED_MAX)) != sizeof(double)) - return (false); - //--- write value of the "FixedMin" property - if (FileWriteDouble(file_handle, ChartGetDouble(mChartID, CHART_FIXED_MIN)) != sizeof(double)) - return (false); - //--- write the "ScalePPB" property - if (FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SCALE_PT_PER_BAR), CHAR_VALUE) != sizeof(char)) - return (false); - //--- write value of the "PointsPerBar" property - if (FileWriteDouble(file_handle, ChartGetDouble(mChartID, CHART_POINTS_PER_BAR)) != sizeof(double)) - return (false); - //--- write value of the "ShowOHLC" property - if (FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_OHLC), CHAR_VALUE) != sizeof(char)) - return (false); - //--- write value of the "ShowLineBid" property - if (FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_BID_LINE), CHAR_VALUE) != sizeof(char)) - return (false); - //--- write value of the "ShowLineAsk" property - if (FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_ASK_LINE), CHAR_VALUE) != sizeof(char)) - return (false); - //--- write value of the "ShowLastLine" property - if (FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_LAST_LINE), CHAR_VALUE) != sizeof(char)) - return (false); - //--- write value of the "ShowPeriodSep" property - if (FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_PERIOD_SEP), CHAR_VALUE) != sizeof(char)) - return (false); - //--- write value of the "ShowGrid" property - if (FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_GRID), CHAR_VALUE) != sizeof(char)) - return (false); - //--- write value of the "ShowVolumes" property - if (FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_VOLUMES), INT_VALUE) != sizeof(int)) - return (false); - //--- write value of the "ShowObjectDescr" property - if (FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_OBJECT_DESCR), CHAR_VALUE) != sizeof(char)) - return (false); - //--- successful - return (true); + { + // + has = FileWriteString(file_handle, work_str, work_int) == work_int; + if (!has) + { + return has; + } + } + + // + // Write Period of chart ... + has = FileWriteInteger(file_handle, Period(), INT_VALUE) == sizeof(int); + if (!has) + { + return has; + } + + // + // Write value of the "Mode" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_MODE), INT_VALUE) == sizeof(int); + if (!has) + { + return has; + } + + // + // Write value of the "Foreground" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_FOREGROUND), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "Shift" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHIFT), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "ShiftSize" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHIFT), INT_VALUE) == sizeof(int); + if (!has) + { + return has; + } + + // + // Write value of the "AutoScroll" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_AUTOSCROLL), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "Scale" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SCALE), INT_VALUE) == sizeof(int); + if (!has) + { + return has; + } + + // + // Write value of the "ScaleFix" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SCALEFIX), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "ScaleFix_11" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SCALEFIX_11), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "FixedMax" property ... + has = FileWriteDouble(file_handle, ChartGetDouble(mChartID, CHART_FIXED_MAX)) == sizeof(double); + if (!has) + { + return has; + } + + // + // Write value of the "FixedMin" property ... + has = FileWriteDouble(file_handle, ChartGetDouble(mChartID, CHART_FIXED_MIN)) == sizeof(double); + if (!has) + { + return has; + } + + // + // Write the "ScalePPB" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SCALE_PT_PER_BAR), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "PointsPerBar" property ... + has = FileWriteDouble(file_handle, ChartGetDouble(mChartID, CHART_POINTS_PER_BAR)) == sizeof(double); + if (!has) + { + return has; + } + + // + // Write value of the "ShowOHLC" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_OHLC), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "ShowLineBid" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_BID_LINE), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "ShowLineAsk" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_ASK_LINE), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "ShowLastLine" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_LAST_LINE), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "ShowPeriodSep" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_PERIOD_SEP), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "ShowGrid" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_GRID), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "ShowVolumes" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_VOLUMES), INT_VALUE) == sizeof(int); + if (!has) + { + return has; + } + + // + // Write value of the "ShowObjectDescr" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_OBJECT_DESCR), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + return has; + } + + /** + * Load Specified Chart File ... + * + * @param file_handle: int ... + * + * @return ( bool ) + */ + bool Load(const int file_handle) + { + // + string work_str; + int work_int; + + // + bool has = false; + + // + // Validate ... + if (file_handle == INVALID_HANDLE || mChartID == -1) + { + return has; + } + + // + // Read and checking start marker - 0xFFFFFFFFFFFFFFFF ... + if (FileReadLong(file_handle) != -1) + return has; + + // + // Read and checking chart type ... + if (FileReadInteger(file_handle, INT_VALUE) != Type()) + return has; + + // + // Read chart symbol ... + work_int = FileReadInteger(file_handle); + if (work_int != 0) + { + work_str = FileReadString(file_handle, work_int); + } + else + { + work_str = ""; + } + + // + // Read chart period ... + work_int = FileReadInteger(file_handle); + SetSymbolPeriod(work_str, (ENUM_TIMEFRAMES)work_int); + + // + // Read value of the "Mode" property ... + has = ChartSetInteger(mChartID, CHART_MODE, FileReadInteger(file_handle, INT_VALUE)); + if (!has) + { + return has; + } + + // + // Read value of the "Foreground" property ... + has = ChartSetInteger(mChartID, CHART_FOREGROUND, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Read value of the "Shift" property ... + has = ChartSetInteger(mChartID, CHART_SHIFT, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Read value of the "ShiftSize" property ... + has = ChartSetInteger(mChartID, CHART_SHIFT, FileReadInteger(file_handle, INT_VALUE)); + if (!has) + { + return has; + } + + // + // Read value of the "AutoScroll" property ... + has = ChartSetInteger(mChartID, CHART_AUTOSCROLL, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Read value of the "Scale" property ... + has = ChartSetInteger(mChartID, CHART_SCALE, FileReadInteger(file_handle, INT_VALUE)); + if (!has) + { + return has; + } + + // + // Read value of the "ScaleFix" property ... + has = ChartSetInteger(mChartID, CHART_SCALEFIX, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Read value of the "ScaleFix_11" property ... + has = ChartSetInteger(mChartID, CHART_SCALEFIX_11, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Rread value of the "FixedMax" property ... + has = ChartSetDouble(mChartID, CHART_FIXED_MAX, FileReadDatetime(file_handle)); + if (!has) + { + return has; + } + + // + // Rread value of the "FixedMin" property ... + has = ChartSetDouble(mChartID, CHART_FIXED_MIN, FileReadDatetime(file_handle)); + if (!has) + { + return has; + } + + // + // Rread value of the "ScalePPB" property ... + has = ChartSetInteger(mChartID, CHART_SCALE_PT_PER_BAR, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Rread value of the "PointsPerBar" property ... + has = ChartSetDouble(mChartID, CHART_POINTS_PER_BAR, FileReadDatetime(file_handle)); + if (!has) + { + return has; + } + + // + // Rread value of the "ShowOHLC" property ... + has = ChartSetInteger(mChartID, CHART_SHOW_OHLC, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Rread value of the "ShowLineBid" property ... + has = ChartSetInteger(mChartID, CHART_SHOW_BID_LINE, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Rread value of the "ShowLineAsk" property ... + has = ChartSetInteger(mChartID, CHART_SHOW_ASK_LINE, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Rread value of the "ShowLastLine" property ... + has = ChartSetInteger(mChartID, CHART_SHOW_LAST_LINE, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Rread value of the "ShowPeriodSep" property ... + has = ChartSetInteger(mChartID, CHART_SHOW_PERIOD_SEP, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Rread value of the "ShowGrid" property ... + has = ChartSetInteger(mChartID, CHART_SHOW_GRID, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Rread value of the "ShowVolumes" property ... + has = ChartSetInteger(mChartID, CHART_SHOW_VOLUMES, FileReadInteger(file_handle, INT_VALUE)); + if (!has) + { + return has; + } + + // + // Rread value of the "ShowObjectDescr" property ... + has = ChartSetInteger(mChartID, CHART_SHOW_OBJECT_DESCR, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + return has; } // diff --git a/Documents/BKP/backtester.temp.mq5 b/Documents/BKP/backtester.temp.mq5 new file mode 100644 index 00000000..e01c1c0e --- /dev/null +++ b/Documents/BKP/backtester.temp.mq5 @@ -0,0 +1,1484 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center XTest MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XBackTester +// Description: a Backtest Tools Strategy Tester +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +//////////////////////////////////////////////////////x +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XBackTester" +#property strict + +// +#define ShortName "XBackTester" + +// +// Imports ... +#include "../Classes/x-saherelm.x-alert.class.mq5" +#include "../Classes/x-saherelm.x-chart.helper.class.mq5" +#include "../Classes/x-saherelm.x-trade.class.mq5" + +// +// Import Chart Objects ... +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Definitions ... + +// +// Inputs ... + +// +// Common ... +input group "Common"; +input long eaMagicNumber = 78692110; // Magic Number +input int eaSlippage = 10; // Slippgae +input string eaLogSuffix = ""; // Log Suffix + +// +// Alert ... +// Here we Provider All Requirements for +// Configuring Alert Provider ... +input group "Alert"; +input bool eAEnableAlerts = true; // Enable Alerts +input bool eALogAlerts = true; // Log Alerts +input bool eAMailAlerts = false; // Mail Alerts +input bool eAPushAlerts = false; // Push Alerts +input bool eATerminalAlerts = false; // Terminal Alerts +// +// Define Local Variables ... + +// +string eaLogTag; // EA Log Prefix ... +XCAlert *eaAlert; // Alert Provider for Expert Adviser ... +XCTrade *eaTrader; // Trader of Expert Adviser ... +XCChartHelper *mChartHelper; // Chart Helper Class ... + +// +// Object Props ... + +// +string objSuffix; + +// +CButton btnBuy; +CButton btnSell; +CButton btnClose; +CButton btnCloseAll; + +// +CEdit lblPositionId; + +// +CButton *btnSelectedPosInfo; +CArrayObj selectedPosInfoArr; + +// +int btnCloseSizeX = 0; +int btnCloseSizeY = 0; +int btnCloseStartX = 0; +int btnCloseStartY = 0; +int lblPositionIdSizeX = 0; +int lblPositionIdSizeY = 0; +int lblPositionIdStartX = 0; +int lblPositionIdStartY = 0; + +// +ulong selectedPositionID = 0; + +// +// Position Arrays ... +CArrayObj posArray; + +// +// Event Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs and Required Parameters + // for EA to Works fine ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Timer ... + if (!InitTimer()) + { + return INIT_FAILED; + } + + // + // Initialize all Requirements ... + if (!InitEA()) + { + return INIT_FAILED; + } + + // + // Initialize all GUI Objects and Classes ... + if (!InitGUI()) + { + return INIT_FAILED; + } + + // + // Alert Initialization ... + string msg = "Initialized Successfully ..."; + eaAlert.SendAlert(msg); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +void OnDeinit(const int 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 + + // + // Destroy Timer ... + DestroyTimer(); + + // + // Destroy all GUI Requirements ... + DestroyGUI(); + + // + // Alert De Initialization Succeeded ... + string msg = "De Initialized Successfully ..."; + eaAlert.SendAlert(msg); + + // + // Destroy all EA Requirements ... + DestroyEA(); +} + +// +// On Tick Handler ... +void OnTick() +{ + // + UpdateGUI(); +} + +// +// Handle On Trade Event ... +void OnTrade() +{ + // + eaTrader.HandleOnTrade(); +} + +// +// On Timer ... +void OnTimer() +{ + // + // TODO: Implement Time Based Functionalities ... +} + +// +// Chart Event Handler ... +void OnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // +) +{ +} + +// +// 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(); +} + +/** + * Initialize all Requirements for Working Fine ... + * + * @return ( bool ) + */ +bool InitEA() +{ + // + bool result = false; + + // + // Locally Apply Changes on Prefix ... + eaLogTag = ShortName + ">" + eaLogSuffix; + + // + // Create Instance of Alert Class and Configure it ... + eaAlert = new XCAlert(); + eaAlert.SetPrefix(eaLogTag); + eaAlert.SetLogAlerts(eALogAlerts); + eaAlert.SetMailAlerts(eAMailAlerts); + eaAlert.SetPushAlerts(eAPushAlerts); + eaAlert.SetEnableAlerts(eAEnableAlerts); + eaAlert.SetTerminalAlerts(eATerminalAlerts); + + // + // Create Trader Instance and Configure it ... + eaTrader = new XCTrade( + eaSlippage, + eaMagicNumber // + ); + + // + // Attach Event Handlers ... + eaTrader.AddOnDealsChangedEventHandler(OnDealsChanged); + eaTrader.AddOnStopLossEventHandler(OnStopLossTriggered); + eaTrader.AddOnOrdersChangedEventHandler(OnOrdersChanged); + eaTrader.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); + eaTrader.AddOnModifyPositionEventHandler(OnPositionModified); + eaTrader.AddOnPositionsChangedEventHandler(OnPositionsChanged); + eaTrader.AddOnTradeStateChangedEventHandler(OnTradeStateChanged); + eaTrader.AddOnForceClosePositionEventHandler(OnPositionForceClosed); + eaTrader.AddOnPartialClosePositionEventHandler(OnPositionPartialClosed); + + // + // TODO: Fix This ... + result = true; + + // + return result; +} + +/** + * Destroy all Initialized EA Requirements ... + */ +void DestroyEA() +{ + // + delete eaAlert; +} + +// +// GUI Events ... + +/** + * Initialize all GUI Requirements for EA ... + * + * @return ( bool ) + */ +bool InitGUI() +{ + // + bool result = false; + + // + int subWindow = 0; + ulong chartId = ChartID(); + objSuffix = ShortName + "_"; + + // + // Initial Chart Class Instance ... + mChartHelper = new XCChartHelper(chartId); + + // + int startX = 5; + int startY = 25; + + // + int defaultGap = 5; + int defaultWidth = 100; + int defaultHeight = 30; + + // + // Buy ... + int btnBuyStartX = startX; + int btnBuySizeX = startX + defaultWidth; + int btnBuyStartY = startY; + int btnBuySizeY = startY + defaultHeight; + string btnBuyName = objSuffix + "BTN_BUY"; + result = btnBuy.Create( + chartId, + btnBuyName, + subWindow, + btnBuyStartX, + btnBuyStartY, + btnBuySizeX, + btnBuySizeY // + ); + if (result) + { + // + // Apply Buy Button Style ... + + // + btnBuy.Text("Buy"); + btnBuy.Color(clrYellow); + btnBuy.ColorBackground(clrGreen); + } + + // + // Sell ... + int btnSellStartX = btnBuyStartX + btnBuySizeX; + int btnSellSizeX = btnSellStartX + defaultWidth; + int btnSellStartY = btnBuyStartY; + int btnSellSizeY = btnBuySizeY; + string btnSellName = objSuffix + "BTN_SELL"; + result = btnSell.Create( + chartId, + btnSellName, + subWindow, + btnSellStartX, + btnSellStartY, + btnSellSizeX, + btnSellSizeY // + ); + if (result) + { + // + // Apply Sell Button Style ... + + // + btnSell.Text("Sell"); + btnSell.Color(clrYellow); + btnSell.ColorBackground(clrDarkRed); + } + + // + // LABEL Position ID ... + lblPositionIdStartX = btnBuyStartX; + lblPositionIdSizeX = lblPositionIdStartX + defaultWidth; + lblPositionIdStartY = btnSellSizeY + defaultGap; + lblPositionIdSizeY = lblPositionIdStartY + defaultHeight; + string lblPositionIdName = objSuffix + "LBL_POS_ID"; + result = lblPositionId.Create( + chartId, + lblPositionIdName, + subWindow, + lblPositionIdStartX, + lblPositionIdStartY, + lblPositionIdSizeX, + lblPositionIdSizeY // + ); + if (result) + { + // + // Apply Label Position ID Style ... + lblPositionId.ReadOnly(true); + lblPositionId.Text("Pos ID: "); + lblPositionId.Color(clrYellow); + lblPositionId.ColorBackground(clrDarkGray); + } + + // + // Close ... + btnCloseStartX = startX; + btnCloseSizeX = btnCloseStartX + defaultWidth; + btnCloseStartY = lblPositionIdSizeY + defaultGap; + btnCloseSizeY = lblPositionIdSizeY + defaultHeight; + string btnCloseName = objSuffix + "BTN_CLOSE"; + result = btnClose.Create( + chartId, + btnCloseName, + subWindow, + btnCloseStartX, + btnCloseStartY, + btnCloseSizeX, + btnCloseSizeY // + ); + if (result) + { + // + // Apply Close Button Style ... + + // + btnClose.Text("Close"); + btnClose.Color(clrYellow); + btnClose.ColorBackground(clrDarkOrange); + } + + // + // Close All ... + int btnCloseAllStartX = btnCloseSizeX + defaultGap; + int btnCloseAllSizeX = btnCloseAllStartX + defaultWidth; + int btnCloseAllStartY = lblPositionIdSizeY + defaultGap; + int btnCloseAllSizeY = lblPositionIdSizeY + defaultHeight; + string btnCloseAllName = objSuffix + "BTN_CLOSE_ALL"; + result = btnCloseAll.Create( + chartId, + btnCloseAllName, + subWindow, + btnCloseAllStartX, + btnCloseAllStartY, + btnCloseAllSizeX, + btnCloseAllSizeY // + ); + if (result) + { + // + // Apply Close Button Style ... + + // + btnCloseAll.Text("Close All"); + btnCloseAll.Color(clrYellow); + btnCloseAll.ColorBackground(clrDarkRed); + } + + // + UpdateGUIState(); + + // + return result; +} + +/** + * Update GUI based on Each Ticks ... + */ +void UpdateGUI() +{ + // + UpdateGUIState(); + + // + // 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 = false; + 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 = iLbl.IsVisible(); + string btnText = isVisible + ? "Hide Info" + : "Show Info"; + btnSelectedPosInfo.Text(btnText); + } + + // + ZeroMemory(iLbl); + } + + // + btnSelectedPosInfo.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; + UpdateGUIState(); + } + } + + // + iBtn.Pressed(false); + } + + // + ZeroMemory(iBtn); + } + } +} + +/** + * Destroy all Initialized GUi Requirements ... + */ +void DestroyGUI() +{ + // + delete mChartHelper; + ZeroMemory(mChartHelper); + + // + delete btnSelectedPosInfo; + ZeroMemory(btnSelectedPosInfo); +} + +// +// Trade Event Handlers ... + +/** + * Handle StopLoss Triggered Positions ... + * + * @param deal: XDeal instance ... + */ +void OnStopLossTriggered(const XDeal &deal) +{ + // + UpdatePositionButtons(); +} + +/** + * Handle Take Profit Triggered Positions ... + * + * @param deal: XDeal instance ... + */ +void OnTakeProfitTriggered(const XDeal &deal) +{ + // + UpdatePositionButtons(); +} + +/** + * 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 // +) +{ + // + UpdatePositionButtons(); +} + +/** + * Handle Deals Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnDealsChanged(int count) +{ +} + +/** + * Handle Orders Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnOrdersChanged(int count) +{ +} + +/** + * Handle Positions Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnPositionsChanged(int count) +{ + // + // Update Position Buttons ... + UpdatePositionButtons(); +} + +/** + * 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 // +) +{ +} + +/** + * 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 // +) +{ +} + +/** + * Handle Trade State Changed ... + * + * @param state: XOnTradeHandlerState instance ... + */ +void OnTradeStateChanged(const XOnTradeHandlerState &state) +{ +} + +// +// GUI Event Handlers and Helpers ... + +// +void HandleBuyTrade() +{ + HandleTrade(X_DIRECTION_BULLISH); +} + +// +void HandleSellTrade() +{ + HandleTrade(X_DIRECTION_BEARISH); +} + +// +void HandleTrade(ENUM_X_DIRECTION dir) +{ + // + if (!HasDirection(dir)) + { + return; + } + + // + string symbol = mChartHelper.Symbol(); + ENUM_TIMEFRAMES period = mChartHelper.Period(); + + // + bool isBullish = IsSpecifiedBullish(dir); + + // + double r2r = 1.5; + double volume = 0.01; + double riskInPoints = 100; + double point = GetPoints(symbol); + double entry = GetEntry(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 = ShortName + "_POS_" + ToXString(dir); + + // + if (isBullish) + { + // + eaTrader.Buy( + symbol, + period, + volume, + entry, + sl, + tp, + comment // + ); + } + else + { + // + eaTrader.Sell( + symbol, + 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); + } + } +} + +// +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; +} + +// +void UpdatePositionButtons() +{ + // + // Retrieve Positions ... + XPosition positions[]; + int count = eaTrader.GetPositions( + positions // + ); + bool has = IsValidSize(count); + if (!has) + { + // + posArray.Clear(); + selectedPositionID = 0; + UpdateGUIState(); + 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 = mChartHelper.ChartId(); + + // + int btnWidth = 25; + + // + int lastX = lblPositionIdSizeX + 5; + int lastSizeX = lastX + btnWidth; + + // + int lastY = lblPositionIdStartY; + int lastSizeY = lblPositionIdSizeY; + + // + 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); + UpdateGUIState(); +} + +// +void UpdateGUIState() +{ + // + // 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 = mChartHelper.Width(); + ulong chartId = mChartHelper.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"; + + // + int btnStartX = btnCloseStartX; + int btnSizeX = btnStartX + 200 + 5; + + // + int btnStartY = btnCloseSizeY + 5; + int btnSizeY = btnStartY + 50; + + // + bool isCreated = btnSelectedPosInfo.Create( + chartId, + name, + subWindow, + btnStartX, + btnStartY, + btnSizeX, + btnSizeY // + ); + 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); + + // + 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 = iLbl.IsVisible(); + 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); + } + else + { + // + btnClose.Enable(); + btnClose.ColorBackground(clrDarkOrange); + } +} + +// \ No newline at end of file diff --git a/Experts/x-saherelm.backtester.mq5 b/Experts/x-saherelm.backtester.mq5 index e01c1c0e..c8f2d242 100644 --- a/Experts/x-saherelm.backtester.mq5 +++ b/Experts/x-saherelm.backtester.mq5 @@ -23,23 +23,7 @@ // // Imports ... -#include "../Classes/x-saherelm.x-alert.class.mq5" -#include "../Classes/x-saherelm.x-chart.helper.class.mq5" -#include "../Classes/x-saherelm.x-trade.class.mq5" - -// -// Import Chart Objects ... -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "../Classes/x-saherelm.x-backtester.expert.class.mq5" // // Definitions ... @@ -59,55 +43,18 @@ input string eaLogSuffix = ""; // Log Suffix // Here we Provider All Requirements for // Configuring Alert Provider ... input group "Alert"; -input bool eAEnableAlerts = true; // Enable Alerts -input bool eALogAlerts = true; // Log Alerts -input bool eAMailAlerts = false; // Mail Alerts -input bool eAPushAlerts = false; // Push Alerts -input bool eATerminalAlerts = false; // Terminal Alerts +input bool eaEnableAlerts = true; // Enable Alerts +input bool eaLogAlerts = true; // Log Alerts +input bool eaMailAlerts = false; // Mail Alerts +input bool eaPushAlerts = false; // Push Alerts +input bool eaTerminalAlerts = false; // Terminal Alerts + // // Define Local Variables ... // -string eaLogTag; // EA Log Prefix ... -XCAlert *eaAlert; // Alert Provider for Expert Adviser ... -XCTrade *eaTrader; // Trader of Expert Adviser ... -XCChartHelper *mChartHelper; // Chart Helper Class ... - -// -// Object Props ... - -// -string objSuffix; - -// -CButton btnBuy; -CButton btnSell; -CButton btnClose; -CButton btnCloseAll; - -// -CEdit lblPositionId; - -// -CButton *btnSelectedPosInfo; -CArrayObj selectedPosInfoArr; - -// -int btnCloseSizeX = 0; -int btnCloseSizeY = 0; -int btnCloseStartX = 0; -int btnCloseStartY = 0; -int lblPositionIdSizeX = 0; -int lblPositionIdSizeY = 0; -int lblPositionIdStartX = 0; -int lblPositionIdStartY = 0; - -// -ulong selectedPositionID = 0; - -// -// Position Arrays ... -CArrayObj posArray; +string eaLogTag; // EA Log Prefix ... +XCBackTesterEA *eaExpert; // EA Expert ... // // Event Handlers ... @@ -116,6 +63,14 @@ CArrayObj posArray; // Initialization ... int OnInit() { + // + // Preparing Tags ... + string eaTag = + (IsValid(eaLogSuffix) + ? eaLogSuffix + "_" + : "") + + ShortName; + // // Validate Inputs and Required Parameters // for EA to Works fine ... @@ -132,26 +87,52 @@ int OnInit() } // - // Initialize all Requirements ... - if (!InitEA()) + // Configure EA Expert Class ... + eaExpert = new XCBackTesterEA(); + + // + // Symbol / Period ... + eaExpert.symbol = _Symbol; + eaExpert.period = _Period; + + // + // Common ... + eaExpert.eaMagicNumber = eaMagicNumber; + eaExpert.eaSlippage = eaSlippage; + eaExpert.eaLogSuffix = eaTag; + + // + // Alert ... + eaExpert.eaEnableAlerts = eaEnableAlerts; + eaExpert.eaLogAlerts = eaLogAlerts; + eaExpert.eaMailAlerts = eaMailAlerts; + eaExpert.eaPushAlerts = eaPushAlerts; + eaExpert.eaTerminalAlerts = eaTerminalAlerts; + + // + // Attach Event Handlers ... + eaExpert.AddOnDealsChangedEventHandler(OnDealsChanged); + eaExpert.AddOnStopLossEventHandler(OnStopLossTriggered); + eaExpert.AddOnOrdersChangedEventHandler(OnOrdersChanged); + eaExpert.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); + 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; } // - // Initialize all GUI Objects and Classes ... - if (!InitGUI()) - { - return INIT_FAILED; - } - - // - // Alert Initialization ... - string msg = "Initialized Successfully ..."; - eaAlert.SendAlert(msg); - - // - // Init Succeed ... + Print(ShortName, ": Initialized Successfully ..."); return INIT_SUCCEEDED; } @@ -173,44 +154,32 @@ void OnDeinit(const int reason) // // Destroy Timer ... - DestroyTimer(); + eaExpert.HandleOnDeInit(); // - // Destroy all GUI Requirements ... - DestroyGUI(); - - // - // Alert De Initialization Succeeded ... - string msg = "De Initialized Successfully ..."; - eaAlert.SendAlert(msg); - - // - // Destroy all EA Requirements ... - DestroyEA(); + delete eaExpert; + ZeroMemory(eaExpert); } // // On Tick Handler ... void OnTick() { - // - UpdateGUI(); + eaExpert.HandleOnTick(); } // // Handle On Trade Event ... void OnTrade() { - // - eaTrader.HandleOnTrade(); + eaExpert.HandleOnTrade(); } // // On Timer ... void OnTimer() { - // - // TODO: Implement Time Based Functionalities ... + eaExpert.HandleOnTimer(); } // @@ -222,6 +191,7 @@ void OnChartEvent( const string &sparam // ) { + eaExpert.HandleOnChartEvent(id, lparam, dparam, sparam); } // @@ -306,400 +276,6 @@ void DestroyTimer() // EventKillTimer(); } -/** - * Initialize all Requirements for Working Fine ... - * - * @return ( bool ) - */ -bool InitEA() -{ - // - bool result = false; - - // - // Locally Apply Changes on Prefix ... - eaLogTag = ShortName + ">" + eaLogSuffix; - - // - // Create Instance of Alert Class and Configure it ... - eaAlert = new XCAlert(); - eaAlert.SetPrefix(eaLogTag); - eaAlert.SetLogAlerts(eALogAlerts); - eaAlert.SetMailAlerts(eAMailAlerts); - eaAlert.SetPushAlerts(eAPushAlerts); - eaAlert.SetEnableAlerts(eAEnableAlerts); - eaAlert.SetTerminalAlerts(eATerminalAlerts); - - // - // Create Trader Instance and Configure it ... - eaTrader = new XCTrade( - eaSlippage, - eaMagicNumber // - ); - - // - // Attach Event Handlers ... - eaTrader.AddOnDealsChangedEventHandler(OnDealsChanged); - eaTrader.AddOnStopLossEventHandler(OnStopLossTriggered); - eaTrader.AddOnOrdersChangedEventHandler(OnOrdersChanged); - eaTrader.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); - eaTrader.AddOnModifyPositionEventHandler(OnPositionModified); - eaTrader.AddOnPositionsChangedEventHandler(OnPositionsChanged); - eaTrader.AddOnTradeStateChangedEventHandler(OnTradeStateChanged); - eaTrader.AddOnForceClosePositionEventHandler(OnPositionForceClosed); - eaTrader.AddOnPartialClosePositionEventHandler(OnPositionPartialClosed); - - // - // TODO: Fix This ... - result = true; - - // - return result; -} - -/** - * Destroy all Initialized EA Requirements ... - */ -void DestroyEA() -{ - // - delete eaAlert; -} - -// -// GUI Events ... - -/** - * Initialize all GUI Requirements for EA ... - * - * @return ( bool ) - */ -bool InitGUI() -{ - // - bool result = false; - - // - int subWindow = 0; - ulong chartId = ChartID(); - objSuffix = ShortName + "_"; - - // - // Initial Chart Class Instance ... - mChartHelper = new XCChartHelper(chartId); - - // - int startX = 5; - int startY = 25; - - // - int defaultGap = 5; - int defaultWidth = 100; - int defaultHeight = 30; - - // - // Buy ... - int btnBuyStartX = startX; - int btnBuySizeX = startX + defaultWidth; - int btnBuyStartY = startY; - int btnBuySizeY = startY + defaultHeight; - string btnBuyName = objSuffix + "BTN_BUY"; - result = btnBuy.Create( - chartId, - btnBuyName, - subWindow, - btnBuyStartX, - btnBuyStartY, - btnBuySizeX, - btnBuySizeY // - ); - if (result) - { - // - // Apply Buy Button Style ... - - // - btnBuy.Text("Buy"); - btnBuy.Color(clrYellow); - btnBuy.ColorBackground(clrGreen); - } - - // - // Sell ... - int btnSellStartX = btnBuyStartX + btnBuySizeX; - int btnSellSizeX = btnSellStartX + defaultWidth; - int btnSellStartY = btnBuyStartY; - int btnSellSizeY = btnBuySizeY; - string btnSellName = objSuffix + "BTN_SELL"; - result = btnSell.Create( - chartId, - btnSellName, - subWindow, - btnSellStartX, - btnSellStartY, - btnSellSizeX, - btnSellSizeY // - ); - if (result) - { - // - // Apply Sell Button Style ... - - // - btnSell.Text("Sell"); - btnSell.Color(clrYellow); - btnSell.ColorBackground(clrDarkRed); - } - - // - // LABEL Position ID ... - lblPositionIdStartX = btnBuyStartX; - lblPositionIdSizeX = lblPositionIdStartX + defaultWidth; - lblPositionIdStartY = btnSellSizeY + defaultGap; - lblPositionIdSizeY = lblPositionIdStartY + defaultHeight; - string lblPositionIdName = objSuffix + "LBL_POS_ID"; - result = lblPositionId.Create( - chartId, - lblPositionIdName, - subWindow, - lblPositionIdStartX, - lblPositionIdStartY, - lblPositionIdSizeX, - lblPositionIdSizeY // - ); - if (result) - { - // - // Apply Label Position ID Style ... - lblPositionId.ReadOnly(true); - lblPositionId.Text("Pos ID: "); - lblPositionId.Color(clrYellow); - lblPositionId.ColorBackground(clrDarkGray); - } - - // - // Close ... - btnCloseStartX = startX; - btnCloseSizeX = btnCloseStartX + defaultWidth; - btnCloseStartY = lblPositionIdSizeY + defaultGap; - btnCloseSizeY = lblPositionIdSizeY + defaultHeight; - string btnCloseName = objSuffix + "BTN_CLOSE"; - result = btnClose.Create( - chartId, - btnCloseName, - subWindow, - btnCloseStartX, - btnCloseStartY, - btnCloseSizeX, - btnCloseSizeY // - ); - if (result) - { - // - // Apply Close Button Style ... - - // - btnClose.Text("Close"); - btnClose.Color(clrYellow); - btnClose.ColorBackground(clrDarkOrange); - } - - // - // Close All ... - int btnCloseAllStartX = btnCloseSizeX + defaultGap; - int btnCloseAllSizeX = btnCloseAllStartX + defaultWidth; - int btnCloseAllStartY = lblPositionIdSizeY + defaultGap; - int btnCloseAllSizeY = lblPositionIdSizeY + defaultHeight; - string btnCloseAllName = objSuffix + "BTN_CLOSE_ALL"; - result = btnCloseAll.Create( - chartId, - btnCloseAllName, - subWindow, - btnCloseAllStartX, - btnCloseAllStartY, - btnCloseAllSizeX, - btnCloseAllSizeY // - ); - if (result) - { - // - // Apply Close Button Style ... - - // - btnCloseAll.Text("Close All"); - btnCloseAll.Color(clrYellow); - btnCloseAll.ColorBackground(clrDarkRed); - } - - // - UpdateGUIState(); - - // - return result; -} - -/** - * Update GUI based on Each Ticks ... - */ -void UpdateGUI() -{ - // - UpdateGUIState(); - - // - // 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 = false; - 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 = iLbl.IsVisible(); - string btnText = isVisible - ? "Hide Info" - : "Show Info"; - btnSelectedPosInfo.Text(btnText); - } - - // - ZeroMemory(iLbl); - } - - // - btnSelectedPosInfo.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; - UpdateGUIState(); - } - } - - // - iBtn.Pressed(false); - } - - // - ZeroMemory(iBtn); - } - } -} - -/** - * Destroy all Initialized GUi Requirements ... - */ -void DestroyGUI() -{ - // - delete mChartHelper; - ZeroMemory(mChartHelper); - - // - delete btnSelectedPosInfo; - ZeroMemory(btnSelectedPosInfo); -} - // // Trade Event Handlers ... @@ -710,8 +286,7 @@ void DestroyGUI() */ void OnStopLossTriggered(const XDeal &deal) { - // - UpdatePositionButtons(); + eaExpert.HandleOnStopLossTriggered(deal); } /** @@ -721,8 +296,7 @@ void OnStopLossTriggered(const XDeal &deal) */ void OnTakeProfitTriggered(const XDeal &deal) { - // - UpdatePositionButtons(); + eaExpert.HandleOnTakeProfitTriggered(deal); } /** @@ -739,7 +313,11 @@ void OnPositionForceClosed( ) { // - UpdatePositionButtons(); + eaExpert.HandleOnPositionForceClosed( + ticket, + position, + comment // + ); } /** @@ -749,6 +327,7 @@ void OnPositionForceClosed( */ void OnDealsChanged(int count) { + eaExpert.HandleOnDealsChanged(count); } /** @@ -758,6 +337,7 @@ void OnDealsChanged(int count) */ void OnOrdersChanged(int count) { + eaExpert.HandleOnOrdersChanged(count); } /** @@ -767,9 +347,7 @@ void OnOrdersChanged(int count) */ void OnPositionsChanged(int count) { - // - // Update Position Buttons ... - UpdatePositionButtons(); + eaExpert.HandleOnPositionsChanged(count); } /** @@ -785,6 +363,12 @@ void OnPositionModified( const string comment // ) { + // + eaExpert.HandleOnPositionModified( + ticket, + profit, + comment // + ); } /** @@ -800,6 +384,12 @@ void OnPositionPartialClosed( const string comment // ) { + // + eaExpert.HandleOnPositionPartialClosed( + ticket, + profit, + comment // + ); } /** @@ -809,676 +399,7 @@ void OnPositionPartialClosed( */ void OnTradeStateChanged(const XOnTradeHandlerState &state) { -} - -// -// GUI Event Handlers and Helpers ... - -// -void HandleBuyTrade() -{ - HandleTrade(X_DIRECTION_BULLISH); -} - -// -void HandleSellTrade() -{ - HandleTrade(X_DIRECTION_BEARISH); -} - -// -void HandleTrade(ENUM_X_DIRECTION dir) -{ - // - if (!HasDirection(dir)) - { - return; - } - - // - string symbol = mChartHelper.Symbol(); - ENUM_TIMEFRAMES period = mChartHelper.Period(); - - // - bool isBullish = IsSpecifiedBullish(dir); - - // - double r2r = 1.5; - double volume = 0.01; - double riskInPoints = 100; - double point = GetPoints(symbol); - double entry = GetEntry(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 = ShortName + "_POS_" + ToXString(dir); - - // - if (isBullish) - { - // - eaTrader.Buy( - symbol, - period, - volume, - entry, - sl, - tp, - comment // - ); - } - else - { - // - eaTrader.Sell( - symbol, - 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); - } - } -} - -// -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; -} - -// -void UpdatePositionButtons() -{ - // - // Retrieve Positions ... - XPosition positions[]; - int count = eaTrader.GetPositions( - positions // - ); - bool has = IsValidSize(count); - if (!has) - { - // - posArray.Clear(); - selectedPositionID = 0; - UpdateGUIState(); - 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 = mChartHelper.ChartId(); - - // - int btnWidth = 25; - - // - int lastX = lblPositionIdSizeX + 5; - int lastSizeX = lastX + btnWidth; - - // - int lastY = lblPositionIdStartY; - int lastSizeY = lblPositionIdSizeY; - - // - 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); - UpdateGUIState(); -} - -// -void UpdateGUIState() -{ - // - // 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 = mChartHelper.Width(); - ulong chartId = mChartHelper.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"; - - // - int btnStartX = btnCloseStartX; - int btnSizeX = btnStartX + 200 + 5; - - // - int btnStartY = btnCloseSizeY + 5; - int btnSizeY = btnStartY + 50; - - // - bool isCreated = btnSelectedPosInfo.Create( - chartId, - name, - subWindow, - btnStartX, - btnStartY, - btnSizeX, - btnSizeY // - ); - 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); - - // - 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 = iLbl.IsVisible(); - 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); - } - else - { - // - btnClose.Enable(); - btnClose.ColorBackground(clrDarkOrange); - } + eaExpert.HandleOnTradeStateChanged(state); } // \ No newline at end of file diff --git a/Experts/x-saherelm.xom1.ea.mq5 b/Experts/x-saherelm.xom1.ea.mq5 index 2dd7ba32..473dbabb 100644 --- a/Experts/x-saherelm.xom1.ea.mq5 +++ b/Experts/x-saherelm.xom1.ea.mq5 @@ -153,6 +153,12 @@ int OnInit() // // Setting All Inputs to Expert Adviser Class ... + // + // Common ... + eaExpert.eaMagicNumber = eaMagicNumber; + eaExpert.eaSlippage = eaSlippage; + eaExpert.eaLogSuffix = eaTag; + // // Symbols ... eaExpert.eaSymbolConfiguration = eaSymbolConfiguration;