Skip to content

Commit

Permalink
WIP. Using Indi_TickProvider to provide tick for Candle indicator and…
Browse files Browse the repository at this point in the history
… finally, for RSI or other one.
  • Loading branch information
nseam committed Feb 23, 2023
1 parent a36e135 commit ccade19
Show file tree
Hide file tree
Showing 31 changed files with 377 additions and 139 deletions.
8 changes: 6 additions & 2 deletions Buffer/BufferTick.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
#include "../Storage/IValueStorage.h"
#include "../Tick/Tick.struct.h"

// Forward declarations.
template <typename TV>
class BufferTick;

// TV = Type of price stored by BufferTick. RV = Type of property to be retrieved from BufferTick.
template <typename TV, typename RV>
class BufferTickValueStorage : ValueStorage<TV> {
Expand Down Expand Up @@ -71,7 +75,7 @@ class BufferTickValueStorage : ValueStorage<TV> {
/**
* Returns number of values available to fetch (size of the values buffer).
*/
int Size() override { return (int)buffer_tick.Size(); }
int Size() override { return (int)THIS_ATTR buffer_tick.Size(); }
};

/**
Expand Down Expand Up @@ -109,7 +113,7 @@ class BufferTick : public BufferStruct<TickAB<TV>> {
_vs_spread = NULL;
_vs_volume = NULL;
_vs_tick_volume = NULL;
SetOverflowListener(BufferStructOverflowListener, 10);
THIS_ATTR SetOverflowListener(BufferStructOverflowListener, 10);
}

public:
Expand Down
53 changes: 30 additions & 23 deletions Candle.struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ struct CandleOCTOHLC : CandleOHLC<T> {
// Struct constructor.
CandleOCTOHLC(T _open = 0, T _high = 0, T _low = 0, T _close = 0, int _start_time = -1, int _length = 0,
long _open_timestamp_ms = -1, long _close_timestamp_ms = -1, int _volume = 0)
: CandleOHLC(_open, _high, _low, _close),
: CandleOHLC<T>(_open, _high, _low, _close),
is_complete(true),
start_time(_start_time),
length(_length),
Expand All @@ -254,6 +254,11 @@ struct CandleOCTOHLC : CandleOHLC<T> {
// Struct constructor.
CandleOCTOHLC(const CandleOCTOHLC &r) { THIS_REF = r; }

// Virtual destructor. Required because of Emscripted warning, despite structure has no virtual methods:
// warning: destructor called on non-final 'CandleOCTOHLC<double>' that has virtual functions but non-virtual
// destructor [-Wdelete-non-abstract-non-virtual-dtor]
virtual ~CandleOCTOHLC() {}

/**
* Initializes candle with a given start time, lenght in seconds, first tick's timestamp and its price.
*/
Expand All @@ -264,7 +269,7 @@ struct CandleOCTOHLC : CandleOHLC<T> {
open_timestamp_ms = _timestamp_ms;
close_timestamp_ms = _timestamp_ms;
volume = _price != 0 ? 1 : 0;
open = high = low = close = _price;
THIS_ATTR open = THIS_ATTR high = THIS_ATTR low = THIS_ATTR close = _price;
}

/**
Expand All @@ -280,19 +285,19 @@ struct CandleOCTOHLC : CandleOHLC<T> {

if (_is_init || _timestamp_ms < open_timestamp_ms) {
open_timestamp_ms = _timestamp_ms;
open = _price;
THIS_ATTR open = _price;
}
if (_is_init || _timestamp_ms > close_timestamp_ms) {
close_timestamp_ms = _timestamp_ms;
close = _price;
THIS_ATTR close = _price;
}

if (_is_init) {
high = _price;
low = _price;
THIS_ATTR high = _price;
THIS_ATTR low = _price;
} else {
high = MathMax(high, _price);
low = MathMin(low, _price);
THIS_ATTR high = MathMax(THIS_ATTR high, _price);
THIS_ATTR low = MathMin(THIS_ATTR low, _price);
}
// Increasing candle's volume.
++volume;
Expand Down Expand Up @@ -337,8 +342,8 @@ struct CandleOCTOHLC : CandleOHLC<T> {
* Returns text representation of candle.
*/
string ToString() {
return StringFormat("%.5f %.5f %.5f %.5f [%s] @ %s - %s", open, high, low, close,
is_complete ? "Complete" : "Incomplete",
return StringFormat("%.5f %.5f %.5f %.5f [%s] @ %s - %s", THIS_ATTR open, THIS_ATTR high, THIS_ATTR low,
THIS_ATTR close, is_complete ? "Complete" : "Incomplete",
TimeToString(open_timestamp_ms, TIME_DATE | TIME_MINUTES | TIME_SECONDS),
TimeToString(close_timestamp_ms, TIME_DATE | TIME_MINUTES | TIME_SECONDS));
}
Expand All @@ -352,18 +357,20 @@ struct CandleTOHLC : CandleOHLC<T> {
datetime time;
// Struct constructors.
CandleTOHLC(datetime _time = 0, T _open = 0, T _high = 0, T _low = 0, T _close = 0)
: time(_time), CandleOHLC(_open, _high, _low, _close) {}
: time(_time), CandleOHLC<T>(_open, _high, _low, _close) {}
// Getters.
datetime GetTime() { return time; }
// Serializers.
SerializerNodeType Serialize(Serializer &s);
// Converters.
string ToCSV() { return StringFormat("%d,%g,%g,%g,%g", time, open, high, low, close); }
string ToCSV() {
return StringFormat("%d,%g,%g,%g,%g", time, THIS_ATTR open, THIS_ATTR high, THIS_ATTR low, THIS_ATTR close);
}
};

/* Method to serialize CandleEntry structure. */
template <typename T>
SerializerNodeType CandleOHLC::Serialize(Serializer &s) {
SerializerNodeType CandleOHLC<T>::Serialize(Serializer &s) {
// s.Pass(THIS_REF, "time", TimeToString(time));
s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC);
Expand All @@ -374,25 +381,25 @@ SerializerNodeType CandleOHLC::Serialize(Serializer &s) {

/* Method to serialize CandleEntry structure. */
template <typename T>
SerializerNodeType CandleTOHLC::Serialize(Serializer &s) {
SerializerNodeType CandleTOHLC<T>::Serialize(Serializer &s) {
s.Pass(THIS_REF, "time", time);
s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "low", low, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "close", close, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "open", THIS_ATTR open, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "high", THIS_ATTR high, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "low", THIS_ATTR low, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "close", THIS_ATTR close, SERIALIZER_FIELD_FLAG_DYNAMIC);
return SerializerNodeObject;
}

/* Method to serialize CandleEntry structure. */
template <typename T>
SerializerNodeType CandleOCTOHLC::Serialize(Serializer &s) {
SerializerNodeType CandleOCTOHLC<T>::Serialize(Serializer &s) {
s.Pass(THIS_REF, "is_complete", is_complete, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "open_timestamp_ms", open_timestamp_ms, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "close_timestamp_ms", close_timestamp_ms, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "open", open, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "high", high, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "low", low, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "close", close, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "open", THIS_ATTR open, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "high", THIS_ATTR high, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "low", THIS_ATTR low, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "close", THIS_ATTR close, SERIALIZER_FIELD_FLAG_DYNAMIC);
s.Pass(THIS_REF, "volume", volume, SERIALIZER_FIELD_FLAG_DYNAMIC);
return SerializerNodeObject;
}
2 changes: 1 addition & 1 deletion DictObject.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class DictObject : public DictBase<K, V> {
*/
V* GetByKey(const K _key) {
unsigned int position;
DictSlot<K, V>* slot = GetSlotByKey(this PTR_DEREF _DictSlots_ref, _key, position);
DictSlot<K, V>* slot = THIS_ATTR GetSlotByKey(this PTR_DEREF _DictSlots_ref, _key, position);

if (!slot) return NULL;

Expand Down
65 changes: 35 additions & 30 deletions Indicator/Indicator.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,6 @@ struct IndicatorParams;
#include "Indicator.struct.serialize.h"
#include "IndicatorData.h"

#ifndef __MQL4__
// Defines global functions (for MQL4 backward compatibility).
bool IndicatorBuffers(int _count) { return Indicator<IndicatorParams>::SetIndicatorBuffers(_count); }
int IndicatorCounted(int _value = 0) {
static int prev_calculated = 0;
// https://docs.mql4.com/customind/indicatorcounted
prev_calculated = _value > 0 ? _value : prev_calculated;
return prev_calculated;
}
#endif

#ifdef __MQL5__
// Defines global functions (for MQL5 forward compatibility).
template <typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I,
Expand Down Expand Up @@ -163,7 +152,8 @@ class Indicator : public IndicatorData {
int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1);

for (int shift = start_bar; shift <= last_bar; ++shift) {
double value = GetEntry(shift).GetMax<T>(GetModeCount());
IndicatorDataEntry _entry = GetEntry(shift);
double value = _entry.GetMax<T>(GetModeCount());
if (value > max) {
max = value;
max_idx = shift;
Expand All @@ -183,7 +173,8 @@ class Indicator : public IndicatorData {
int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1);

for (int shift = start_bar; shift <= last_bar; ++shift) {
double value = GetEntry(shift).GetMin<T>(GetModeCount());
IndicatorDataEntry _entry = GetEntry(shift);
double value = _entry.GetMin<T>(GetModeCount());
if (value < min) {
min = value;
min_idx = shift;
Expand Down Expand Up @@ -226,7 +217,7 @@ class Indicator : public IndicatorData {

/* Buffer methods */

virtual string CacheKey() { return GetFullName(); }
string CacheKey() override { return GetFullName(); }

/**
* Initializes a cached proxy between i*OnArray() methods and OnCalculate()
Expand Down Expand Up @@ -358,9 +349,8 @@ class Indicator : public IndicatorData {
*
* When indicator values are not valid, returns empty signals.
*/
IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) {
bool _is_valid = true;
IndicatorDataEntry _data[];
IndicatorSignal GetSignals(int _count = 3, int _shift = 0, int _mode1 = 0, int _mode2 = 0) override {
ARRAY(IndicatorDataEntry, _data);
if (!CopyEntries(_data, _count, _shift)) {
// Some copied data is invalid, so returns empty signals.
IndicatorSignal _signals(0);
Expand All @@ -381,7 +371,7 @@ class Indicator : public IndicatorData {
/**
* Get more descriptive name of the indicator.
*/
string GetDescriptiveName() {
string GetDescriptiveName() override {
int _max_modes = Get<int>(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES));
string name = iparams.name + " (";

Expand All @@ -393,8 +383,10 @@ class Indicator : public IndicatorData {
name += "custom, ";
break;
case IDATA_INDICATOR:
name += "over " + GetDataSource().GetDescriptiveName() + ", ";
name += "over " + GetDataSource() PTR_DEREF GetDescriptiveName() + ", ";
break;
default:
name += "unknown ";
}

name += IntegerToString(_max_modes) + (_max_modes == 1 ? " mode" : " modes");
Expand All @@ -407,14 +399,14 @@ class Indicator : public IndicatorData {
/**
* Sets name of the indicator.
*/
void SetName(string _name) { iparams.SetName(_name); }
void SetName(string _name) override { iparams.SetName(_name); }

/**
* Sets indicator's handle.
*
* Note: Not supported in MT4.
*/
void SetHandle(int _handle) {
void SetHandle(int _handle) override {
istate.handle = _handle;
istate.is_changed = true;
}
Expand All @@ -436,7 +428,7 @@ class Indicator : public IndicatorData {
* @return
* Returns true when the condition is met.
*/
bool CheckCondition(ENUM_INDICATOR_CONDITION _cond, DataParamEntry& _args[]) {
bool CheckCondition(ENUM_INDICATOR_CONDITION _cond, ARRAY_REF(DataParamEntry, _args)) {
switch (_cond) {
case INDI_COND_ENTRY_IS_MAX:
// @todo: Add arguments, check if the entry value is max.
Expand All @@ -461,7 +453,8 @@ class Indicator : public IndicatorData {
// Indicator entry value is lesser than median.
return false;
default:
GetLogger().Error(StringFormat("Invalid indicator condition: %s!", EnumToString(_cond), __FUNCTION_LINE__));
GetLogger() PTR_DEREF Error(
StringFormat("Invalid indicator condition: %s at %s!", EnumToString(_cond), __FUNCTION_LINE__));
return false;
}
}
Expand All @@ -480,18 +473,19 @@ class Indicator : public IndicatorData {
* @return
* Returns true when the action has been executed successfully.
*/
virtual bool ExecuteAction(ENUM_INDICATOR_ACTION _action, DataParamEntry& _args[]) {
virtual bool ExecuteAction(ENUM_INDICATOR_ACTION _action, ARRAY_REF(DataParamEntry, _args)) {
bool _result = true;
long _arg1 = ArraySize(_args) > 0 ? DataParamEntry::ToInteger(_args[0]) : WRONG_VALUE;
switch (_action) {
case INDI_ACTION_CLEAR_CACHE:
_arg1 = _arg1 > 0 ? _arg1 : TimeCurrent();
_arg1 = _arg1 != 0 ? _arg1 : (long)TimeCurrent();
Print("Action not yet implemented!");
DebugBreak();
// idata.Clear(_arg1);
return true;
default:
GetLogger().Error(StringFormat("Invalid Indicator action: %s!", EnumToString(_action), __FUNCTION_LINE__));
GetLogger() PTR_DEREF Error(StringFormat("Invalid Indicator action: %s at %s!", C_STR(EnumToString(_action)),
C_STR(__FUNCTION_LINE__)));
return false;
}
return _result;
Expand Down Expand Up @@ -537,7 +531,7 @@ class Indicator : public IndicatorData {
/**
* Whether we can and have to select mode when specifying data source.
*/
virtual bool IsDataSourceModeSelectable() { return true; }
virtual bool IsDataSourceModeSelectable() override { return true; }

/**
* Checks if indicator entry is valid.
Expand Down Expand Up @@ -652,7 +646,7 @@ class Indicator : public IndicatorData {
DebugBreak();
}
}
GetEntryAlter(_entry, _rel_shift);
THIS_ATTR GetEntryAlter(_entry, _rel_shift);
_entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry));
if (_entry.IsValid()) {
idata.Add(_entry, _bar_time);
Expand All @@ -675,7 +669,7 @@ class Indicator : public IndicatorData {
* This method allows user to modify the struct entry before it's added to cache.
* This method is called on GetEntry() right after values are set.
*/
virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _rel_shift) {
void GetEntryAlter(IndicatorDataEntry& _entry, int _rel_shift) override {
ENUM_DATATYPE _dtype = Get<ENUM_DATATYPE>(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DTYPE));
_entry.AddFlags(_entry.GetDataTypeFlags(_dtype));
};
Expand All @@ -702,10 +696,21 @@ class Indicator : public IndicatorData {
/**
* Update indicator.
*/
virtual bool Update() {
virtual bool Update() override {
// @todo
return false;
};
};

#ifndef __MQL4__
// Defines global functions (for MQL4 backward compatibility).
bool IndicatorBuffers(int _count) { return Indicator<IndicatorParams>::SetIndicatorBuffers(_count); }
int IndicatorCounted(int _value = 0) {
static int prev_calculated = 0;
// https://docs.mql4.com/customind/indicatorcounted
prev_calculated = _value > 0 ? _value : prev_calculated;
return prev_calculated;
}
#endif

#endif
Loading

0 comments on commit ccade19

Please sign in to comment.