Skip to content

Commit

Permalink
WIP. Shift parameters refactoring for Indicator/IndicatorData/other c…
Browse files Browse the repository at this point in the history
…lasses. Still some errors.
  • Loading branch information
nseam committed Oct 31, 2022
1 parent 6c4ac8d commit ecc90c4
Show file tree
Hide file tree
Showing 90 changed files with 492 additions and 465 deletions.
14 changes: 7 additions & 7 deletions ChartBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class ChartBase : public Dynamic {
/**
* Returns time of the bar with a given shift.
*/
virtual datetime GetBarTime(int _shift = 0) = 0;
virtual datetime GetBarTime(int _rel_shift = 0) = 0;

datetime GetLastBarTime() { return last_bar_time; }

Expand Down Expand Up @@ -170,14 +170,14 @@ class ChartBase : public Dynamic {
/**
* Gets OHLC price values.
*/
virtual BarOHLC GetOHLC(int _shift = 0) {
datetime _time = GetBarTime(_shift);
virtual BarOHLC GetOHLC(int _rel_shift = 0) {
datetime _time = GetBarTime(_rel_shift);
float _open = 0, _high = 0, _low = 0, _close = 0;
if (_time > 0) {
_open = (float)GetOpen(_shift);
_high = (float)GetHigh(_shift);
_low = (float)GetLow(_shift);
_close = (float)GetClose(_shift);
_open = (float)GetOpen(_rel_shift);
_high = (float)GetHigh(_rel_shift);
_low = (float)GetLow(_rel_shift);
_close = (float)GetClose(_rel_shift);
}
BarOHLC _ohlc(_open, _high, _low, _close, _time);
return _ohlc;
Expand Down
6 changes: 3 additions & 3 deletions ChartMt.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ class ChartMt : public ChartBase {
/**
* Returns time of the bar with a given shift.
*/
virtual datetime GetBarTime(int _shift = 0) override {
datetime _time = ::iTime(GetSymbol(), GetTf(), _shift);
virtual datetime GetBarTime(int _rel_shift = 0) override {
datetime _time = ::iTime(GetSymbol(), GetTf(), _rel_shift);

if (_LastError != ERR_NO_ERROR) {
Print("Error: ", _LastError, " while doing ::iTime() in ChartMt::GetBarTime(", _shift, ")");
Print("Error: ", _LastError, " while doing ::iTime() in ChartMt::GetBarTime(", _rel_shift, ")");
DebugBreak();
}

Expand Down
108 changes: 76 additions & 32 deletions Indicator/Details.md
Original file line number Diff line number Diff line change
@@ -1,59 +1,103 @@
# Explanation of shift parameters in Indicator/IndicatorData classes for following methods:
- `GetEntryValue(int _mode, int _abs_shift)`
#Explanation of shift parameters in Indicator / IndicatorData / other classes for following methods:
- `GetEntryValue(int _mode = 0, int _abs_shift = 0)`
- `GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift)`
- `GetValue(int _mode = 0, int _rel_shift = 0)`
- `GetEntry(int _rel_shift = 0)`
- `GetBarTime(int _rel_shift = 0)`

## GetEntryValue(int _mode, int _abs_shift) - overridable method

Method must be overriden in any new indicator and MUST NOT apply shift from `iparams.shift`/`iparams.GetShift()`! Shift 0 must always point to the value for the current tick.

Returns indicators's value for a given mode and absolute shift (the shift is directly passed to built-in methods such as iATR(), OnCalculate methods such as `iVIDyAOnIndicator()` and also to `iCustom()`).

For `OnCalculate()` methods such as iVIDyAOnIndicator(), the shift is passed to `return _cache.GetTailValue<double>(_mode, _shift);` so we can return value calculated in the past (or just retrieve **DBL_MAX** in case the value was not yet calculated).
Note that `OnCalculate()` methods uses single/multiple price buffers, e.g., applied price or OHLCs from base indicator.
For `OnCalculate()` methods such as iVIDyAOnIndicator(), the shift is passed to `return _cache.GetTailValue<double>(_mode, _shift);
` so we can return value calculated in the past(or just retrieve * *DBL_MAX * *in case the value was not yet calculated)
.Note that `OnCalculate()` methods uses single /
multiple price buffers,
e.g.,
applied price or OHLCs from base indicator.

In scenario of `VIDyA[shift = 2] <- Candle <- TickMt` call hierarchy looks like:
In scenario of `VIDyA[shift = 2] < -Candle < -TickMt` call hierarchy looks like :
```cpp - VIDyA::GetEntry(_rel_shift = 1) // Then per each mode:
- entry.values[_mode] =
Indicator::GetValue(_mode, _rel_shift = 1) - VIDyA::GetEntryValue(_mode, _abs_shift = iparams.shift + 1) -
VIDyA::iVIDyAOnIndicator(..., _mode, _shift = 3) then : // Shift is absolute.
-VIDyA::iVIDyAOnArray(..., _mode, _shift = 3) then
: // Shift is absolute.
return _cache.GetTailValue<double>(_mode, _shift = 3); // Shift is absolute.
``` Last line means that we will retrieve **VIDyA **value shifted by 3(2 from `iparams.shift` + 1 from `GetEntry()`)
.It is correct.

##GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) -
overridable method

Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`)
.

Method calls(seen in **MWMFI **, **CCI **, **Envelopes **, **Momentum **, **Pivot **)
:
```cpp
- VIDyA::GetEntry(_rel_shift = 1) // Then per each mode:
- entry.values[_mode] = Indicator::GetValue(_mode, _rel_shift = 1)
- VIDyA::GetEntryValue(_mode, _abs_shift = iparams.shift + 1)
- VIDyA::iVIDyAOnIndicator(..., _mode, _shift = 3) then: // Shift is absolute.
- VIDyA::iVIDyAOnArray(..., _mode, _shift = 3) then: // Shift is absolute.
return _cache.GetTailValue<double>(_mode, _shift = 3); // Shift is absolute.
-
GetValue<double>(_mode, _rel_shift) // GetValue<T>() takes relative shift.
```
Last line means that we will retrieve **VIDyA** value shifted by 3 (2 from `iparams.shift` + 1 from `GetEntry()`). It is correct.

## GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift) - overridable method
##GetValue(int _mode = 0, int _rel_shift = 0) -
non -
overridable method

Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`).
Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`)
.

Method calls (seen in **MWMFI**, **CCI**, **Envelopes**, **Momentum**, **Pivot**):
Method calls :
```cpp
- GetValue<double>(_mode, _rel_shift) // GetValue<T>() takes relative shift.
-
GetEntryValue(_mode, _abs_shift = iparams.shift + _rel_shift)
```
## GetValue(int _mode = 0, int _rel_shift = 0) - non-overridable method
##GetEntry(int _rel_shift = 0) -
overridable method
Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`).
Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`)
.
Method calls:
```cpp
- GetEntryValue(_mode, _abs_shift = iparams.shift + _rel_shift)
If you need to access entries from absolute shift,
use `GetEntryByAbsShift(int _abs_shift)`
.
Note that values accessed via index
operator `storage[rel_shift]` e.g.,
inside `OnCalculate()` methods like `double _o =
open[rel_shift = 4].Get()` will take relative shift
and retrieve open price shifted by(in this scenario) `4 + iparams.shift` set in base indicator :
```cpp - double _o =
open[_rel_shift = 4] - IndicatorBufferValueStorage::Fetch(_rel_shift = 4) -
IndicatorData::GetValue(_mode, _rel_shift = 4) -
Indicator::GetEntryValue(
_mode, _abs_shift = iparams.shift +
4) // As GetEntryValue() takes absolute shift, we add shift from iparams.shift.
- Indicator::GetEntry(_rel_shift =
_abs_shift -
iparams.shift)... // Converting absolute shift into relative one for GetEntry().
- ...[_mode]; // IndicatorDataEntry.values[_mode].Get(...);
```

## GetEntry(int _rel_shift = 0) - overridable method
## GetBarTime(int _rel_shift = 0)

Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`).

If you need to access entries from absolute shift, use `GetEntryByAbsShift(int _abs_shift)`.
## GetPrice(ENUM_APPLIED_PRICE _ap, int _rel_shift = 0)

Note that values accessed via index operator `storage[rel_shift]` e.g., inside `OnCalculate()` methods like `double _o = open[rel_shift = 4].Get()` will take relative shift and retrieve open price shifted by (in this scenario) `4 + iparams.shift` set in base indicator:
```cpp
- double _o = open[_rel_shift = 4]
- IndicatorBufferValueStorage::Fetch(_rel_shift = 4)
- IndicatorData::GetValue(_mode, _rel_shift = 4)
- Indicator::GetEntryValue(_mode, _abs_shift = iparams.shift + 4) // As GetEntryValue() takes absolute shift, we add shift from iparams.shift.
- Indicator::GetEntry(_rel_shift = _abs_shift - iparams.shift)... // Converting absolute shift into relative one for GetEntry().
- ...[_mode]; // IndicatorDataEntry.values[_mode].Get(...);
```
Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`).

## GetBars()

Number of returned bars is decremented by `IndicatorParams::shift` (read via `Indicator::iparams.shift`). Thus if there are **10** bars and *shift* is **8** then `GetBars()` will return **2**. That means that you can safely do `GetEntry()` for relative shifts **0** or **1**. There won't be any value in other relative shifts.

## HistoryValueStorage::Fetch(int _rel_shift)

Shift passed is relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`).

## Indi_\*::\*OnIndicator(..., _shift, [_shift1], [_shift2])

All shifts passed are relative to the shift from `IndicatorParams::shift` (read via `Indicator::iparams.shift`).
4 changes: 2 additions & 2 deletions Indicator/Indicator.define.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,5 +137,5 @@

// We're adding 1 because e.g., shift 1 means that we need two bars to exist in
// history in order to retrieve bar at shift 1.
#define INDI_REQUIRE_SHIFT_OR_RETURN(_indi, _shift, _ret) INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _shift + 1)
#define INDI_REQUIRE_SHIFT_OR_RETURN_EMPTY(_indi, _shift) INDI_REQUIRE_SHIFT_OR_RETURN(_indi, _shift, DBL_MAX)
#define INDI_REQUIRE_SHIFT_OR_RETURN(_indi, _rel_shift, _ret) INDI_REQUIRE_BARS_OR_RETURN_EMPTY(_indi, _rel_shift + 1)
#define INDI_REQUIRE_SHIFT_OR_RETURN_EMPTY(_indi, _rel_shift) INDI_REQUIRE_SHIFT_OR_RETURN(_indi, _rel_shift, DBL_MAX)
45 changes: 27 additions & 18 deletions Indicator/Indicator.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,18 @@ class Indicator : public IndicatorData {
draw.SetWindow(_window);
}

/* Converters */

/**
* Converts relative shift into absolute one.
*/
int ToAbsShift(int _rel_shift) override { return _rel_shift + iparams.shift; }

/**
* Converts absolute shift into relative one.
*/
int ToRelShift(int _abs_shift) override { return _abs_shift - iparams.shift; }

/* Buffer methods */

virtual string CacheKey() { return GetFullName(); }
Expand Down Expand Up @@ -575,11 +587,9 @@ class Indicator : public IndicatorData {
* @return
* Returns IndicatorDataEntry struct filled with indicator values.
*/
IndicatorDataEntry GetEntry(int _index = 0) override {
IndicatorDataEntry GetEntry(int _rel_shift = 0) override {
ResetLastError();
int _ishift = _index + iparams.GetShift();
long _bar_time;
_bar_time = GetBarTime(_ishift);
long _bar_time = GetBarTime(_rel_shift);

if (Get<ENUM_IDATA_SOURCE_TYPE>(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_IDSTYPE)) == IDATA_BUILTIN &&
(GetPossibleDataModes() & IDATA_BUILTIN) == 0) {
Expand All @@ -598,7 +608,7 @@ class Indicator : public IndicatorData {
if (_bar_time > 0 && !_entry.IsValid() && !_entry.CheckFlag(INDI_ENTRY_FLAG_INSUFFICIENT_DATA)) {
int _max_modes = Get<int>(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES));
_entry.Resize(_max_modes);
_entry.timestamp = GetBarTime(_ishift);
_entry.timestamp = GetBarTime(_rel_shift);
#ifndef __MQL4__
if (IndicatorData::Get<bool>(STRUCT_ENUM(IndicatorState, INDICATOR_STATE_PROP_IS_CHANGED))) {
// Resets the handle on any parameter changes.
Expand All @@ -611,22 +621,22 @@ class Indicator : public IndicatorData {
case TYPE_BOOL:
case TYPE_CHAR:
case TYPE_INT:
_entry.values[_mode] = GetValue<int>(_mode, _ishift);
_entry.values[_mode] = GetValue<int>(_mode, _rel_shift);
break;
case TYPE_LONG:
_entry.values[_mode] = GetValue<long>(_mode, _ishift);
_entry.values[_mode] = GetValue<long>(_mode, _rel_shift);
break;
case TYPE_UINT:
_entry.values[_mode] = GetValue<unsigned int>(_mode, _ishift);
_entry.values[_mode] = GetValue<unsigned int>(_mode, _rel_shift);
break;
case TYPE_ULONG:
_entry.values[_mode] = GetValue<unsigned long>(_mode, _ishift);
_entry.values[_mode] = GetValue<unsigned long>(_mode, _rel_shift);
break;
case TYPE_DOUBLE:
_entry.values[_mode] = GetValue<double>(_mode, _ishift);
_entry.values[_mode] = GetValue<double>(_mode, _rel_shift);
break;
case TYPE_FLOAT:
_entry.values[_mode] = GetValue<float>(_mode, _ishift);
_entry.values[_mode] = GetValue<float>(_mode, _rel_shift);
break;
case TYPE_STRING:
case TYPE_UCHAR:
Expand All @@ -637,12 +647,12 @@ class Indicator : public IndicatorData {

if (_LastError != ERR_SUCCESS) {
datetime _bar_dt = (datetime)_bar_time;
Print("Error: Code ", _LastError, " while trying to retrieve entry at shift ", _ishift, ", mode ", _mode,
", time ", _bar_dt);
Print("Error: Code ", _LastError, " while trying to retrieve entry at shift ", _rel_shift, " (absolute ",
ToAbsShift(_rel_shift), "), mode ", _mode, ", time ", _bar_dt);
DebugBreak();
}
}
GetEntryAlter(_entry, _ishift);
GetEntryAlter(_entry, _rel_shift);
_entry.SetFlag(INDI_ENTRY_FLAG_IS_VALID, IsValidEntry(_entry));
if (_entry.IsValid()) {
idata.Add(_entry, _bar_time);
Expand All @@ -665,7 +675,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 _shift) {
virtual void GetEntryAlter(IndicatorDataEntry& _entry, int _rel_shift) {
ENUM_DATATYPE _dtype = Get<ENUM_DATATYPE>(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_DTYPE));
_entry.AddFlags(_entry.GetDataTypeFlags(_dtype));
};
Expand All @@ -678,9 +688,8 @@ class Indicator : public IndicatorData {
* @return
* Returns DataParamEntry struct filled with a single value.
*/
IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _shift = 0) override {
int _ishift = _shift + iparams.GetShift();
return GetEntry(_ishift)[_mode];
IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) override {
return GetEntry(ToRelShift(_abs_shift))[_mode];
}

/* Virtual methods */
Expand Down
10 changes: 5 additions & 5 deletions Indicator/IndicatorCandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,12 @@ class IndicatorCandle : public Indicator<TS> {
int GetBarIndex() override { return history.GetCurrentIndex(); }

/**
* Returns the number of bars on the chart.
* Returns the number of bars on the chart decremented by iparams.shift.
*/
int GetBars() override {
// Will return number of bars prepended and appended to the history,
// even if those bars were cleaned up because of history's candle limit.
return (int)history.GetPeakSize();
return (int)history.GetPeakSize() - iparams.shift;
}

/**
Expand Down Expand Up @@ -182,7 +182,7 @@ class IndicatorCandle : public Indicator<TS> {
/**
* Returns time of the bar for a given shift.
*/
virtual datetime GetBarTime(int _shift = 0) { return history.GetItemTimeByShift(_shift); }
virtual datetime GetBarTime(int _rel_shift = 0) { return history.GetItemTimeByShift(_rel_shift); }

/**
* Traverses source indicators' hierarchy and tries to find OHLC-featured
Expand All @@ -196,11 +196,11 @@ class IndicatorCandle : public Indicator<TS> {
/**
* Gets OHLC price values.
*/
BarOHLC GetOHLC(int _shift = 0) override {
BarOHLC GetOHLC(int _rel_shift = 0) override {
BarOHLC _bar;
CandleOCTOHLC<double> _candle;

if (history.TryGetItemByShift(_shift, _candle)) {
if (history.TryGetItemByShift(ToAbsShift(_rel_shift), _candle)) {
_bar = BarOHLC(_candle.open, _candle.high, _candle.low, _candle.close, _candle.start_time);
}

Expand Down
Loading

0 comments on commit ecc90c4

Please sign in to comment.