Skip to content

Commit

Permalink
Merge pull request #754 from nseam/v3.007-dev-new-mt5-code-in-mt4-ind…
Browse files Browse the repository at this point in the history
…icator-support

V3.007 dev new mt5 code in mt4 indicator support
  • Loading branch information
kenorb committed May 20, 2024
2 parents fd565d1 + 42ccf6a commit 7a9c15c
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 5 deletions.
7 changes: 7 additions & 0 deletions Indicator/IndicatorData.h
Original file line number Diff line number Diff line change
Expand Up @@ -1438,6 +1438,13 @@ class IndicatorData : public IndicatorBase {
return false;
}

/**
* Fetches historic ticks for a given index (absolute shift) range.
*/
virtual bool FetchHistoryByIndexRange(int _index_from, int _index_to, ARRAY_REF(TickTAB<double>, _out_ticks)) {
return false;
}

/**
* Fetches historic ticks for a given start time and minimum number of tick to retrieve.
*/
Expand Down
5 changes: 5 additions & 0 deletions Indicator/IndicatorTf.provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,14 @@ class ItemsHistoryTfCandleProvider : public ItemsHistoryCandleProvider<TV> {
long _candle_length_ms = (long)spc * 1000;
long _ticks_to_ms = _ticks_from_ms + _candle_length_ms - 1;

// We will try to fetch history by two methods.
// 1. By time range if IndicatorTick supports that way.
if (!_indi_tick PTR_DEREF FetchHistoryByTimeRange(_ticks_from_ms, _ticks_to_ms, _ticks)) {
// 2. By number of bars if IndicatorTick supports that way.
// if (!_indi_tick PTR_DEREF FetchHistoryByIndexRange(_ticks_from_index, _ticks_to_ms, _ticks))) {
// There is no more ticks in the history, giving up.
break;
//}
}

if (ArraySize(_ticks) > 0) {
Expand Down
46 changes: 44 additions & 2 deletions IndicatorLegacy.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,67 @@

#ifdef __MQL4__

#include <EA31337-classes/IndicatorBase.h>
#include <EA31337-classes/Indicator/IndicatorData.h>
#include <EA31337-classes/Platform.h>
#include <EA31337-classes/Std.h>
#include <EA31337-classes/Storage/ObjectsCache.h>
#include <EA31337-classes/Util.h>

#ifndef INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER
#define INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER
#endif

#ifndef INDICATOR_LEGACY_VERSION_RELEASE_BUFFER
#define INDICATOR_LEGACY_VERSION_RELEASE_BUFFER
#endif

#ifdef INDICATOR_LEGACY_VERSION_MT5

#ifndef INDICATOR_LEGACY_VERSION_SHORT

/**
* Replacement for future OnCalculate(). Currently not used, but could be handy in the future.
* Replacement for future OHLC-based OnCalculate().
*/
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[]) {
// We need to call Platform::Tick() and maybe also IndicatorData::EmitHistory() before.
Platform::OnCalculate(rates_total, prev_calculated);

INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER;

int _num_calculated =
OnCalculateMT5(rates_total, prev_calculated, time, open, high, low, close, tick_volume, volume, spread);

INDICATOR_LEGACY_VERSION_RELEASE_BUFFER;

return _num_calculated;
}

#else

/**
* Replacement for future price-based OnCalculate().
*/
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double& price[]) {
// We need to call Platform::Tick() and maybe also IndicatorData::EmitHistory() before.
Platform::OnCalculate(rates_total, prev_calculated);

INDICATOR_LEGACY_VERSION_ACQUIRE_BUFFER;

// NOTE: If compiler sees an error here about parameter conversion then you
// probably must do:
// #define INDICATOR_LEGACY_VERSION_SHORT
// before including IndicatorLegacy.h
int _num_calculated = OnCalculateMT5(rates_total, prev_calculated, begin, price);

INDICATOR_LEGACY_VERSION_RELEASE_BUFFER;

return _num_calculated;
}

#endif

#define OnCalculate OnCalculateMT5

/**
Expand Down
76 changes: 73 additions & 3 deletions Indicators/Tick/Indi_TickMt.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ struct Indi_TickMtParams : IndicatorParams {

// MT platform's tick-based indicator.
class Indi_TickMt : public IndicatorTick<Indi_TickMtParams, double, ItemsHistoryTickProvider<double>> {
// Caching _to_ms in FetchHistoryByTimeRange() in order to start from last
// shift and don't loop over the same bars again.
long _cache_fetch_history_shift_to_ms;
// Shift to start with if given _to_ms is less that cached _cache_fetch_history_shift_to_ms.
long _cache_fetch_history_shift_shift;

public:
Indi_TickMt(Indi_TickMtParams &_p, ENUM_IDATA_SOURCE_TYPE _idstype = IDATA_BUILTIN, IndicatorData *_indi_src = NULL,
int _indi_src_mode = 0)
Expand All @@ -61,7 +67,10 @@ class Indi_TickMt : public IndicatorTick<Indi_TickMtParams, double, ItemsHistory
/**
* Initializes the class.
*/
void Init() {}
void Init() {
_cache_fetch_history_shift_to_ms = 0;
_cache_fetch_history_shift_shift = 0;
}

string GetName() override { return "Indi_TickMt"; }

