forked from EA31337/EA31337-classes
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
273 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
//+------------------------------------------------------------------+ | ||
//| EA31337 framework | | ||
//| Copyright 2016-2023, EA31337 Ltd | | ||
//| https://github.com/EA31337 | | ||
//+------------------------------------------------------------------+ | ||
|
||
/* | ||
* This file is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
/** | ||
* @file | ||
* Tf-based candle indicator for MT. | ||
*/ | ||
|
||
#ifndef __MQL__ | ||
// Allows the preprocessor to include a header file when it is needed. | ||
#pragma once | ||
#endif | ||
|
||
// Includes. | ||
#include "../../Indicator/IndicatorCandle.h" | ||
#include "Indi_TfMt.provider.h" | ||
|
||
// Params for MT Tf-based candle indicator. | ||
struct Indi_TfMtParams : IndicatorTfParams { | ||
Indi_TfMtParams(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) : IndicatorTfParams("IndicatorTf", _tf) {} | ||
}; | ||
|
||
/** | ||
* Tf-based candle indicator for MT. | ||
*/ | ||
class Indi_TfMt : public IndicatorCandle<Indi_TfMtParams, double, ItemsHistoryTfMtCandleProvider<double>> { | ||
protected: | ||
// Time-frame used to create candles. | ||
ENUM_TIMEFRAMES tf; | ||
|
||
/* Protected methods */ | ||
|
||
/** | ||
* Initialize class. | ||
* | ||
* Called on constructor. | ||
*/ | ||
void Init() { history.SetItemProvider(new ItemsHistoryTfMtCandleProvider<double>(THIS_PTR)); } | ||
|
||
public: | ||
/* Special methods */ | ||
|
||
/** | ||
* Class constructor with timeframe enum. | ||
*/ | ||
Indi_TfMt(ENUM_TIMEFRAMES _tf = PERIOD_CURRENT) { | ||
tf = _tf; | ||
Init(); | ||
} | ||
|
||
/** | ||
* Class constructor with timeframe index. | ||
*/ | ||
Indi_TfMt(ENUM_TIMEFRAMES_INDEX _tfi = 0) { | ||
tf = ChartTf::IndexToTf(_tfi); | ||
Init(); | ||
} | ||
|
||
/** | ||
* Class constructor with parameters. | ||
*/ | ||
Indi_TfMt(Indi_TfMtParams& _icparams, const IndicatorDataParams& _idparams) { Init(); } | ||
|
||
/** | ||
* Gets indicator's time-frame. | ||
*/ | ||
ENUM_TIMEFRAMES GetTf() override { return tf; } | ||
|
||
/** | ||
* Returns current tick index (incremented every OnTick()). | ||
*/ | ||
int GetTickIndex() override { return history.GetItemProvider() PTR_DEREF GetTickIndex(); } | ||
|
||
/** | ||
* 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 ::Bars(GetSymbol(), GetTf()) - iparams.shift; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
//+------------------------------------------------------------------+ | ||
//| EA31337 framework | | ||
//| Copyright 2016-2021, EA31337 Ltd | | ||
//| https://github.com/EA31337 | | ||
//+------------------------------------------------------------------+ | ||
|
||
/* | ||
* This file is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
|
||
#ifndef __MQL__ | ||
// Allows the preprocessor to include a header file when it is needed. | ||
#pragma once | ||
#endif | ||
|
||
/** | ||
* Candle grouping and regeneration for time-frame based candles. | ||
*/ | ||
template <typename TV> | ||
class ItemsHistoryTfMtCandleProvider : public ItemsHistoryCandleProvider<TV> { | ||
// Pointer to Tf Indicator, e.g., Indi_TfMt or IndicatorTfDummy. Used to fetch data by fixed timeframe candles. | ||
IndicatorData* indi; | ||
|
||
// Current tick index. Effectively a number of ticks generated by attached Tick indicator. | ||
int tick_index; | ||
|
||
public: | ||
/** | ||
* Constructor. | ||
*/ | ||
ItemsHistoryTfMtCandleProvider(IndicatorData* _indi_tf) : indi(_indi_tf), tick_index(0) {} | ||
|
||
/** | ||
* Called when new tick was emitted from IndicatorTick-based source. | ||
*/ | ||
virtual void OnTick(ItemsHistory<CandleOCTOHLC<TV>, ItemsHistoryTfMtCandleProvider<TV>>* _history, long _time_ms, | ||
float _ask, float _bid) { | ||
++tick_index; | ||
|
||
// Seconds per candle calculated from TF. | ||
int _spc = (int)ChartTf::TfToSeconds(indi PTR_DEREF GetTf()); | ||
|
||
Print("Indi_TfMt's history: New tick: ", TimeToString(_time_ms / 1000, TIME_DATE | TIME_MINUTES | TIME_SECONDS), | ||
", ", _ask, ", ", _bid); | ||
|
||
// We know that tick's timestamp will be ahead of the last tick and thus | ||
// inside or ahead of the last created candle. In order to retrieve last | ||
// valid candle, we need to use ItemsHistory::GetItemByShift(0) to check if | ||
// we have to update last or create/append new candle. | ||
CandleOCTOHLC<TV> _candle; | ||
|
||
// Will regenerate candles up to the last added candle ever. We have to | ||
// call it, because some of the previous actions may have removed some of | ||
// the recent candles. Note that OnTick() advances its _time_ms in | ||
// ascending order, so all we need to most recent history. | ||
// | ||
// Note that EnsureShiftExists() may return false when there never been any | ||
// candle added. | ||
_history PTR_DEREF EnsureShiftExists(0); | ||
|
||
if (_history PTR_DEREF TryGetItemByShift(0, _candle, false) && _candle.ContainsTimeMs(_time_ms)) { | ||
// Time given fits in the last added candle's time-frame, updating the candle with given price. | ||
_candle.Update(_time_ms, _bid); | ||
|
||
// Storing candle in the history. | ||
_history PTR_DEREF Update(_candle, _history PTR_DEREF GetShiftIndex(0)); | ||
} else { | ||
CandleOCTOHLC<TV> _candle_tmp; | ||
|
||
// We don't want to regenerate history, because at the start there will bo no candle however. | ||
if (_history PTR_DEREF TryGetItemByShift(0, _candle_tmp, false)) { | ||
// Print("Completed candle: ", _candle_tmp.ToString()); | ||
// Print("Real candle: ", iOpen(NULL, Period(), 1), " ", iHigh(NULL, Period(), 1), " ", | ||
// iLow(NULL, Period(), 1), " ", ChartStatic::iClose(NULL, (ENUM_TIMEFRAMES)Period(), 1)); | ||
// Print("--"); | ||
} | ||
|
||
// Either there is no candle at shift 0 or given time doesn't fit in the #0 candle's time-frame. | ||
_candle.Init(GetCandleTimeFromTimeMs(_time_ms, _spc), _spc, _time_ms, _bid); | ||
|
||
// Adding candle as the most recent item in the history. It will now become the candle at shift 0. | ||
_history PTR_DEREF Append(_candle); | ||
} | ||
} | ||
|
||
/** | ||
* Returns current tick index. Effectively a number of ticks generated by | ||
* attached IndicatorTick. | ||
*/ | ||
int GetTickIndex() { return tick_index; } | ||
|
||
/** | ||
* Returns start time of the candle (the place it's on the chart) for the given tick's time in milliseconds. | ||
*/ | ||
int GetCandleTimeFromTimeMs(long _time_ms, int _length_in_secs) { | ||
return (int)((_time_ms - _time_ms % ((long)_length_in_secs * 1000)) / 1000); | ||
} | ||
|
||
/** | ||
* Retrieves given number of items starting from the given microseconds or index (inclusive). "_dir" identifies if we | ||
* want previous or next items from selected starting point. Should return false if retrieving items by this method | ||
* is not available. | ||
*/ | ||
bool GetItems(ItemsHistory<CandleOCTOHLC<TV>, ItemsHistoryTfMtCandleProvider<TV>>* _history, long _from_time_ms, | ||
ENUM_ITEMS_HISTORY_DIRECTION _dir, int _num_items, ARRAY_REF(CandleOCTOHLC<TV>, _out_arr)) { | ||
return false; | ||
} | ||
|
||
/** | ||
* Retrieves items between given indices (both indices inclusive). Should return false if retrieving items by this | ||
* method is not available. | ||
*/ | ||
bool GetItems(ItemsHistory<CandleOCTOHLC<TV>, ItemsHistoryTfMtCandleProvider<TV>>* _history, int _start_index, | ||
int _end_index, ARRAY_REF(CandleOCTOHLC<TV>, _out_arr)) { | ||
Print("Indi_TfMt::GetItems()"); | ||
|
||
// Converting absolute indices into MT shifts. | ||
int _num_bars = _end_index - _start_index + 1; | ||
// Current candle index. Could be 0 if no candles have been added or if there is only one candle added so far. | ||
int _current_index = _history PTR_DEREF GetCurrentIndex(); | ||
int _start_shift = _current_index - _start_index; | ||
int _end_shift = _current_index - _end_index; | ||
|
||
Print("Indi_TfMt::GetItems(): Will fetch ", _num_bars, " bars between shift ", _start_shift, " and ", _end_shift); | ||
|
||
// Seconds per candle calculated from TF. | ||
int _spc = (int)ChartTf::TfToSeconds(indi PTR_DEREF GetTf()); | ||
|
||
// Static, reusable array of rates. | ||
static ARRAY(MqlRates, _rates); | ||
int _count = _end_index - _start_index + 1; | ||
ArrayResize(_rates, _count); | ||
|
||
Print("CopyRates(", indi PTR_DEREF GetSymbol(), ", ", EnumToString(indi PTR_DEREF GetTf()), ", ", _start_index, | ||
", ", _count, ", ...)"); | ||
|
||
// As GetItems() will only be called for missing candles, we can just ask MT for OHLCs and return them. | ||
// Note that we have to specify most recent shift and count of history ticks to return. | ||
// Also note that CopyRates() will insert oldest candle at the start of _rates array, so we have to inverse items in | ||
// the array in order all candles be from most recent to the oldest ones. | ||
int _num_copied = CopyRates(indi PTR_DEREF GetSymbol(), indi PTR_DEREF GetTf(), _end_shift, _count, _rates); | ||
ArrayResize(_out_arr, _num_copied); | ||
|
||
for (int i = 0; i < _num_copied; ++i) { | ||
MqlRates _rate = _rates[i]; | ||
int _start_secs = (int)(long)_rate.time; | ||
CandleOCTOHLC<TV> _candle(_rate.open, _rate.high, _rate.low, _rate.close, _start_secs, _spc, | ||
(long)_start_secs * 1000, long(_start_secs + _spc) * 1000 - 1, (int)_rate.tick_volume); | ||
// Reversing output, so most recent candle will be at start. | ||
_out_arr[_num_copied - i - 1] = _candle; | ||
} | ||
|
||
ArrayResize(_rates, 0); | ||
return true; | ||
} | ||
|
||
/** | ||
* Returns information about item provider. | ||
*/ | ||
string const ToString() override { return "Indi_TfMt candle provider on " + indi PTR_DEREF GetFullName(); } | ||
}; |