1

I've the following problem. I've a set of OHLCV (Open, High, Low, Close, Volume) data for a symbol, with the following structure:

struct OHLCV {
  double Open{0.0};
  double High{0.0};
  double Low{0.0};
  double Close{0.0};
  double Volume{0.0};
};

every data cover a time frame of 1 hour. I need to take many of them and then calculate the cumulative OHLCV. For example if need to calculate the OHLCV for a day from 24 hourly OHLCV.

for creating the cumulative OHLCV from a set of them I need to:

  • Take the first Open value;
  • Take the last Close value;
  • Take the highest High value;
  • Take the lowest Low value;
  • Take the sum of Volume values

I'd like to know if it's possible to use boost::accumulator for this purpose so I can write code like following one:

using namespace boost::accumulators;

std::vector<OHLCV> rawData;

// creating CustomFeatures and OHLCVCumulative...

accumulator_set<OHLCV, CustomFeatures> ohlcvAcc;

for (const auto& ohlcv : rawData) {
  ohlcvAcc(ohlcv);
}

auto cumulativeOHLCV = OHLCVCumulative(ohlcvAcc);

It's possible to do something like this? Or there's a better solution?

Jepessen
  • 11,744
  • 14
  • 82
  • 149
  • Quote from [Boost library documentation](https://www.boost.org/doc/libs/1_65_0/doc/html/accumulators/user_s_guide.html#accumulators.user_s_guide.the_accumulators_framework): ``The accumulator_set<> computes the requested quantities in the most efficient method possible, resolving dependencies between requested calculations, possibly caching intermediate results.`` The calculations in the question appear independent of each other - hence do we really need an accumulator library or a custom accumulator? – vpa1977 Jun 26 '21 at 10:03

1 Answers1

1

Interesting question. It looks clearly like the Sample concept is extensible with custom types, but I don't immediately see the mechanism(s). For one thing, if you could replace OHLCV witf valarray<double> you might be home free:

enum { Open, High, Low, Close, Volume };
using OHLCV = std::valarray<double>;

E.g.:

#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>
#include <boost/accumulators/numeric/functional.hpp>
#include <valarray>
#include <fmt/ranges.h>
namespace ba = boost::accumulators;
namespace bat = ba::tag;

enum { Open, High, Low, Close, Volume };
using OHLCV = std::valarray<double>;

// creating CustomFeatures and OHLCVCumulative...
using CustomFeatures = ba::stats<bat::sum>;

int main()
{
    ba::accumulator_set<OHLCV, CustomFeatures> ohlcvAcc(
        ba::sample = OHLCV{0, 0, 0, 0, 0});

    std::vector<OHLCV> rawData{
        {1, 2, 3, 4, 5}, {2, 3, 4, 5, 6}, {3, 4, 5, 6, 7},
        {4, 5, 6, 7, 8}, {5, 6, 7, 8, 9}, {6, 7, 8, 9, 10},
    };

    for (auto const& sample : rawData) {
        ohlcvAcc(sample);
    }

    auto sum = ba::sum(ohlcvAcc);
    fmt::print("sum: {}, Close: {}\n", sum, sum[Close]);
}

Prints

sum: {21, 27, 33, 39, 45}, Close: 39

(That's using libfmt 7.1.3, boost 1.76, GCC 11 -std=c++2a)

sehe
  • 374,641
  • 47
  • 450
  • 633