price_speedometer/price_speedometer.mqh
2026-05-19 23:26:31 +02:00

191 lines
6.9 KiB
MQL5

#ifndef PRICE_SPEEDOMETER_MQH
#define PRICE_SPEEDOMETER_MQH
#include "circular_buffer.mqh"
class Price_speedometer {
protected:
Circular_buffer<MqlTick> 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