Skip to content

Commit

Permalink
IndicatorTick: Implements tick fetching logic
Browse files Browse the repository at this point in the history
  • Loading branch information
kenorb committed Nov 9, 2021
1 parent ad83367 commit 28ff4d4
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 82 deletions.
30 changes: 29 additions & 1 deletion Indicator.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,34 @@ class Indicator : public IndicatorBase {
return median;
}

/**
* Returns price corresponding to indicator value for a given shift and mode.
*
* Can be useful for calculating trailing stops based on the indicator.
*
* @return
* Returns price value of the corresponding indicator values.
*/
template <typename T>
float GetValuePrice(int _shift = 0, int _mode = 0, ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL) {
float _price = 0;
if (GetIDataValueRange() != IDATA_RANGE_PRICE) {
_price = (float)GetPrice(_ap, _shift);
} else if (GetIDataValueRange() == IDATA_RANGE_PRICE) {
// When indicator values are the actual prices.
T _values[4];
if (!CopyValues(_values, 4, _shift, _mode)) {
// When values aren't valid, return 0.
return _price;
}
datetime _bar_time = GetBarTime(_shift);
float _value = 0;
BarOHLC _ohlc(_values, _bar_time);
_price = _ohlc.GetAppliedPrice(_ap);
}
return _price;
}

/**
* Returns currently selected data source doing validation.
*/
Expand Down Expand Up @@ -839,7 +867,7 @@ class Indicator : public IndicatorBase {
}
*/

ENUM_IDATA_VALUE_RANGE GetIDataValueRange() { return iparams.idvrange; }
// ENUM_IDATA_VALUE_RANGE GetIDataValueRange() { return iparams.idvrange; }