Expand Down Expand Up @@ -121,11 +130,60 @@ class Indi_TickMt : public IndicatorTick<Indi_TickMtParams, double, ItemsHistory
virtual bool FetchHistoryByTimeRange(long _from_ms, long _to_ms, ARRAY_REF(TickTAB<double>, _out_ticks)) {
ArrayResize(_out_ticks, 0);

#ifdef __MQL4__
// Searching from current bar to older ones.
int _shift;

if (_to_ms <= _cache_fetch_history_shift_to_ms) {
_shift = _cache_fetch_history_shift_shift;
} else {
_shift = 0;
}

string _symbol = GetSymbol();

while (true) {
double _time = (double)iTime(_symbol, PERIOD_M1, _shift);

if (_time == 0) {
// Invalid time.
break;
}

long _time_ms = (long)_time * 1000;

if (_time_ms > _to_ms) {
// No yet get into valid time range.
++_shift;
continue;
}

if (_time_ms < _from_ms) {
// No more ticks.
break;
}

TickTAB<double> _tick_o(_time_ms, iOpen(_Symbol, PERIOD_M1, _shift));
TickTAB<double> _tick_h(_time_ms, iHigh(_Symbol, PERIOD_M1, _shift));
TickTAB<double> _tick_l(_time_ms, iLow(_Symbol, PERIOD_M1, _shift));
TickTAB<double> _tick_c(_time_ms, iClose(_Symbol, PERIOD_M1, _shift));
ArrayPushObject(_out_ticks, _tick_o);
ArrayPushObject(_out_ticks, _tick_h);
ArrayPushObject(_out_ticks, _tick_l);
ArrayPushObject(_out_ticks, _tick_c);
++_shift;
}

if (_shift != -1) {
_cache_fetch_history_shift_to_ms = _to_ms;
_cache_fetch_history_shift_shift = _shift;
}

return ArraySize(_out_ticks) != 0;
#else
static MqlTick _tmp_ticks[];
ArrayResize(_tmp_ticks, 0);

// There's no history in MQL4.
#ifndef __MQL4__
int _tries = 10;

while (_tries > 0) {
Expand Down Expand Up @@ -154,6 +212,18 @@ class Indi_TickMt : public IndicatorTick<Indi_TickMtParams, double, ItemsHistory
return false;
}

/**
* Fetches historic ticks for a given index (absolute shift) range.
*/
virtual bool FetchHistoryByIndexRange(int _index_from, int _index_to, ARRAY_REF(TickTAB<double>, _out_ticks)) {
return false;
}

/**
* Sends historic entries to listening indicators. May be overriden.
*/
virtual void EmitHistory() {}

void OnTick(int _global_tick_index) override {
#ifdef __MQL4__
// Refreshes Ask/Bid constants.
Expand Down
42 changes: 42 additions & 0 deletions Platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ class Platform {
// Whether to clear passed periods on consecutive Platform::UpdateTime().
static bool time_clear_flags;

// Whether history for all the indicators was emitted.
static bool emitted_history;

// List of added indicators.
static DictStruct<long, Ref<IndicatorData>> indis;

Expand Down Expand Up @@ -108,6 +111,38 @@ class Platform {
++global_tick_index;
}

/**
* Called by indicators' OnCalculate() method in order to prepare history via
* IndicatorData::EmitHistory() and to call Tick() for each OnCalculate()
* call so Tick indicator can emit new tick and Candle indicator can update
* or add new candle data to be used by all indicators added to the platform
* via Platform::Add...().
*/
static void OnCalculate(const int rates_total, const int prev_calculated) {
if (!emitted_history) {
for (DictStructIterator<long, Ref<IndicatorData>> _iter = indis.Begin(); _iter.IsValid(); ++_iter) {
EmitHistory(_iter.Value().Ptr());
}
emitted_history = true;
}

// We're ready for a tick.
Tick();
}

/**
* Emits history for parent indicators in hierarchy and then for the indicator itself.
*/
static void EmitHistory(IndicatorData *_indi) {
IndicatorData *_parent = _indi PTR_DEREF GetDataSource(false);

if (_parent != nullptr) {
EmitHistory(_parent);
}

_indi PTR_DEREF EmitHistory();
}

/**
* Returns dictionary of added indicators (keyed by unique id).
*/
Expand Down Expand Up @@ -319,6 +354,7 @@ DateTime Platform::time = 0;
unsigned int Platform::time_flags = 0;
bool Platform::time_clear_flags = true;
int Platform::global_tick_index = 0;
bool Platform::emitted_history = false;
DictStruct<long, Ref<IndicatorData>> Platform::indis;
DictStruct<long, Ref<IndicatorData>> Platform::indis_dflt;

Expand Down Expand Up @@ -353,3 +389,9 @@ DictStruct<long, Ref<IndicatorData>> Platform::indis_dflt;
}

#define TEST_INDICATOR_DEFAULT_BINDINGS(C) TEST_INDICATOR_DEFAULT_BINDINGS_PARAMS(C, )

// Auto-initializer for Platform class.
class PlatformAutoInitializer {
public:
PlatformAutoInitializer() { Platform::Init(); }
} _platform_auto_initializer;

0 comments on commit 7a9c15c

Please sign in to comment.