From cc51c0e90686c71be8a17831406c4774120e5192 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Sun, 16 Aug 2026 15:46:50 +0330 Subject: [PATCH] last works: - Complete XReply Bar; - Add Region Folding Configs in Workspace Settings; --- Indicators/x-saherelm.x121.x-reply.mq5 | 1388 ++++++++++++++++++++++++ MQL5.code-workspace | 11 +- 2 files changed, 1398 insertions(+), 1 deletion(-) create mode 100644 Indicators/x-saherelm.x121.x-reply.mq5 diff --git a/Indicators/x-saherelm.x121.x-reply.mq5 b/Indicators/x-saherelm.x121.x-reply.mq5 new file mode 100644 index 00000000..40d2a75f --- /dev/null +++ b/Indicators/x-saherelm.x121.x-reply.mq5 @@ -0,0 +1,1388 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// --------------------------------------------------- +// Name: X121 XReplay +// Description: SaherElm Replay Tool ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "2.00" +#property description "SaherElm X121 XReplay Indicator" +#property icon "../Images/SaherElm_Logo_Color.ico" +#property strict + +// #region Imports ... +#include "../Libraries/x-saherelm.common.lib.mq5" +// #endregion + +// #region Definitions ... +// +#define ShortName "X121 XReplay" + +// +#define hideColorIDX 0 +#define bullishColorIDX 1 +#define bearishColorIDX 2 +#define neuturalColorIDX 3 + +// +#define bullishState 1 +#define neuturalState 0 +#define bearishState -1 + +// +#define emptyValue 0.0 + +// +// an strucutre to save Chart Style ... +struct XChartStyle +{ + long chartId; // chart's ID ... + ENUM_CHART_MODE mode; // chart's mode ... + bool showBidLine; // show bid line ... + bool showAskLine; // show ask line ... + bool showGrid; // show grids on chart ... + bool showVolumes; // show volumes ... + bool showTradeLevels; // Displaying trade levels in the chart (levels of open positions, Stop Loss, Take Profit and pending orders) ... + bool autoScroll; // chart autoscroll ... + bool quickNavigation; // chart quick navigation state ... + color foreGroundColor; // chart's foreground color ... + color backGroundColor; // chart's background color ... + color upColor; // Up Color ... + color downColor; // Down Color ... + color bullishColor; // Bullish color ... + color bearishColor; // Bearish color ... + color gridColor; // grid color ... + color bidLineColor; // bid line color ... + color askLineColor; // ask line color ... + color lineColor; // line mode and doji candlestick color ... + color stopColor; // Color of stop order levels (Stop Loss and Take Profit) ... + color volumesColor; // volumes color ... +}; +// #endregion + +// #region Inputs ... +input group "Replay Settings"; +input int startBar = 20; // Cutof Bars +input int autoPlaySpeed = 1000; // Auto-Play Speed (ms) + +input group "Presentation"; +input color panelButtonTextColor = clrYellow; // Button Text Color +input color panelBackgroundColor = clrBlack; // Panel Background +input color infoColor = clrWhite; // Info Color +input color infoPanelBorderColor = clrBlack; // Info Panel Border Color +// #endregion + +// #region Buffers ... +#define buffersCount 0 +#property indicator_chart_window +#property indicator_buffers 5 +#property indicator_plots 1 + +// +// Played Bar ... + +// +#define pBarOpenBufferIndex buffersCount +double pBarOpenBuffer[]; + +// +#define pBarHighBufferIndex buffersCount + 1 +double pBarHighBuffer[]; + +// +#define pBarLowBufferIndex buffersCount + 2 +double pBarLowBuffer[]; + +// +#define pBarCloseBufferIndex buffersCount + 3 +double pBarCloseBuffer[]; + +// +#define pBarColorBufferIndex buffersCount + 4 +double pBarColorBuffer[]; + +// +#define pBarBufferPlotIndex 0 +#property indicator_label1 "XPBar Open;XPBar High;XPBar Low;XPBar Close" +#property indicator_type1 DRAW_COLOR_CANDLES +#property indicator_color1 CLR_NONE, clrDodgerBlue, clrDarkOrange + +// +// Data Buffers ... + +// +// #define pBarTimeBufferIndex buffersCount + 5 +// datetime pBarTimeBuffer[]; + +// +// #define pBarTickVolumeBufferIndex buffersCount + 6 +// long pBarTickVolumeBuffer[]; + +// +// #define pBarVolumeBufferIndex buffersCount + 7 +// long pBarVolumeBuffer[]; + +// +// #define pBarSpreadBufferIndex buffersCount + 8 +// long pBarSpreadBuffer[]; +// #endregion + +// #region Variables ... +// +int xReplyLimit; +int xReplyMaxLength; +int xReplyFirstBarIndex; + +// +XChartStyle xReplyChartStyle; +XChartStyle xReplyClearStyle; +string xReplyChartStyleFileName = "XChartStyle_" + ShortName + "_" + _Symbol + "_" + ToXString(_Period) + ".bin"; + +// +// UI Object Names ... +string xReplyBtnPlay; +string xReplyBtnPrev; +string xReplyBtnNext; +string xReplyLblInfo; +string xReplyBtnPause; +string xReplyBtnReset; + +// +// Replay State ... +int xReplyCandlesCount = 0; +int xReplyStartBarIndex = 0; +bool xReplyIsPlaying = false; +ulong xReplyLastPlayTick = 0; +datetime xReplyStartTime = NULL; +int xReplyCurrentVisibleBars = 0; +// #endregion + +// #region Event Handlers ... +/** + * Initialize Indicator ... + * + * @return ( int ) + */ +int OnInit() +{ + // + bool has = false; + + // + // Validate Inputs ... + has = ValidateInputs(); + if (!has) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + xReplyMaxLength = ExtractxReplyMaxLengthOfInputs(); + + // + // Initial Requirements ... + has = InitRequirements(); + if (!has) + { + return INIT_FAILED; + } + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Apply Chart Style ... + ApplyCustomChartStyle(); + + // + int idx = startBar; + if (idx >= Bars(_Symbol, _Period)) + { + idx = Bars(_Symbol, _Period) - 10; + } + + // + xReplyStartTime = iTime(_Symbol, _Period, idx); + xReplyStartBarIndex = iBarShift(_Symbol, _Period, xReplyStartTime, false); + has = xReplyStartBarIndex >= 0; + if (!has) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Create UI Panel ... + CreatePanel(); + + // + // Initial Draw ... + xReplyCurrentVisibleBars = 1; + DrawVisibleCandles(); + UpdateInfoLabel(); + + // + // Enable Timer for Auto Play ... + EventSetMillisecondTimer(100); + + // + // Init Succeed ... + return INIT_SUCCEEDED; + + // +} + +/** + * De Initialize Indicator ... + * + * @param reason: Integer, De Initialization Reason ... + * - REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + * - REASON_REMOVE 1 Program removed from a chart + * - REASON_RECOMPILE 2 Program recompiled + * - REASON_CHARTCHANGE 3 A symbol or a chart period is changed + * - REASON_CHARTCLOSE 4 Chart closed + * - REASON_PARAMETERS 5 Inputs changed by a user + * - REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + * - REASON_TEMPLATE 7 Another chart template applied + * - REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + * - REASON_CLOSE 9 Terminal closed + */ +void OnDeinit(const int reason) +{ + // + // Show Saved Chart Style ... + ShowBars(); + + // + // Remove Chart Style File ... + FileDelete(xReplyChartStyleFileName); + + // + // Remove UI Objects ... + RemoveUIObjects(); + + // + // Kill Timer ... + EventKillTimer(); +} + +/** + * Calculate Bars ... + * + * @param rates_total: Integer, Total Bars on Chart ... + * @param prev_calculated: Integer, Total Calculated Bars on Charts ... + * @param time: DateTime Array, History of Open Time ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param low: Double Array, History of Low Prices ... + * @param close: Double Array, History of Close Prices ... + * @param tick_volume: Long, History of Tick Volumes on Bar ... + * @param volume: Long, History of Trade Volumes ... + * @param spread: Double, History of Spread Price ... + * + * @return ( int ) + */ +int OnCalculate( + const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[] // +) +{ + // + // Prepare Buffers ... + ArraySetAsSeries(time, true); + ArraySetAsSeries(open, true); + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(close, true); + ArraySetAsSeries(tick_volume, true); + ArraySetAsSeries(volume, true); + ArraySetAsSeries(spread, true); + + // + // Validate Calculated Bars ... + + // + bool isPassedRequiredCalculatedBars = true; + if (!isPassedRequiredCalculatedBars) + { + return prev_calculated; + } + + // + xReplyLimit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + + // + // Validate Copied Items ... + bool isPassedRequiredCopiedItems = true; + if (!isPassedRequiredCopiedItems) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = xReplyLimit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + if (prev_calculated == 0) + { + // + string message = "History Finished ..."; + Print(message); + } + + // + return rates_total; +} + +/** + * Handle Timer Event ... + */ +void OnTimer() +{ + // + if (!xReplyIsPlaying) + { + return; + } + + // + ulong now = GetTickCount64(); + if (now - xReplyLastPlayTick >= (ulong)autoPlaySpeed) + { + // + xReplyLastPlayTick = now; + StepForward(); + + // + // Auto Stop at Current Market Bar ... + if (xReplyStartBarIndex - xReplyCurrentVisibleBars <= 0) + { + // + xReplyIsPlaying = false; + ObjectSetInteger(0, xReplyBtnPlay, OBJPROP_STATE, false); + ObjectSetInteger(0, xReplyBtnPause, OBJPROP_STATE, true); + } + } +} + +/** + * Handle Chart Events ... + * + * @param id: int, Event id ... + * @param lparam: long, Event Long Parameter ... + * @param dparam: double, Event Double Parameter ... + * @param sparam: string, Event String Parameter ... + */ +void OnChartEvent( + const int id, // Event id ... + const long &lparam, // Event Long Parameter ... + const double &dparam, // Event Double Parameter ... + const string &sparam // Event String Parameter ... +) +{ + // + // Button Clicks ... + if (id == CHARTEVENT_OBJECT_CLICK) + { + // + if (sparam == xReplyBtnNext) + { + // + StepForward(); + ObjectSetInteger(0, xReplyBtnNext, OBJPROP_STATE, false); + ChartRedraw(); + } + else if (sparam == xReplyBtnPrev) + { + // + StepBackward(); + ObjectSetInteger(0, xReplyBtnPrev, OBJPROP_STATE, false); + ChartRedraw(); + } + else if (sparam == xReplyBtnPlay) + { + // + xReplyIsPlaying = true; + ObjectSetInteger(0, xReplyBtnPlay, OBJPROP_STATE, true); + ObjectSetInteger(0, xReplyBtnPause, OBJPROP_STATE, false); + ChartRedraw(); + } + else if (sparam == xReplyBtnPause) + { + // + xReplyIsPlaying = false; + ObjectSetInteger(0, xReplyBtnPause, OBJPROP_STATE, true); + ObjectSetInteger(0, xReplyBtnPlay, OBJPROP_STATE, false); + ChartRedraw(); + } + else if (sparam == xReplyBtnReset) + { + // + ResetReplay(); + ObjectSetInteger(0, xReplyBtnReset, OBJPROP_STATE, false); + ChartRedraw(); + } + // + return; + } + + // + // Keyboard Shortcuts ... + if (id == CHARTEVENT_KEYDOWN) + { + // + switch ((int)lparam) + { + // + // Arrow Right ... + case 38: + case 39: + StepForward(); + break; + // + // Arrow Left ... + case 37: + case 40: + StepBackward(); + break; + // + // Space ... + case 32: + xReplyIsPlaying = !xReplyIsPlaying; + ObjectSetInteger(0, xReplyBtnPlay, OBJPROP_STATE, xReplyIsPlaying); + ObjectSetInteger(0, xReplyBtnPause, OBJPROP_STATE, !xReplyIsPlaying); + ChartRedraw(); + break; + // + // R ... + case 82: + ResetReplay(); + break; + } + + // + return; + } +} +// #endregion + +// #region Custm Functions ... +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + // + IndicatorSetInteger(INDICATOR_DIGITS, _Digits); + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + startBar > 0 + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractxReplyMaxLengthOfInputs() +{ + // + int result = 0; + + // + + // + return result; +} + +/** + * Initial all Indicator Requirements ... + * + * @return ( false ) + * + */ +bool InitRequirements() +{ + // + bool result = false; + + // + // Handlers ... + result = true; + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // #region Plot Buffers ... + // + // SIGNAL Bar ... + + // + // Signal Bars Color ... + ArraySetAsSeries(pBarColorBuffer, true); + SetIndexBuffer(pBarColorBufferIndex, pBarColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Set EMPTY_VALUE on XHK Bar Buffer ... + PlotIndexSetDouble(pBarBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); + PlotIndexSetInteger(pBarBufferPlotIndex, PLOT_SHOW_DATA, false); + + // + // Open ... + ArraySetAsSeries(pBarOpenBuffer, true); + SetIndexBuffer(pBarOpenBufferIndex, pBarOpenBuffer, INDICATOR_DATA); + + // + // High ... + ArraySetAsSeries(pBarHighBuffer, true); + SetIndexBuffer(pBarHighBufferIndex, pBarHighBuffer, INDICATOR_DATA); + + // + // Low ... + ArraySetAsSeries(pBarLowBuffer, true); + SetIndexBuffer(pBarLowBufferIndex, pBarLowBuffer, INDICATOR_DATA); + + // + // Close ... + ArraySetAsSeries(pBarCloseBuffer, true); + SetIndexBuffer(pBarCloseBufferIndex, pBarCloseBuffer, INDICATOR_DATA); + + // + // Time ... + // ArraySetAsSeries(pBarTimeBuffer, true); + // SetIndexBuffer(pBarTimeBufferIndex, pBarTimeBuffer, INDICATOR_CALCULATIONS); + + // + // Tick Volume ... + // ArraySetAsSeries(pBarTickVolumeBuffer, true); + // SetIndexBuffer(pBarTickVolumeBufferIndex, pBarTickVolumeBuffer, INDICATOR_CALCULATIONS); + + // + // Volume ... + // ArraySetAsSeries(pBarVolumeBuffer, true); + // SetIndexBuffer(pBarVolumeBufferIndex, pBarVolumeBuffer, INDICATOR_CALCULATIONS); + + // + // Spread ... + // ArraySetAsSeries(pBarSpreadBuffer, true); + // SetIndexBuffer(pBarSpreadBufferIndex, pBarSpreadBuffer, INDICATOR_CALCULATIONS); + // #endregion +} + +/** + * Calculate Custom Buffers ... + * + * @param barIndex: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int barIndex, + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsxReplyLimit = ratesTotal; + xReplyFirstBarIndex = barsxReplyLimit - 1; + + // + bool canCalculate = + barIndex <= barsxReplyLimit; + if (canCalculate) + { + // + // Calculate Values ... + CalculateValues( + barIndex, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + } + else + { + FillBuffersZero(barIndex); + } +} + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + pBarColorBuffer[barIndex] = hideColorIDX; +} +// #endregion + +// #region Value Calculators ... +/** + * Calculate Values ... + * + * @param barIndex: int, Specified Bar Index ... + * @param prevCalculated: int, Provides Previous Calculated Bars ... + * @param ratesTotal: int, Provides All Availabled Bars ... + * @param open: double Collection, Provides Open Prices Time Series ... + * @param high: double Collection, Provides High Prices Time Series ... + * @param close: double Collection, Provides Close Prices Time Series ... + * @param low: double Collection, Provides Low Prices Time Series ... + * @param tickVolume: long Collection, Provides Ticks Volume Prices Time Series ... + */ +void CalculateValues( + int barIndex, + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int lastBarIndex = barIndex + 1; + int maxBarIndex = ratesTotal; + bool isFirstBar = barIndex == xReplyFirstBarIndex; + + // + // Filling Buffers ... + pBarLowBuffer[barIndex] = low[barIndex]; + pBarOpenBuffer[barIndex] = open[barIndex]; + pBarHighBuffer[barIndex] = high[barIndex]; + pBarCloseBuffer[barIndex] = close[barIndex]; + + // + // Actually Bars Color Index ... + int colorIDX = + close[barIndex] >= open[barIndex] + ? bullishColorIDX + : close[barIndex] < open[barIndex] + ? bearishColorIDX + : neuturalColorIDX; + + // + int selectedColorIDX = colorIDX; + if (barIndex <= startBar) + { + selectedColorIDX = hideColorIDX; + } + pBarColorBuffer[barIndex] = selectedColorIDX; +} +// #endregion + +// #region Chart Style ... +/** + * Show Bars ... + */ +void ShowBars() +{ + LoadChartStyleFromFile(xReplyChartStyle); + SetChartStyle(xReplyChartStyle); +} + +/** + * Show Hide ... + */ +void HideBars() +{ + SetChartStyle(xReplyClearStyle); +} + +/** + * Read and Save Chart Style ... + */ +void ReadChartStyle() +{ + // + if (LoadChartStyleFromFile(xReplyChartStyle)) + { + return; + } + + // + // Retrieve Current Chart ID ... + long chartId = ChartID(); + xReplyChartStyle.chartId = chartId; + + // + // Retrieve Chart Mode ... + xReplyChartStyle.mode = (ENUM_CHART_MODE)ChartGetInteger(chartId, CHART_MODE); + + // + xReplyChartStyle.showBidLine = (bool)ChartGetInteger(chartId, CHART_SHOW_BID_LINE); + xReplyChartStyle.showAskLine = (bool)ChartGetInteger(chartId, CHART_SHOW_ASK_LINE); + xReplyChartStyle.showGrid = (bool)ChartGetInteger(chartId, CHART_SHOW_GRID); + xReplyChartStyle.showVolumes = (bool)ChartGetInteger(chartId, CHART_SHOW_VOLUMES); + xReplyChartStyle.showTradeLevels = (bool)ChartGetInteger(chartId, CHART_SHOW_TRADE_LEVELS); + xReplyChartStyle.autoScroll = (bool)ChartGetInteger(chartId, CHART_AUTOSCROLL); + xReplyChartStyle.quickNavigation = (bool)ChartGetInteger(chartId, CHART_QUICK_NAVIGATION); + + // + xReplyChartStyle.foreGroundColor = (color)ChartGetInteger(chartId, CHART_COLOR_FOREGROUND); + xReplyChartStyle.backGroundColor = (color)ChartGetInteger(chartId, CHART_COLOR_BACKGROUND); + xReplyChartStyle.upColor = (color)ChartGetInteger(chartId, CHART_COLOR_CHART_UP); + xReplyChartStyle.downColor = (color)ChartGetInteger(chartId, CHART_COLOR_CHART_DOWN); + xReplyChartStyle.bullishColor = (color)ChartGetInteger(chartId, CHART_COLOR_CANDLE_BULL); + xReplyChartStyle.bearishColor = (color)ChartGetInteger(chartId, CHART_COLOR_CANDLE_BEAR); + xReplyChartStyle.gridColor = (color)ChartGetInteger(chartId, CHART_COLOR_GRID); + xReplyChartStyle.bidLineColor = (color)ChartGetInteger(chartId, CHART_COLOR_BID); + xReplyChartStyle.askLineColor = (color)ChartGetInteger(chartId, CHART_COLOR_ASK); + xReplyChartStyle.stopColor = (color)ChartGetInteger(chartId, CHART_COLOR_STOP_LEVEL); + xReplyChartStyle.lineColor = (color)ChartGetInteger(chartId, CHART_COLOR_CHART_LINE); + xReplyChartStyle.volumesColor = (color)ChartGetInteger(chartId, CHART_COLOR_VOLUME); + + // + SaveChartStyleToFile(xReplyChartStyle); +} + +/** + * Setting Chart Style based on given Configuration ... + * + * @param mChartStyle: XChartStyle instance ... + */ +void SetChartStyle( + XChartStyle &mChartStyle // Chart Style to Apply +) +{ + // + ApplyChartStyle( + mChartStyle.chartId, + mChartStyle.mode, + mChartStyle.showBidLine, + mChartStyle.showAskLine, + mChartStyle.showGrid, + mChartStyle.showVolumes, + mChartStyle.showTradeLevels, + mChartStyle.autoScroll, + mChartStyle.quickNavigation, + mChartStyle.foreGroundColor, + mChartStyle.backGroundColor, + mChartStyle.upColor, + mChartStyle.downColor, + mChartStyle.bullishColor, + mChartStyle.bearishColor, + mChartStyle.gridColor, + mChartStyle.bidLineColor, + mChartStyle.askLineColor, + mChartStyle.lineColor, + mChartStyle.stopColor, + mChartStyle.volumesColor); +} + +/** + * Setting Chart Style by Providing required data ... + * + * @param mChartId: int, Chart ID ... + * @param mMode: ENUM_CHART_MODE, Chart Bars Style ... + * @param mShowBidLine: bool, Show Bid Line ... + * @param mShowAskLine: bool, Show Ask Line ... + * @param mShowGrid: bool, Show Grids ... + * @param mShowVolumes: bool, Show Volumes ... + * @param mShowTradeLevels: bool, Show Trade Levels ... + * @param mAutoScroll: bool, Auto Scroll Chart ... + * @param mQuickNavigation: bool, Show Quick Navigations ... + * @param mForeGroundColor: color, Foreground Color ... + * @param mBackGroundColor: color, Background Color ... + * @param mUpColor: color, Up Bars Color ... + * @param mDownColor: color, Down Bars Color ... + * @param mBullishColor: color, Bullish Bars Color ... + * @param mBearishColor: color, Bearish Bars Color ... + * @param mGridColor: color, Chart Grid Color ... + * @param mBidLineColor: color, Bid Line Color ... + * @param mAskLineColor: color, Ask Line Color ... + * @param mLineColor: color, Bars Line Color ... + * @param mStopColor: color, Trading Stop Color ... + * @param mVolumesColor: color, Volumes Bar Color ... + */ +void ApplyChartStyle( + long mChartId = -1, // chart's ID + ENUM_CHART_MODE mMode = CHART_CANDLES, // chart's mMode + bool mShowBidLine = true, // show bid line + bool mShowAskLine = true, // show ask line + bool mShowGrid = false, // show grids on chart + bool mShowVolumes = false, // show volumes + bool mShowTradeLevels = true, // Displaying trade levels in the chart (levels of open positions, Stop Loss, Take Profit and pending orders) + bool mAutoScroll = true, // chart autoscroll + bool mQuickNavigation = true, // chart quick navigation state + color mForeGroundColor = clrWhite, // chart's foreground color + color mBackGroundColor = clrBlack, // chart's background color + color mUpColor = clrGreen, // Up Color + color mDownColor = clrRed, // Down Color + color mBullishColor = clrGreen, // Bullish color + color mBearishColor = clrRed, // Bearish color + color mGridColor = clrGray, // grid color + color mBidLineColor = clrGray, // bid line color + color mAskLineColor = clrRed, // ask line color + color mLineColor = clrLime, // line mMode and doji candlestick color + color mStopColor = clrGold, // Color of stop order levels (Stop Loss and Take Profit) + color mVolumesColor = clrGreen // volumes color +) +{ + // + // Validate Args ... + if (mChartId == -1) + { + mChartId = 0; + } + + // + ChartSetInteger(mChartId, CHART_MODE, mMode); + ChartSetInteger(mChartId, CHART_SHOW_BID_LINE, mShowBidLine); + ChartSetInteger(mChartId, CHART_SHOW_ASK_LINE, mShowAskLine); + ChartSetInteger(mChartId, CHART_SHOW_GRID, mShowGrid); + ChartSetInteger(mChartId, CHART_SHOW_VOLUMES, mShowVolumes); + ChartSetInteger(mChartId, CHART_SHOW_TRADE_LEVELS, mShowTradeLevels); + ChartSetInteger(mChartId, CHART_AUTOSCROLL, mAutoScroll); + ChartSetInteger(mChartId, CHART_QUICK_NAVIGATION, mQuickNavigation); + ChartSetInteger(mChartId, CHART_COLOR_FOREGROUND, mForeGroundColor); + ChartSetInteger(mChartId, CHART_COLOR_BACKGROUND, mBackGroundColor); + ChartSetInteger(mChartId, CHART_COLOR_CHART_UP, mUpColor); + ChartSetInteger(mChartId, CHART_COLOR_CHART_DOWN, mDownColor); + ChartSetInteger(mChartId, CHART_COLOR_CANDLE_BULL, mBullishColor); + ChartSetInteger(mChartId, CHART_COLOR_CANDLE_BEAR, mBearishColor); + ChartSetInteger(mChartId, CHART_COLOR_GRID, mGridColor); + ChartSetInteger(mChartId, CHART_COLOR_BID, mBidLineColor); + ChartSetInteger(mChartId, CHART_COLOR_ASK, mAskLineColor); + ChartSetInteger(mChartId, CHART_COLOR_STOP_LEVEL, mStopColor); + ChartSetInteger(mChartId, CHART_COLOR_CHART_LINE, mLineColor); + ChartSetInteger(mChartId, CHART_COLOR_VOLUME, mVolumesColor); + + // + ChartRedraw(); +} + +/** + * Apply Custom Chart Style ... + */ +void ApplyCustomChartStyle() +{ + // + // Read Current Chart Config and Store it ... + ReadChartStyle(); + + // + // After Reading Current Chart Style ... + // we have to Save Configs and Change Styles ... + xReplyClearStyle = xReplyChartStyle; + + // + xReplyClearStyle.upColor = CLR_NONE; + xReplyClearStyle.downColor = CLR_NONE; + xReplyClearStyle.lineColor = CLR_NONE; + xReplyClearStyle.bullishColor = CLR_NONE; + xReplyClearStyle.bearishColor = CLR_NONE; + + // + // Decide to Show or not Candles based on User Input ... + HideBars(); +} + +/** + * Save Chart Style ... + * + * @param style: XChartStyle instance ... + * + * @return ( bool ) + */ +bool SaveChartStyleToFile( + const XChartStyle &style // +) +{ + // + bool result = false; + + // + // Create a File Handler for Writing Content to File ... + int fileHandler = FileOpen(xReplyChartStyleFileName, FILE_WRITE | FILE_BIN | FILE_COMMON); + result = fileHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + // Writing Struct to File ... + uint bytesWritten = FileWriteStruct(fileHandler, style); + FileClose(fileHandler); + result = bytesWritten > 0; + + // + return result; +} + +/** + * Load Chart Style ... + * + * @param style: XChartStyle instance ... + * + * @return ( bool ) + */ +bool LoadChartStyleFromFile( + XChartStyle &style // +) +{ + // + bool result = false; + + // + // Create a File Handler for Reading File Content ... + int fileHandler = FileOpen(xReplyChartStyleFileName, FILE_READ | FILE_BIN | FILE_COMMON); + result = fileHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + // Read File Content and Fill Struct ... + uint bytesRead = FileReadStruct(fileHandler, style); + FileClose(fileHandler); + + // + result = bytesRead > 0; + if (!result) + { + return result; + } + + // + return result; +} +// #endregion + +// #region UI ... +/** + * Create UI Panel ... + */ +void CreatePanel() +{ + // + xReplyBtnPlay = ShortName + "_BTN_PLAY"; + xReplyBtnPause = ShortName + "_BTN_PAUSE"; + xReplyBtnPrev = ShortName + "_BTN_PREV"; + xReplyBtnNext = ShortName + "_BTN_NEXT"; + xReplyBtnReset = ShortName + "_BTN_RESET"; + xReplyLblInfo = ShortName + "_LBL_INFO"; + + // + int x = 20; + int y = 30; + int w = 45; + int h = 30; + int gap = 5; + + // + // Prev Button ... + CreateButton( + xReplyBtnPrev, + x, + y, + w, + h, + "|<", + clrLightSkyBlue // + ); + + // + // Play Button ... + CreateButton( + xReplyBtnPlay, + x + (w + gap) * 1, + y, + w, + h, + ">", + clrLimeGreen // + ); + + // + // Pause Button ... + CreateButton( + xReplyBtnPause, + x + (w + gap) * 2, + y, + w, + h, + "||", + clrGoldenrod // + ); + + // + // Next Button ... + CreateButton( + xReplyBtnNext, + x + (w + gap) * 3, + y, + w, + h, + ">|", + clrLightSkyBlue // + ); + + // + // Reset Button ... + CreateButton( + xReplyBtnReset, + x + (w + gap) * 4, + y, + w, + h, + "R", + clrTomato // + ); + + // + // Info Label ... + ObjectCreate(0, xReplyLblInfo, OBJ_EDIT, 0, 0, 0); + ObjectSetInteger(0, xReplyLblInfo, OBJPROP_XDISTANCE, x); + ObjectSetInteger(0, xReplyLblInfo, OBJPROP_YDISTANCE, y + h + gap); + ObjectSetInteger(0, xReplyLblInfo, OBJPROP_XSIZE, (w + gap) * 5 - gap); + ObjectSetInteger(0, xReplyLblInfo, OBJPROP_YSIZE, 22); + ObjectSetInteger(0, xReplyLblInfo, OBJPROP_BGCOLOR, panelBackgroundColor); + ObjectSetInteger(0, xReplyLblInfo, OBJPROP_COLOR, infoColor); + ObjectSetInteger(0, xReplyLblInfo, OBJPROP_BORDER_COLOR, infoPanelBorderColor); + ObjectSetInteger(0, xReplyLblInfo, OBJPROP_READONLY, true); + ObjectSetInteger(0, xReplyLblInfo, OBJPROP_FONTSIZE, 9); + ObjectSetString(0, xReplyLblInfo, OBJPROP_FONT, "Arial"); + ObjectSetInteger(0, xReplyLblInfo, OBJPROP_CORNER, CORNER_LEFT_UPPER); + ObjectSetInteger(0, xReplyLblInfo, OBJPROP_SELECTABLE, false); + + // + ChartRedraw(); +} + +/** + * Create Specified Button ... + * + * @param name: string, Object Name ... + * @param x: int, X Position ... + * @param y: int, Y Position ... + * @param w: int, Width ... + * @param h: int, Height ... + * @param text: int Button Text ... + * @param borderClr: color, Border Color ... + */ +void CreateButton( + string name, // Button Name ... + int x, // X Position ... + int y, // Y Position ... + int w, // Width ... + int h, // Height ... + string text, // Button Text ... + color borderClr // Border Color ... +) +{ + // + ObjectCreate(0, name, OBJ_BUTTON, 0, 0, 0); + ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x); + ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y); + ObjectSetInteger(0, name, OBJPROP_XSIZE, w); + ObjectSetInteger(0, name, OBJPROP_YSIZE, h); + ObjectSetInteger(0, name, OBJPROP_BGCOLOR, panelBackgroundColor); + ObjectSetInteger(0, name, OBJPROP_COLOR, panelButtonTextColor); + ObjectSetInteger(0, name, OBJPROP_BORDER_COLOR, borderClr); + ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 11); + ObjectSetString(0, name, OBJPROP_FONT, "Arial Bold"); + ObjectSetString(0, name, OBJPROP_TEXT, text); + ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER); + ObjectSetInteger(0, name, OBJPROP_STATE, false); + ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); +} + +/** + * Remove All Drawn Objects ... + */ +void RemoveUIObjects() +{ + // + long cid = ChartID(); + for (int i = ObjectsTotal(cid, 0) - 1; i >= 0; i--) + { + // + string name = ObjectName(cid, i, 0); + if (StringFind(name, ShortName + "_") >= 0) + { + ObjectDelete(cid, name); + } + } + + // + ChartRedraw(); +} + +/** + * Update Information Label ... + */ +void UpdateInfoLabel() +{ + // + int shownBars = MathMin( + xReplyCurrentVisibleBars, + xReplyStartBarIndex + 1 // + ); + + // + int currentBarIdx = xReplyStartBarIndex - shownBars + 1; + if (currentBarIdx < 0) + { + currentBarIdx = 0; + } + + // + datetime barTime = iTime(_Symbol, _Period, currentBarIdx); + string status = xReplyIsPlaying + ? "PLAYING" + : "PAUSED"; + + // + string info = StringFormat( + "Bar: %d / %d | %s | %s", + shownBars, + xReplyStartBarIndex + 1, + TimeToString(barTime, TIME_DATE | TIME_MINUTES), + status // + ); + + // + ObjectSetString(0, xReplyLblInfo, OBJPROP_TEXT, info); + ChartRedraw(); +} + +/** + * Handle Show Visible Bars ... + */ +void DrawVisibleCandles() +{ + // + if (ArraySize(pBarColorBuffer) <= 0) + { + return; + } + + // + // Destroy Existing Candle Objects ... + ArrayInitialize(pBarColorBuffer, hideColorIDX); + + // + int barsToDraw = MathMin( + xReplyCurrentVisibleBars, + xReplyStartBarIndex + 1 // + ); + + // + int barSeconds = PeriodSeconds(_Period); + + // + // Resize Candle Array ... + xReplyCandlesCount = barsToDraw; + + // + // Main Loop ... + bool isBullish = false; + int colorIDX = hideColorIDX; + for (int i = 0; i < barsToDraw; i++) + { + // + int barIdx = xReplyStartBarIndex - i; + if (barIdx < 0) + { + break; + } + + // + isBullish = + pBarCloseBuffer[barIdx] >= pBarOpenBuffer[barIdx]; + colorIDX = + isBullish + ? bullishColorIDX + : bearishColorIDX; + pBarColorBuffer[barIdx] = colorIDX; + } + + // + for (int i = xReplyStartBarIndex + 1; i < ArraySize(pBarColorBuffer); i++) + { + // + isBullish = + pBarCloseBuffer[i] >= pBarOpenBuffer[i]; + colorIDX = + isBullish + ? bullishColorIDX + : bearishColorIDX; + pBarColorBuffer[i] = colorIDX; + } + + // + ChartRedraw(); +} +// #endregion + +// #region Control Actions ... +/** + * Handle Step Forward Action ... + */ +void StepForward() +{ + // + int maxBars = xReplyStartBarIndex + 1; + if (xReplyCurrentVisibleBars < maxBars) + { + // + xReplyCurrentVisibleBars++; + DrawVisibleCandles(); + UpdateInfoLabel(); + + // + int currentBarIndex = xReplyStartBarIndex - xReplyCurrentVisibleBars + 1; + ScrollToBar(currentBarIndex); + } +} + +/** + * Handle Step Backward Action ... + */ +void StepBackward() +{ + // + if (xReplyCurrentVisibleBars > 1) + { + // + xReplyCurrentVisibleBars--; + DrawVisibleCandles(); + UpdateInfoLabel(); + + // + int currentBarIndex = xReplyStartBarIndex - xReplyCurrentVisibleBars + 1; + ScrollToBar(currentBarIndex); + } +} + +/** + * Handle Reset Reply Action ... + */ +void ResetReplay() +{ + // + xReplyCurrentVisibleBars = 1; + xReplyIsPlaying = false; + + // + ObjectSetInteger(0, xReplyBtnPlay, OBJPROP_STATE, false); + ObjectSetInteger(0, xReplyBtnPause, OBJPROP_STATE, true); + + // + DrawVisibleCandles(); + UpdateInfoLabel(); + + // + ScrollToBar(xReplyStartBarIndex); +} + +/** + * Scroll Chart to Specified Bar Index ... + * + * @param barIndex: int, Specified Bar Index ... + */ +void ScrollToBar(int barIndex) +{ + // + // Validate Bar Index ... + int totalBars = Bars(_Symbol, _Period); + if (barIndex < 0 || barIndex >= totalBars) + { + return; + } + + // + // Set First Visible Bar to Specified Index ... + ChartSetInteger(ChartID(), CHART_FIRST_VISIBLE_BAR, barIndex); + ChartRedraw(); +} +// #endregion \ No newline at end of file diff --git a/MQL5.code-workspace b/MQL5.code-workspace index cb107554..e7947f34 100644 --- a/MQL5.code-workspace +++ b/MQL5.code-workspace @@ -16,6 +16,15 @@ "*.mq5": "cpp", "*.mqh": "cpp", "*.ex5": "cpp" + }, + "maptz.regionfolder": { + "[cpp]": { + "foldStart": "//#region [NAME]", + "foldEnd": "//#endregion", + "foldEndRegex": "//[\\s]*#endregion", + "foldStartRegex": "//[\\s]*#region[\\s]*(.*)", + "disableFolding": false + } } } -} +} \ No newline at end of file