← Back to Documentations

Signature Description Parameters
#include <DataFrame/DataFrameFinancialVisitors.h>

template<typename T, typename I = unsigned long,
         std::size_t A = 0>
struct SupertrendVisitor;

// -------------------------------------

template<typename T, typename I = unsigned long,
         std::size_t A = 0>
using supertrend_v = SupertrendVisitor<T, I, A>;
This is a “single action visitor”, meaning it is passed the whole data vector in one call and you must use the single_act_visit() interface.

Supertrend is a trend-following indicator that draws one line on the price chart. The line sits below price in an uptrend and above price in a downtrend, and it flips sides when the trend changes. It is built on Average True Range (ATR), so the line keeps a distance from price that adapts to recent volatility.
It requires 3 input columns, in the order low, high, close. This is a “single action visitor”: use single_act_visit().
True range is computed per bar. ATR is Wilder-smoothed over period bars, seeded with the simple mean of the first period true ranges. The raw bands are (high + low) / 2 ± multiplier * ATR. The final bands only tighten while a trend lasts. The upper band can move down but not up, and the lower band can move up but not down, until the previous close breaks through it. This is what makes the line behave like a trailing stop. In an uptrend the line is the final lower band, and in a downtrend it is the final upper band. The trend flips when the close crosses the active band: below the lower band in an uptrend, above the upper band in a downtrend. The first valid bar starts in an uptrend (the same convention as TradingView).

When to use it
Trend direction filter. Trade long only when the trend is up, short only when it is down.
Trailing stop. The line only moves in the trade’s favor, so it can serve as a stop level.
Entry and exit signals. A trend flip is the signal.
Best in trending markets. In sideways markets it flips back and forth (whipsaws). Pairing it with a trend-strength or choppiness filter (e.g. AvgDirMovIdxVisitor or ChopIndexVisitor) helps.
Tuning. A larger multiplier gives a wider line, fewer flips and later signals. A smaller one gives a tighter line, more flips and more false signals. A longer period gives a smoother ATR and a slower response.
Lag. Like all trend followers, it confirms a trend after it has started.

get_result() and get_supertrend(): Return the Supertrend line.
get_trend(): Returns +1 for an uptrend, −1 for a downtrend. A signal is any bar where the value differs from the previous bar’s.
get_upper_band() and get_lower_band(): Return the final bands. Both are always populated. The Supertrend line equals one of them at each bar, according to the trend.
explicit
SupertrendVisitor(size_type period = 10, value_type multiplier = 3);

period: ATR period. It must be greater than 0 and no larger than the column size.
multiplier: how many ATRs away from the bar’s midpoint the bands sit.

        
T: Column data type
I: Index type
A: Memory alignment boundary for vectors. Default is system default alignment
static void test_SupertrendVisitor()  {

    std::cout << "\nTesting SupertrendVisitor{ } ..." << std::endl;

    StrDataFrame    df;

    try  {
        df.read("IBM.csv", io_format::csv2);
    }
    catch (const DataFrameError &ex)  {
        std::cout << ex.what() << std::endl;
        ::exit(-1);
    }

    supertrend_v<double, std::string>   st;

    df.single_act_visit<double, double, double>("IBM_Low", "IBM_High", "IBM_Close", st);

    // Same as calling get_supertrend()
    //
    assert(st.get_result().size() == 5031);
    assert(std::isnan(st.get_result()[0]));
    assert(std::isnan(st.get_result()[8]));
    assert(std::abs(st.get_result()[9] - 86.7938) < 0.0001);
    assert(std::abs(st.get_result()[10] - 86.9581) < 0.0001);
    assert(std::abs(st.get_result()[25] - 91.1886) < 0.0001);
    assert(std::abs(st.get_result()[51] - 98.5394) < 0.0001);
    assert(std::abs(st.get_result()[52] - 90.8008) < 0.0001);
    assert(std::abs(st.get_result()[77] - 118.575) < 0.001);
    assert(std::abs(st.get_result()[101] - 102.913) < 0.001);
    assert(std::abs(st.get_result()[5022] - 128.97) < 0.001);
    assert(std::abs(st.get_result()[5029] - 117.745) < 0.001);
    assert(std::abs(st.get_result()[5030] - 117.745) < 0.001);

    assert(st.get_trend().size() == 5031);
    assert(std::isnan(st.get_trend()[8]));
    assert(st.get_trend()[9] == 1.0);
    assert(st.get_trend()[25] == 1.0);
    assert(st.get_trend()[51] == -1.0);
    assert(st.get_trend()[52] == 1.0);
    assert(st.get_trend()[77] == -1.0);
    assert(st.get_trend()[101] == -1.0);
    assert(st.get_trend()[5030] == -1.0);

    assert(st.get_upper_band().size() == 5031);
    assert(std::isnan(st.get_upper_band()[8]));
    assert(std::abs(st.get_upper_band()[9] - 111.581) < 0.001);
    assert(std::abs(st.get_upper_band()[25] - 107.091) < 0.001);
    assert(std::abs(st.get_upper_band()[51] - 98.5394) < 0.0001);
    assert(std::abs(st.get_upper_band()[101] - 102.913) < 0.001);
    assert(std::abs(st.get_upper_band()[5030] - 117.745) < 0.001);

    assert(st.get_lower_band().size() == 5031);
    assert(std::isnan(st.get_lower_band()[8]));
    assert(std::abs(st.get_lower_band()[9] - 86.7938) < 0.0001);
    assert(std::abs(st.get_lower_band()[25] - 91.1886) < 0.0001);
    assert(std::abs(st.get_lower_band()[51] - 82.7474) < 0.0001);
    assert(std::abs(st.get_lower_band()[101] - 83.2584) < 0.0001);
    assert(std::abs(st.get_lower_band()[5030] - 106.575) < 0.001);
}

C++ DataFrame