virtual void OnTick() {
Chart::OnTick();
Expand Down
207 changes: 176 additions & 31 deletions Indicator/IndicatorTick.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,43 +26,47 @@

// Includes.
#include "../IndicatorBase.h"
//#include "Array.mqh"
//#include "BufferStruct.mqh"
//#include "Chart.mqh"
//#include "DateTime.mqh"
//#include "DrawIndicator.mqh"
//#include "Indicator.define.h"
//#include "Indicator.enum.h"
//#include "Indicator.struct.cache.h"
//#include "Indicator.struct.h"
//#include "Indicator.struct.serialize.h"
//#include "Indicator.struct.signal.h"
//#include "IndicatorBase.h"
//#include "Math.h"
//#include "Object.mqh"
//#include "Refs.mqh"
//#include "Serializer.mqh"
//#include "SerializerCsv.mqh"
//#include "SerializerJson.mqh"
//#include "Storage/ValueStorage.h"
//#include "Storage/ValueStorage.indicator.h"
//#include "Storage/ValueStorage.native.h"

/**
* Class to deal with tick indicators.
*/
// template <typename TS>
template <typename TS>
class IndicatorTick : public IndicatorBase {
protected:
BufferStruct<IndicatorDataEntry> tickdata;
BufferStruct<IndicatorDataEntry> itdata;
TS itparams;

protected:
/* Protected methods */

/**
* Initialize class.
*
* Called on constructor.
*/
void Init() {
itdata.AddFlags(DICT_FLAG_FILL_HOLES_UNSORTED);
itdata.SetOverflowListener(IndicatorTickOverflowListener, 10);
}

public:
/* Special methods */

/**
* Class constructor.
*/
IndicatorTick() {}
IndicatorTick(const TS& _itparams, IndicatorBase* _indi_src = NULL, int _indi_mode = 0) {
itparams = _itparams;
if (_indi_src != NULL) {
SetDataSource(_indi_src, _indi_mode);
}
Init();
}
IndicatorTick(ENUM_INDICATOR_TYPE _itype, string _symbol, int _shift = 0, string _name = "") {
itparams.SetIndicatorType(_itype);
itparams.SetShift(_shift);
Init();
}

/* Virtual method implementations */

Expand All @@ -75,22 +79,163 @@ class IndicatorTick : public IndicatorBase {
* Returns IndicatorDataEntry struct filled with indicator values.
*/
IndicatorDataEntry GetEntry(int _timestamp = 0) {
IndicatorDataEntry _entry = tickdata.GetByKey(_timestamp);
ResetLastError();
IndicatorDataEntry _entry = itdata.GetByKey(_timestamp);
if (!_entry.IsValid() && !_entry.CheckFlag(INDI_ENTRY_FLAG_INSUFFICIENT_DATA)) {
_entry.Resize(itparams.GetMaxModes());
_entry.timestamp = _timestamp;
_entry.Resize(4);
//_entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry));
// for (int _mode = 0; _mode < (int)iparams.GetMaxModes(); _mode++) {
//_entry.values[_mode] = GetValue(_mode, _shift); / @todo
//}
for (int _mode = 0; _mode < (int)itparams.GetMaxModes(); _mode++) {
switch (itparams.GetDataValueType()) {
case TYPE_BOOL:
case TYPE_CHAR:
case TYPE_INT:
_entry.values[_mode] = GetValue<int>(_mode, _timestamp);
break;
case TYPE_LONG:
_entry.values[_mode] = GetValue<long>(_mode, _timestamp);
break;
case TYPE_UINT:
_entry.values[_mode] = GetValue<uint>(_mode, _timestamp);
break;
case TYPE_ULONG:
_entry.values[_mode] = GetValue<ulong>(_mode, _timestamp);
break;
case TYPE_DOUBLE:
_entry.values[_mode] = GetValue<double>(_mode, _timestamp);
break;
case TYPE_FLOAT:
_entry.values[_mode] = GetValue<float>(_mode, _timestamp);
break;
case TYPE_STRING:
case TYPE_UCHAR:
default:
SetUserError(ERR_INVALID_PARAMETER);
break;
}
}
GetEntryAlter(_entry, _timestamp);
_entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry));
if (_entry.IsValid()) {
// idata.Add(_entry, _bar_time);
itdata.Add(_entry, _timestamp);
istate.is_changed = false;
istate.is_ready = true;
} else {
_entry.AddFlags(INDI_ENTRY_FLAG_INSUFFICIENT_DATA);
}
}
if (_LastError != ERR_NO_ERROR) {
istate.is_ready = false;
ResetLastError();
}
return _entry;
}

/**
* Alters indicator's struct value.
*
* 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 _shift = -1) {
_entry.AddFlags(_entry.GetDataTypeFlags(itparams.GetDataValueType()));
};

/**
* Returns the indicator's entry value for the given shift and mode.
*
* @see: DataParamEntry.
*
* @return
* Returns DataParamEntry struct filled with a single value.
*/
virtual DataParamEntry GetEntryValue(int _shift = -1, int _mode = 0) {
IndicatorDataEntry _entry = GetEntry(_shift >= 0 ? _shift : itparams.GetShift());
DataParamEntry _value_entry;
return _value_entry;
}

/**
* Function should return true if resize can be made, or false to overwrite current slot.
*/
static bool IndicatorTickOverflowListener(ENUM_DICT_OVERFLOW_REASON _reason, int _size, int _num_conflicts) {
switch (_reason) {
case DICT_OVERFLOW_REASON_FULL:
// We allow resize if dictionary size is less than 86400 slots.
return _size < 86400;
case DICT_OVERFLOW_REASON_TOO_MANY_CONFLICTS:
default:
// When there is too many conflicts, we just reject doing resize, so first conflicting slot will be reused.
break;
}
return false;
}

/**
* Sets indicator data source.
*/
void SetDataSource(IndicatorBase* _indi, int _input_mode = 0) {
indi_src = _indi;
itparams.SetDataSource(-1, _input_mode);
}

/* Virtual methods */

/**
* Returns a tick struct with price values.
*
* @see: MqlTick.
*
* @return
* Returns MqlTick struct with prices of the symbol.
*/
virtual MqlTick GetTick(int _timestamp = 0) {
IndicatorDataEntry _entry = GetEntry(_timestamp);
MqlTick _tick;
_tick.time = (datetime)_entry.GetTime();
_tick.bid = _entry[0];
_tick.ask = _entry[1];
return _tick;
}

/**
* Checks if indicator entry is valid.
*
* @return
* Returns true if entry is valid (has valid values), otherwise false.
*/
virtual bool IsValidEntry(IndicatorDataEntry& _entry) {
bool _result = true;
_result &= _entry.timestamp > 0;
_result &= _entry.GetSize() > 0;
if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_REAL)) {
if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) {
_result &= !_entry.HasValue<double>(DBL_MAX);
_result &= !_entry.HasValue<double>(NULL);
} else {
_result &= !_entry.HasValue<float>(FLT_MAX);
_result &= !_entry.HasValue<float>(NULL);
}
} else {
if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_UNSIGNED)) {
if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) {
_result &= !_entry.HasValue<ulong>(ULONG_MAX);
_result &= !_entry.HasValue<ulong>(NULL);
} else {
_result &= !_entry.HasValue<uint>(UINT_MAX);
_result &= !_entry.HasValue<uint>(NULL);
}
} else {
if (_entry.CheckFlags(INDI_ENTRY_FLAG_IS_DOUBLED)) {
_result &= !_entry.HasValue<long>(LONG_MAX);
_result &= !_entry.HasValue<long>(NULL);
} else {
_result &= !_entry.HasValue<int>(INT_MAX);
_result &= !_entry.HasValue<int>(NULL);
}
}
}
return _result;
}
};

