/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Indicator // ------------------------------------------------- // Name: XTick Oscillator // Description: Tick Charts ... // // // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) // ////////////////////////////////////////////////////// // // Global Properties ... #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://saherelm.ir" #property version "1.00" #property description "SaherElm XTick Oscillator" #property strict // // Definitions ... // #define ShortName "XTick" // // Declaration of the enumeration enum ENUM_X_PRICE_TYPES { X_Bid, // Bid X_Ask // Ask }; // // Includes Common Library ... #include "../Libraries/x-saherelm.common.lib.mq5" // // Inputs ... // input group "Makret"; // input group "Chart Config"; input int ticksCount = 3; // Ticks Count input ENUM_X_PRICE_TYPES appliedPrice = 0; // Price // input group "Moving Average"; input int maLength = 10; // Length input int maShift = 0; // Shift input ENUM_MA_METHOD maMethod = MODE_SMA; // Mode input ENUM_X_PRICE maAppliedTo = X_PRICE_CLOSE; // Applied To // input group "Presentation"; input bool showBars = true; // Show Bars input bool showMa = true; // Show Moving Average // // Buffers ... // #property indicator_separate_window // #property indicator_buffers 8 #property indicator_plots 2 // double openBuffer[]; #define openBufferIndex 0 // double highBuffer[]; #define highBufferIndex 1 // double lowBuffer[]; #define lowBufferIndex 2 // double closeBuffer[]; #define closeBufferIndex 3 // double colorBuffer[]; #define colorBufferIndex 4 // #define barBufferIndex 0 #property indicator_label1 "Open;High;Low;Close" #property indicator_type1 DRAW_COLOR_CANDLES #property indicator_color1 CLR_NONE, clrGray, clrAqua, clrMagenta // double maBuffer[]; #define maBufferIndex 5 #define maPlotBufferIndex 1 // #property indicator_label2 "MA" #property indicator_type2 DRAW_LINE // DRAW_COLOR_LINE #property indicator_color2 clrRoyalBlue // CLR_NONE, clrGreen, clrRed #property indicator_style2 STYLE_DOT #property indicator_width2 1 // double ticksBuffer[]; #define ticksBufferIndex 6 // double maPriceBuffer[]; #define maPriceBufferIndex 7 // #define hideColorIDX 0; #define neuturalColorIDX 1; #define bullishColorIDX 2; #define bearishColorIDX 3; // // The variable contains the number of stored quotes ... int ticks_stored; // // The variable specifies the path and prefix to the file name ... string path_prefix = ""; // FileName Prefix // // Event Handlers ... /** * Initialize Indicator ... * * @return ( int ) */ int OnInit() { // // Validate Inputs ... if (!ValidateInputs()) { return INIT_PARAMETERS_INCORRECT; } // // Define Index Buffers ... DefineBuffers(); // // Set Indicator ShortName ... SetIndicatorName(); // // Init Succeed ... return INIT_SUCCEEDED; } /** * De Initialize Indicator ... * * @param reason: Integer, De Initialization Reason ... */ 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 } /** * 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); // int file_handle; // is a file handle int bidPosition; // are positions of Bid prices in the string int askPosition; // are positions of Ask prices in the string int line_string_len; // is a length of a string, read from the file int barNumber; // number of candle, for which the prices OHLC are determined int i; // loop counter // // the recent received Bid price ... double last_price_bid = SymbolInfoDouble(Symbol(), SYMBOL_BID); // // the recent received Ask price ... double last_price_ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK); // string filename; // name of a file, the file_buffer is a string string file_buffer; // a buffer for reading and writing of string data // // Setting the size of ticksBuffer array ... ArrayResize(ticksBuffer, ArraySize(closeBuffer)); // // File name formation from the path_prefix variable, name // of financial instrument and ".Txt" symbols StringConcatenate(filename, path_prefix, Symbol(), ".txt"); // // Opening a file for reading and writing, codepage ANSI, shared reading mode file_handle = FileOpen(filename, FILE_READ | FILE_WRITE | FILE_ANSI | FILE_SHARE_READ); if (prev_calculated == 0) { // // Reading the first line from the file and determine the length of a string ... line_string_len = StringLen(FileReadString(file_handle)) + 2; // // if file is large (contains more quotes than rates_total/2) ... if (FileSize(file_handle) > (ulong)line_string_len * rates_total / 2) { // // Setting file pointer to read the latest rates_total/2 quotes FileSeek(file_handle, -line_string_len * rates_total / 2, SEEK_END); // // Moving file pointer to the beginning of the next line FileReadString(file_handle); } // // if file size is small else { // // Moving file pointer at the beginning of a file FileSeek(file_handle, 0, SEEK_SET); } // // Reset the counter of stored quotes ticks_stored = 0; // // Reading until the end of the file while (FileIsEnding(file_handle) == false) { // // Reading a string from thefile file_buffer = FileReadString(file_handle); // // Processing of string if its length is larger than 6 characters if (StringLen(file_buffer) > 6) { // // Finding the start position of Bid price in the line bidPosition = StringFind(file_buffer, " ", StringFind(file_buffer, " ") + 1) + 1; // // Finding the start position of Ask price in the line askPosition = StringFind(file_buffer, " ", bidPosition) + 1; // // If the Bid prices are used, adding the Bid price to ticksBuffer[] array if (appliedPrice == 0) { ticksBuffer[ticks_stored] = StringToDouble(StringSubstr(file_buffer, bidPosition, askPosition - bidPosition - 1)); } // // If the Ask prices are used, adding the Ask price to ticksBuffer[] array if (appliedPrice == 1) { ticksBuffer[ticks_stored] = StringToDouble(StringSubstr(file_buffer, askPosition)); } // // Increasing the counter of stored quotes ticks_stored++; } } } // // If the data have been read before else { // // Moving file pointer at the end of the file FileSeek(file_handle, 0, SEEK_END); // // Forming a string, that should be written to the file StringConcatenate(file_buffer, TimeCurrent(), " ", DoubleToString(last_price_bid, _Digits), " ", DoubleToString(last_price_ask, _Digits)); // // Writing a string to the file FileWrite(file_handle, file_buffer); // // If the Bid prices are used, adding the last Bid price to ticksBuffer[] array if (appliedPrice == 0) { ticksBuffer[ticks_stored] = last_price_bid; } // // If the Ask prices are used, adding the last Ask price to ticksBuffer[] array if (appliedPrice == 1) { ticksBuffer[ticks_stored] = last_price_ask; } // // Increasing the quotes counter ticks_stored++; } // // Closing the file FileClose(file_handle); // // If number of quotes is more or equal than number of bars in the chart if (ticks_stored >= rates_total) { // // Removing the first tick_stored/2 quotes and shifting remaining quotes for (i = ticks_stored / 2; i < ticks_stored; i++) { // // Shifting the data to the beginning in the ticksBuffer[] array on tick_stored/2 ticksBuffer[i - ticks_stored / 2] = ticksBuffer[i]; } // // Changing the quotes counter ticks_stored -= ticks_stored / 2; } // // We assign the barNumber with a number of invalid candle barNumber = -1; // // Search for all the price data available for candle formation for (i = 0; i < ticks_stored; i++) { // // If this candle is forming already if (barNumber == (int)(MathFloor((ticks_stored - 1) / ticksCount) - MathFloor(i / ticksCount))) { // // The current quote is still closing price of the current candle closeBuffer[barNumber] = ticksBuffer[i]; // // If the current price is greater than the highest price of the current candle, it will be a new highest price of the candle if (ticksBuffer[i] > highBuffer[barNumber]) { highBuffer[barNumber] = ticksBuffer[i]; } // // If the current price is lower than the lowest price of the current candle, it will be a new lowest price of the candle if (ticksBuffer[i] < lowBuffer[barNumber]) { lowBuffer[barNumber] = ticksBuffer[i]; } // // If the candle is bullish ... if (closeBuffer[barNumber] > openBuffer[barNumber]) { colorBuffer[barNumber] = bullishColorIDX; } // // If the candle is bearish ... if (closeBuffer[barNumber] < openBuffer[barNumber]) { colorBuffer[barNumber] = bearishColorIDX; } // // If the opening and closing prices are equal, then the candle will have a color with index 0 (grey) if (closeBuffer[barNumber] == openBuffer[barNumber]) { colorBuffer[barNumber] = neuturalColorIDX; } } // // If this candle hasn't benn calculated yet else { // // Let's determine the index of a candle barNumber = (int)(MathFloor((ticks_stored - 1) / ticksCount) - MathFloor(i / ticksCount)); // // The current quote will be the opening price of a candle openBuffer[barNumber] = ticksBuffer[i]; // // The current quote will be the highest price of a candle highBuffer[barNumber] = ticksBuffer[i]; // // The current quote will be the lowest price of a candle lowBuffer[barNumber] = ticksBuffer[i]; // // The current quote will be the closing price of a candle closeBuffer[barNumber] = ticksBuffer[i]; // // The candle will have a color with index 0 (gray) colorBuffer[barNumber] = 0; } } // // Custom Calculations ... // int limit = (prev_calculated > rates_total || prev_calculated <= 0) ? rates_total : (rates_total - prev_calculated) + 1; // // Main Loop ... for (int i = limit - 1; i >= 0 && !IsStopped(); i--) { // CalculateBuffers( i, prev_calculated, rates_total // ); } // // Return from OnCalculate(), return a value, different from zero return (rates_total); } // // Functions ... /** * Validate Input Args for Initialization ... * * @return ( bool ) */ bool ValidateInputs() { // bool result = // ticksCount > 0 // ; // return result; } /** * Define Required Buffers ... */ void DefineBuffers() { // // Color ... ArraySetAsSeries(colorBuffer, true); SetIndexBuffer(colorBufferIndex, colorBuffer, INDICATOR_COLOR_INDEX); // // Set EMPTY_VALUE on Bar Buffer ... PlotIndexSetDouble(barBufferIndex, PLOT_EMPTY_VALUE, 0.0); // PlotIndexSetInteger(barBufferIndex, PLOT_SHOW_DATA, false); PlotIndexSetInteger(colorBufferIndex, PLOT_SHOW_DATA, false); // // Open ... ArraySetAsSeries(openBuffer, true); PlotIndexSetInteger(openBufferIndex, PLOT_SHOW_DATA, true); SetIndexBuffer(openBufferIndex, openBuffer, INDICATOR_DATA); // // High ... ArraySetAsSeries(highBuffer, true); PlotIndexSetInteger(highBufferIndex, PLOT_SHOW_DATA, true); SetIndexBuffer(highBufferIndex, highBuffer, INDICATOR_DATA); // // Close ... ArraySetAsSeries(closeBuffer, true); PlotIndexSetInteger(closeBufferIndex, PLOT_SHOW_DATA, true); SetIndexBuffer(closeBufferIndex, closeBuffer, INDICATOR_DATA); // // Low ... ArraySetAsSeries(lowBuffer, true); PlotIndexSetInteger(lowBufferIndex, PLOT_SHOW_DATA, true); SetIndexBuffer(lowBufferIndex, lowBuffer, INDICATOR_DATA); // bool canShowMa = showMa; ArraySetAsSeries(maBuffer, true); SetIndexBuffer(maBufferIndex, maBuffer, INDICATOR_DATA); PlotIndexSetDouble(maPlotBufferIndex, PLOT_EMPTY_VALUE, 0); PlotIndexSetInteger(maPlotBufferIndex, PLOT_DRAW_BEGIN, maLength); PlotIndexSetInteger(maPlotBufferIndex, PLOT_SHOW_DATA, showMa); // // Data Buffers ... // // The TicksBuffer[] array is used for intermediate calculations SetIndexBuffer(ticksBufferIndex, ticksBuffer, INDICATOR_CALCULATIONS); // ArraySetAsSeries(maPriceBuffer, true); SetIndexBuffer(maPriceBufferIndex, maPriceBuffer, INDICATOR_CALCULATIONS); } /** * Set Indicator Short Name and also we can define Buffers Labels ... */ void SetIndicatorName() { IndicatorSetString(INDICATOR_SHORTNAME, ShortName); } /** * Calculate Custom Buffers ... * * @param barIndex: Integer ... */ void CalculateBuffers( int barIndex, int prevCalculated, int ratesTotal // ) { // bool canDoMovingAverage = maLength > 0 && maAppliedTo != X_PRICE_UP && maAppliedTo != X_PRICE_DOWN; if (canDoMovingAverage) { // // Do Moving Average Calculations ... // // Select Ma Price ... double iPrice = 0; switch (maAppliedTo) { // case X_PRICE_HIGH: iPrice = highBuffer[barIndex]; break; // case X_PRICE_OPEN: iPrice = openBuffer[barIndex]; break; // case X_PRICE_CLOSE: iPrice = closeBuffer[barIndex]; break; // case X_PRICE_LOW: iPrice = lowBuffer[barIndex]; break; } // maPriceBuffer[barIndex] = iPrice; int total = ArraySize(closeBuffer); // int calculatedMas = iMAOnBuffer( total, prevCalculated, barIndex, maLength, maPriceBuffer, maBuffer, maMethod // ); } } //