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

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

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

template<typename T, typename I = unsigned long>
using u_idx_v = UlcerIndexVisitor<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 Ulcer Index.
The result is a vector of values with same number of items as the given column. The first periods items, in the result, will be NAN.

The Ulcer Index (UI) is a technical indicator that measures downside risk in terms of both the depth and duration of price declines. The index increases in value as the price moves farther away from a recent high and falls as the price rises to new highs. The indicator is usually calculated over a 14-day period, with the Ulcer Index showing the percentage drawdown a trader can expect from the high over that period.
The greater the value of the Ulcer Index, the longer it takes for a stock to get back to the former high. Simply stated, it is designed as one measure of volatility only on the downside.
    explicit
    UlcerIndexVisitor(std::size_t periods = 14, bool use_sum = true);
        
periods: The daily period to calculate over
use_sum: If true, the final calculation is done over the rolling sum of periods. If false, the final calculation is done over rolling average of periods
T: Column data type
I: Index type
static void test_UlcerIndexVisitor()  {

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

    typedef StdDataFrame<std::string> StrDataFrame;

    StrDataFrame    df;

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

        UlcerIndexVisitor<double, std::string>  ui_v;

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

        assert(ui_v.get_result().size() == 5031);
        assert(std::isnan(ui_v.get_result()[0]));
        assert(std::isnan(ui_v.get_result()[12]));
        assert(ui_v.get_result()[13] == 0);
        assert(std::abs(ui_v.get_result()[27] - 6.10378) < 0.00001);
        assert(std::abs(ui_v.get_result()[31] - 8.48463) < 0.00001);
        assert(std::abs(ui_v.get_result()[5030] - 11.1348) < 0.0001);
        assert(std::abs(ui_v.get_result()[5026] - 7.98096) < 0.00001);

        UlcerIndexVisitor<double, std::string>  ui_v2 (14, false);

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

        assert(ui_v2.get_result().size() == 5031);
        assert(std::isnan(ui_v2.get_result()[0]));
        assert(std::isnan(ui_v2.get_result()[12]));
        assert(ui_v2.get_result()[13] == 0);
        assert(std::abs(ui_v2.get_result()[27] - 1.6313) < 0.0001);
        assert(std::abs(ui_v2.get_result()[31] - 2.26761) < 0.00001);
        assert(std::abs(ui_v2.get_result()[5030] - 2.9759) < 0.0001);
        assert(std::abs(ui_v2.get_result()[5026] - 2.133) < 0.001);
    }
    catch (const DataFrameError &ex)  {
        std::cout << ex.what() << std::endl;
    }
}