#endif
32 changes: 2 additions & 30 deletions IndicatorBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -695,8 +695,6 @@ class IndicatorBase : public Chart {
istate.is_changed = true;
}

virtual ENUM_IDATA_VALUE_RANGE GetIDataValueRange() = 0;

ValueStorage<double>* GetValueStorage(int _mode = 0) {
if (value_storages[_mode] == NULL) {
value_storages[_mode] = new IndicatorBufferValueStorage<double>(THIS_PTR, _mode);
Expand All @@ -713,34 +711,6 @@ class IndicatorBase : public Chart {

virtual IndicatorDataEntryValue GetMixedValue(int _mode = 0, int _shift = 0) = NULL;

/**
* Returns price corresponding to indicator value for a given shift and mode.
*
* Can be useful for calculating trailing stops based on the indicator.
*
* @return
* Returns price value of the corresponding indicator values.
*/
template <typename T>
float GetValuePrice(int _shift = 0, int _mode = 0, ENUM_APPLIED_PRICE _ap = PRICE_TYPICAL) {
float _price = 0;
if (GetIDataValueRange() != IDATA_RANGE_PRICE) {
_price = (float)GetPrice(_ap, _shift);
} else if (GetIDataValueRange() == IDATA_RANGE_PRICE) {
// When indicator values are the actual prices.
T _values[4];
if (!CopyValues(_values, 4, _shift, _mode)) {
// When values aren't valid, return 0.
return _price;
}
datetime _bar_time = GetBarTime(_shift);
float _value = 0;
BarOHLC _ohlc(_values, _bar_time);
_price = _ohlc.GetAppliedPrice(_ap);
}
return _price;
}

/**
* Returns values for a given shift.
*
Expand Down Expand Up @@ -798,6 +768,8 @@ class IndicatorBase : public Chart {
*/
virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _shift = -1) = NULL;

// virtual ENUM_IDATA_VALUE_RANGE GetIDataValueRange() = NULL;

/**
* Returns the indicator's entry value.
*/
Expand Down
Loading

0 comments on commit 28ff4d4

Please sign in to comment.