Join our fan page
- Views:
- 1189
- Rating:
- Published:
-
Need a robot or indicator based on this code? Order it on Freelance Go to Freelance
Standard API functions ChartXYToTimePrice and ChartTimePriceToXY have significant drawbacks. For example, ChartXYToTimePrice works correctly only if the input parameters X and Y are in the visible area of the chart window, outside the window the function returns zeros. ChartTimePriceToXY also works incorrectly in some cases. Both functions are slow.
I present the functions that work correctly in all ranges of input parameters:
int GetXFromTime(datetime time) { int pixels_per_bar = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS) / (int)ChartGetInteger(0, CHART_WIDTH_IN_BARS) + 1; double pixels_per_time = (double)pixels_per_bar / PeriodSeconds(); int first_bar = (int)ChartGetInteger(0, CHART_FIRST_VISIBLE_BAR); datetime time_first_bar = iTime(Symbol(), Period(), first_bar); datetime time_0 = iTime(Symbol(), Period(), 0); if(time <= time_0) { int nearest_bar = iBarShift(Symbol(), Period(), time); datetime time_nearest_bar = iTime(Symbol(), Period(), nearest_bar); datetime time_remaining = time - time_nearest_bar; time_remaining -= (int)MathFloor(time_remaining / PeriodSeconds()) * PeriodSeconds(); return (first_bar - nearest_bar) * pixels_per_bar + (int)MathRound(time_remaining * pixels_per_time); } else return first_bar * pixels_per_bar + (int)MathRound((time - time_0) * pixels_per_time); } //+------------------------------------------------------------------+ int GetYFromPrice(double price) { double price_max = ChartGetDouble(0, CHART_PRICE_MAX); double price_min = ChartGetDouble(0, CHART_PRICE_MIN); double pixels_per_price = ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS) / (price_max - price_min); return (int)MathRound((price_max - price) * pixels_per_price); } //+------------------------------------------------------------------+ datetime GetTimeFromX(int x_dist) { int first_bar = (int)ChartGetInteger(0, CHART_FIRST_VISIBLE_BAR); datetime time_first_bar = iTime(Symbol(), Period(), first_bar); int pixels_per_bar = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS) / (int)ChartGetInteger(0, CHART_WIDTH_IN_BARS) + 1; double time_per_pixel = (double)PeriodSeconds() / pixels_per_bar; datetime time_remaining = (int)(((double)x_dist / pixels_per_bar - (int)(x_dist / pixels_per_bar)) * pixels_per_bar * time_per_pixel); int nearest_bar = first_bar - (int)(x_dist / pixels_per_bar); datetime time_nearest_bar = {}; if(nearest_bar < 0) { datetime time_0 = iTime(Symbol(), Period(), 0); datetime delta_time_start = time_0 - time_first_bar; datetime delta_time_stop = (0 - nearest_bar) * PeriodSeconds(); time_nearest_bar = time_first_bar + delta_time_start + delta_time_stop; } else time_nearest_bar = iTime(Symbol(), Period(), nearest_bar); return time_nearest_bar + time_remaining; } //+------------------------------------------------------------------+ double GetPriceFromY(int y_dist) { double price_per_pixel = (ChartGetDouble(0, CHART_PRICE_MAX) - ChartGetDouble(0, CHART_PRICE_MIN)) / ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS); double price_max = ChartGetDouble(0, CHART_PRICE_MAX); return price_max - price_per_pixel * y_dist; } //+------------------------------------------------------------------+
A script demonstrating the correctness of the functions' work. The essence of its work is that the generated X and Y coordinates are converted to time and price, and then back to X and Y. If the input X and Y coordinates differ from the output ones, it means that the functions have problems and the script will print the discrepancy. If all is well, the script does not print anything during the work, but at the very end it will print the result
void OnStart() { int generations_total = {}; int deviations_total = {}; uint time_start_script = GetTickCount(); while(!IsStopped()) { int x_input = 16383 - MathRand(); int y_input = 16383 - MathRand(); int first_bar_downloaded = TerminalInfoInteger(TERMINAL_MAXBARS) - 1; datetime time_first_bar_downloaded = iTime(Symbol(), Period(), first_bar_downloaded); double price_max_start = ChartGetDouble(0, CHART_PRICE_MAX); double price_min_start = ChartGetDouble(0, CHART_PRICE_MIN); int first_bar_start = (int)ChartGetInteger(0, CHART_FIRST_VISIBLE_BAR); int chart_scale_start = (int)ChartGetInteger(0, CHART_SCALE); int x_0 = GetXFromTime(time_first_bar_downloaded); int y_0 = GetYFromPrice(0); if(x_input < x_0) x_input = x_0; if(y_input > y_0) y_input = y_0; datetime time = GetTimeFromX(x_input); double price = GetPriceFromY(y_input); int x_output = GetXFromTime(time); int y_output = GetYFromPrice(price); double price_max_stop = ChartGetDouble(0, CHART_PRICE_MAX); double price_min_stop = ChartGetDouble(0, CHART_PRICE_MIN); int first_bar_stop = (int)ChartGetInteger(0, CHART_FIRST_VISIBLE_BAR); int chart_scale_stop = (int)ChartGetInteger(0, CHART_SCALE); if(price_max_start == price_max_stop && price_min_start == price_min_stop && first_bar_start == first_bar_stop && chart_scale_start == chart_scale_stop)//check that at the moment of coordinates transfer from one system to another and back, the scale and position of the chart do not change { ++generations_total; if(x_input != x_output || y_input != y_output) { ++deviations_total; Print("!!! deviation detected !!!"); Print("x_input= ", x_input, " y_input= ", y_input); Print("x_output= ", x_output, " y_output= ", y_output); } } } Print("Test ended up with ", deviations_total, " deviations"); if(deviations_total == 0) Print("Everything is Ok"); Print("generations_total= ", generations_total); int generations_rate = generations_total / ((double)(GetTickCount() - time_start_script) / 1000); Print("generations rate= ", generations_rate, " generations / sec"); } //+------------------------------------------------------------------+ int GetXFromTime(datetime time) { int pixels_per_bar = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS) / (int)ChartGetInteger(0, CHART_WIDTH_IN_BARS) + 1; double pixels_per_time = (double)pixels_per_bar / PeriodSeconds(); int first_bar = (int)ChartGetInteger(0, CHART_FIRST_VISIBLE_BAR); datetime time_first_bar = iTime(Symbol(), Period(), first_bar); datetime time_0 = iTime(Symbol(), Period(), 0); if(time <= time_0) { int nearest_bar = iBarShift(Symbol(), Period(), time); datetime time_nearest_bar = iTime(Symbol(), Period(), nearest_bar); datetime time_remaining = time - time_nearest_bar; time_remaining -= (int)MathFloor(time_remaining / PeriodSeconds()) * PeriodSeconds(); return (first_bar - nearest_bar) * pixels_per_bar + (int)MathRound(time_remaining * pixels_per_time); } else return first_bar * pixels_per_bar + (int)MathRound((time - time_0) * pixels_per_time); } //+------------------------------------------------------------------+ int GetYFromPrice(double price) { double price_max = ChartGetDouble(0, CHART_PRICE_MAX); double price_min = ChartGetDouble(0, CHART_PRICE_MIN); double pixels_per_price = ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS) / (price_max - price_min); return (int)MathRound((price_max - price) * pixels_per_price); } //+------------------------------------------------------------------+ datetime GetTimeFromX(int x_dist) { int first_bar = (int)ChartGetInteger(0, CHART_FIRST_VISIBLE_BAR); datetime time_first_bar = iTime(Symbol(), Period(), first_bar); int pixels_per_bar = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS) / (int)ChartGetInteger(0, CHART_WIDTH_IN_BARS) + 1; double time_per_pixel = (double)PeriodSeconds() / pixels_per_bar; datetime time_remaining = (int)(((double)x_dist / pixels_per_bar - (int)(x_dist / pixels_per_bar)) * pixels_per_bar * time_per_pixel); int nearest_bar = first_bar - (int)(x_dist / pixels_per_bar); datetime time_nearest_bar = {}; if(nearest_bar < 0) { datetime time_0 = iTime(Symbol(), Period(), 0); datetime delta_time_start = time_0 - time_first_bar; datetime delta_time_stop = (0 - nearest_bar) * PeriodSeconds(); time_nearest_bar = time_first_bar + delta_time_start + delta_time_stop; } else time_nearest_bar = iTime(Symbol(), Period(), nearest_bar); return time_nearest_bar + time_remaining; } //+------------------------------------------------------------------+ double GetPriceFromY(int y_dist) { double price_per_pixel = (ChartGetDouble(0, CHART_PRICE_MAX) - ChartGetDouble(0, CHART_PRICE_MIN)) / ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS); double price_max = ChartGetDouble(0, CHART_PRICE_MAX); return price_max - price_per_pixel * y_dist; } //+------------------------------------------------------------------+
Translated from Russian by MetaQuotes Ltd.
Original code: https://www.mql5.com/ru/code/48325
Developing Multicurrency Expert Advisor - source codes from the article series
Source codes written in the process of developing a library for creating multi-currency Expert Advisors combining multiple instances of different trading strategies.
AIS Extremum
The indicator allows you to estimate the probability that the price has reached its maximum or minimum.
DeltaFusionLite
DeltaFusion Lite is the simplified version of the DeltaFusionPro indicator for MT4. It calculates and displays Cumulative Delta and Net Delta, giving traders a clear view of buying and selling pressure within each candle. By analyzing the distribution of volume between bid and ask, it helps identify market sentiment shifts, potential reversals, and various types of divergences between price and volume.
Clickable button excample (close all positions)
An example of adding buttons for your advisors. In this example, a button has been implemented to close all active positions for all instruments. In addition to the button event processing functionality, methods for closing positions relative to the symbol name and counting the number of positions relative to the symbol name are also implemented.