Skip to content

Commit

Permalink
WIP. Added explanation of shift parameters in Indicator/IndicatorData…
Browse files Browse the repository at this point in the history
… classes for following methods: GetEntryValue/GetEntryAlter/GetValue/GetEntry().
  • Loading branch information
nseam committed Oct 28, 2022
1 parent 0e9563e commit 6c4ac8d
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 3 deletions.
59 changes: 59 additions & 0 deletions Indicator/Details.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Explanation of shift parameters in Indicator/IndicatorData classes for following methods:
- `GetEntryValue(int _mode, int _abs_shift)`
- `GetEntryAlter(IndicatorDataEntry &_entry, int _rel_shift)`
- `GetValue(int _mode = 0, int _rel_shift = 0)`
- `GetEntry(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.

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
- GetValue<double>(_mode, _rel_shift) // GetValue<T>() takes relative shift.
```

## 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`).

Method calls:
```cpp
- GetEntryValue(_mode, _abs_shift = iparams.shift + _rel_shift)
```

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

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)`.

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(...);
```
2 changes: 1 addition & 1 deletion Indicator/IndicatorData.h
Original file line number Diff line number Diff line change
Expand Up @@ -1126,7 +1126,7 @@ class IndicatorData : public IndicatorBase {
if (_indi == nullptr) _indi = GetTick(false);

if (_indi == nullptr) {
Print("Error: Neither candle nor tick indicator exists in the hierarch of ", GetFullName(), "!");
Print("Error: Neither candle nor tick indicator exists in the hierarchy of ", GetFullName(), "!");
DebugBreak();
return (datetime)0;
}
Expand Down
2 changes: 2 additions & 0 deletions Indicator/IndicatorData.struct.cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,9 @@ class IndicatorCalculateCache : public Dynamic {
}

/**
* Retrieves _shift-th (0 = most recent) cached value from the given buffer.
*
* @todo Return DBL_MAX in case the index is out of array boundary.
*/
template <typename D>
D GetTailValue(int _buffer_index, int _shift) {
Expand Down
9 changes: 7 additions & 2 deletions Indicators/Indi_MA.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,13 @@ struct IndiMAParams : IndicatorParams {
ENUM_MA_METHOD ma_method;
ENUM_APPLIED_PRICE applied_array;
// Struct constructors.
IndiMAParams(unsigned int _period = 13, int _ma_shift = 10, ENUM_MA_METHOD _ma_method = MODE_SMA,
ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 0)
/**
* Regarding _ma_shift and _shift:
* @see https://www.mql5.com/en/forum/146006#comment_3685589
* "Always use MA shift 0 (ignore it) and use the regular shift, unless you are placing it on the chart for visual".
*/
IndiMAParams(unsigned int _period = 13, int _ma_shift = 0, ENUM_MA_METHOD _ma_method = MODE_SMA,
ENUM_APPLIED_PRICE _ap = PRICE_OPEN, int _shift = 10)
: period(_period), ma_shift(_ma_shift), ma_method(_ma_method), applied_array(_ap), IndicatorParams(INDI_MA) {
shift = _shift;
SetCustomIndicatorName("Examples\\Moving Average");
Expand Down

0 comments on commit 6c4ac8d

Please sign in to comment.