#ifndef PRICE_SPEEDOMETER_MQH #define PRICE_SPEEDOMETER_MQH #include "circular_buffer.mqh" class Price_speedometer { protected: Circular_buffer ticks; const int period_in_ticks; const long period_in_milliseconds; double speed_per_ticks; double directional_speed_per_ticks; double percent_per_ticks; double speed_per_milliseconds; double directional_speed_per_milliseconds; double percent_per_milliseconds; public: Price_speedometer(const int &_ticks_capacity, const int &_period_in_ticks, const long &_period_in_milliseconds) : ticks(_ticks_capacity), period_in_ticks(_period_in_ticks), period_in_milliseconds(_period_in_milliseconds), speed_per_ticks(0.0), directional_speed_per_ticks(0.0), percent_per_ticks(0.0), speed_per_milliseconds(0.0), directional_speed_per_milliseconds(0.0), percent_per_milliseconds(0.0) {} Price_speedometer(const Price_speedometer &_price_speedometer) : ticks(_price_speedometer.ticks), period_in_ticks(_price_speedometer.period_in_ticks), period_in_milliseconds(_price_speedometer.period_in_milliseconds), speed_per_ticks(_price_speedometer.speed_per_ticks), directional_speed_per_ticks( _price_speedometer.directional_speed_per_ticks), percent_per_ticks(_price_speedometer.percent_per_ticks), speed_per_milliseconds(_price_speedometer.speed_per_milliseconds), directional_speed_per_milliseconds( _price_speedometer.directional_speed_per_milliseconds), percent_per_milliseconds(_price_speedometer.percent_per_milliseconds) {} virtual ~Price_speedometer() {} public: Price_speedometer operator=(const Price_speedometer &_price_speedometer) { ticks = _price_speedometer.ticks; speed_per_ticks = _price_speedometer.speed_per_ticks; directional_speed_per_ticks = _price_speedometer.directional_speed_per_ticks; percent_per_ticks = _price_speedometer.percent_per_ticks; speed_per_milliseconds = _price_speedometer.speed_per_milliseconds; directional_speed_per_milliseconds = _price_speedometer.directional_speed_per_milliseconds; percent_per_milliseconds = _price_speedometer.percent_per_milliseconds; return *this; } protected: double calculate_price_speed(const int &_period_in_ticks) const { double price_change = 0.0; const int ticks_size = ticks.get_size(); int position_offset = (int)MathMin((double)(_period_in_ticks - 1), (double)(ticks_size - 1)); for (position_offset; position_offset > 0; --position_offset) { MqlTick previous_tick = {0ul, 0.0, 0.0, 0.0, 0ul, 0l, 0u, 0.0}; bool return_value = ticks.read(position_offset, previous_tick); if (!return_value || previous_tick.time_msc == 0l) { continue; } MqlTick next_tick = {0ul, 0.0, 0.0, 0.0, 0ul, 0l, 0u, 0.0}; return_value = ticks.read(position_offset - 1, next_tick); if (!return_value || next_tick.time_msc == 0l) { continue; } price_change += MathAbs(next_tick.last - previous_tick.last); } return price_change; } double calculate_directional_price_speed(const int &_period_in_ticks) const { if (_period_in_ticks < 2) { return 0.0; } const int ticks_size = ticks.get_size(); const int first_position_offset = (int)MathMin((double)(_period_in_ticks - 1), (double)(ticks_size - 1)); MqlTick first_tick = {0ul, 0.0, 0.0, 0.0, 0ul, 0l, 0u, 0.0}; bool return_value = ticks.read(first_position_offset, first_tick); if (!return_value || first_tick.time_msc == 0l) { return 0.0; } const int last_position_offset = 0; MqlTick last_tick = {0ul, 0.0, 0.0, 0.0, 0ul, 0l, 0u, 0.0}; return_value = ticks.read(last_position_offset, last_tick); if (!return_value || last_tick.time_msc == 0l) { return 0.0; } return last_tick.last - first_tick.last; } int find_position_offset(const long &_period_in_milliseconds) const { const int ticks_size = ticks.get_size(); if (ticks_size < 2) { return 0; } const int last_position_offset = 0; MqlTick last_tick = {0ul, 0.0, 0.0, 0.0, 0ul, 0l, 0u, 0.0}; const bool return_value = ticks.read(last_position_offset, last_tick); if (!return_value || last_tick.time_msc == 0l) { return 0; } int previous_position_offset = 1; MqlTick previous_tick = {0ul, 0.0, 0.0, 0.0, 0ul, 0l, 0u, 0.0}; while (ticks.read(previous_position_offset, previous_tick)) { if (previous_tick.time_msc < last_tick.time_msc - _period_in_milliseconds) { break; } ++previous_position_offset; } return previous_position_offset - 1; } public: double get_speed_per_ticks() const { return speed_per_ticks; } double get_directional_speed_per_ticks() const { return directional_speed_per_ticks; } double get_percent_per_ticks() const { return percent_per_ticks; } double get_speed_per_milliseconds() const { return speed_per_milliseconds; } double get_directional_speed_per_milliseconds() const { return directional_speed_per_milliseconds; } double get_percent_per_milliseconds() const { return percent_per_milliseconds; } void add_tick(const MqlTick &tick) { ticks.write(tick); return; } void calculate_price_speeds() { speed_per_ticks = calculate_price_speed(period_in_ticks); directional_speed_per_ticks = calculate_directional_price_speed(period_in_ticks); const int period_in_milliseconds_in_ticks = find_position_offset(period_in_milliseconds) + 1; speed_per_milliseconds = calculate_price_speed(period_in_milliseconds_in_ticks); directional_speed_per_milliseconds = calculate_directional_price_speed(period_in_milliseconds_in_ticks); return; } void calculate_percents() { percent_per_ticks = 0.0; if (speed_per_ticks != 0.0) { percent_per_ticks = directional_speed_per_ticks / speed_per_ticks * 100.0; } percent_per_milliseconds = 0.0; if (speed_per_milliseconds != 0.0) { percent_per_milliseconds = directional_speed_per_milliseconds / speed_per_milliseconds * 100.0; } return; } string get_comment() const { const int digits = _Digits; const string comment = "Per " + IntegerToString((long)period_in_ticks) + " ticks:\nSpeed: " + DoubleToString(speed_per_ticks, digits) + "\nDirectional speed: " + DoubleToString(directional_speed_per_ticks, digits) + "\nPercent: " + IntegerToString((long)percent_per_ticks) + "%\n\nPer " + IntegerToString(period_in_milliseconds) + " ms:\nSpeed: " + DoubleToString(speed_per_milliseconds, digits) + "\nDirectional speed: " + DoubleToString(directional_speed_per_milliseconds, digits) + "\nPercent: " + IntegerToString((long)percent_per_milliseconds) + "%"; return comment; } }; #endif