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

template<typename T, typename I = unsigned long>
struct PercentPriceOSCIVisitor;

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

template<typename T, typename I = unsigned long>
using pp_osc_v = PercentPriceOSCIVisitor<T, I>;
        
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.

This visitor calculates the rolling values of Percentage Price Oscillator. It requires 3 input columns in the order of low, high, close.
The result is a vector of values with same number of items as the given columns. The first slow_roll items, in the result, will be NAN.

The percentage price oscillator (PPO) is a technical momentum indicator that shows the relationship between two moving averages in percentage terms. The moving averages are a 26-period and 12-period exponential moving average (EMA).
The PPO is used to compare asset performance and volatility, spot divergence which could lead to price reversals, generate trade signals, and help confirm trend direction. The PPO is identical to the moving average convergence divergence (MACD) indicator, except the PPO measures percentage difference between two EMAs, while the MACD measures absolute (dollar) difference. Some traders prefer the PPO because readings are comparable between assets with different prices, whereas MACD readings are not comparable.
    explicit
    PercentPriceOSCIVisitor(std::size_t fast_period = 12,
                            std::size_t slow_period = 26);
        
T: Column data type
I: Index type
static void test_PercentPriceOSCIVisitor()  {

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

    typedef StdDataFrame<std::string> StrDataFrame;

    StrDataFrame    df;

    try  {
        df.read("IBM.csv", io_format::csv2);

        PercentPriceOSCIVisitor<double, std::string>    ppo_v;

        df.single_act_visit<double>("IBM_Close", ppo_v);

        assert(ppo_v.get_result().size() == 5031);
        assert(std::isnan(ppo_v.get_result()[0]));
        assert(std::isnan(ppo_v.get_result()[24]));
        assert(std::abs(ppo_v.get_result()[25] - -1.01156) < 0.00001);
        assert(std::abs(ppo_v.get_result()[29] - -1.63896) < 0.00001);
        assert(std::abs(ppo_v.get_result()[34] - -3.17651) < 0.00001);
        assert(std::abs(ppo_v.get_result()[5030] - -3.46821) < 0.00001);
        assert(std::abs(ppo_v.get_result()[5026] - -0.00785639) < 0.00001);
        assert(std::abs(ppo_v.get_result()[5021] - 1.69995) < 0.00001);
    }
    catch (const DataFrameError &ex)  {
        std::cout << ex.what() << std::endl;
    }
}