Returning Tuples
This tutorial we takes a closer look at the popular MACD and Bollinger Bands indicators. Both indicators are composed of multiple series that are returned as a single object of type series_tuple<T>. Let's first take a look at the MACD. It consists of two moving averages, a signal line, and a histogram.
Extract from Tutorial 210:
series_tuple<double> MACD_DEMO( sref<double> close, size_t period_short, size_t period_long, size_t period_signal) { auto ma_short = EMA(close, period_short); // short period moving average auto ma_long = EMA(close, period_long); // long period moving average auto macd_line = ma_short - ma_long; // difference between averages auto signal = EMA(macd_line, period_signal); // MACD signal auto histo = signal - macd_line; // MACD histogram
series_tuple<double> tuple = { // return value is tuple of series
macd_line.name("macd").plot_as("MACD", { period_short, period_long }, plot_type::line, color::blue),
signal.name("signal").plot_as("MACD-SIG", period_signal, plot_type::line, color::white),
histo.name("hist").plot_as("MACD-HIST", 0, plot_type::bar, color::green), };
return tuple; } |
|
Chart produced by tutorial 210:
Program Output: |
|
Accessing Series in Series Tuples
Lets have a look at how we would access series references that are themselves elements in a tuple object. In DSL, each series can simply be accessed by its name. Doing so has no impact on performance since DSL code is not evaluated repeatedly. We simply write:
void on_prepare(void) override
{
macd = MACD_DEMO(in.close, 12, 24, 9); // 'macd' is a strategy member
auto signal = macd("signal"); // access to individual tuple elements
auto macd_line = macd("macd");
auto macd_hist = macd("hist");
}
Performance is more of an issue when defining strategy::on_bar_close(), as it is called repeatedly for every bar. Although access to tuple elements by name is also possible, it is preferable to access values by ordinal position such as in:
void on_bar_close(void) override
{
const size_t macd_line_pos = 0;
const size_t macd_signal_pos = 1;
const size_t macd_histo_pos = 2;
double macd_line = macd[macd_line_pos][0];
double macd_signal = macd[macd_signal_pos][0];
double macd_histo = macd[macd_histo_pos][0];
}
Bollinger Bands
The popular Bollinger Bands function is another example of a function returning a tuple. The Bollinger Band concept is relatively simple. First, calculate a moving average, then add two bands, one above and one below the moving average, both at a distance defined by the standard deviation of price over the given period, multiplied by a given constant. Bollinger Bands can be used both as the basis for breakout systems as well as for mean reversion systems.
Extract from Tutorial 211.
|
series_tuple<double> BOLLINGER_BANDS_DEMO( series_cref<double> hi, series_cref<double> lo, series_cref<double> cl, size_t period, double std_dev_mult) { auto tp = TYPICAL_PRICE(hi, lo, cl); auto avg = SMA(tp, period); auto offset = STDEVP(tp, period) * std_dev_mult; auto upper = avg + offset; auto lower = avg - offset;
series_tuple<double> tuple = { upper.name("upper").plot_as("BB_U", std_dev_mult, plot_type::line, color::green), avg.name("avg").plot_as("BB_AVG", period, plot_type::line, color::white), lower.name("lower").plot_as("BB_L", std_dev_mult, plot_type::line, color::green) }; return tuple; } |
Chart produced by tutorial 211:
Program Output: |
|