#ifndef __SmbLR_h_ #define __SmbLR_h_ #include "../data_framework/StandardCandles.h" #include "../data_framework/GenericTosData.h" /* This computes the linear regression channel for a stock based on the closing * price of historical candles. Like a typical desktop application we use the * last print as the last data point, without waiting for the candle to end. * As typically used in stock analytics, we compute two values at the same * time. One is the point where the stock should be at this time, if it was * right on the linear regression line. The other is the standard deviation of * the recent points. The channel is typically defined as being n standard * deviations above the regression line, and n standard deviations below the * line. * * This was copied from ../data_framework/LinearRegression.[Ch] and modified * to better fit the SMB requirements. The biggest change is that we want * to compute the linear regression of (H+L+C)/3 rather than just the close. * It seemed easier to copy and modify the file than to make it flexible * enough to handle either case. * * Also, we are adding the R-squared value. That could have been done in the * main version, we just never needed it before now. * * I took out the Standard Deviation data node as it was not required, and that * was the easist way to avoid a name conflict. */ class SmbLRBase : public DataNode { public: class Accumulator { private: double _sx, _sxx, _sy, _syy, _sxy; // Sums. int _count; public: Accumulator(); void addPoint(double x, double y); void removePoint(double x, double y); double getStdDev() const; void getMAndB(double &m, double &b) const; void getRSquared(double &rr) const; double getEstimated(double x) const; int getCount() const { return _count; } bool empty() const { return _count == 0; } void reset(); }; private: StandardCandles *_candleData; GenericTosDataNode *_tosData; int _bars; StandardCandles::Epoch _lastEpoch; // This includes the most recent N-1 complete bars. To see the current // value, add the point in progress from the TOS. To see the value for the // last complete bar, add the oldest point that we should be looking at. Accumulator _accumulator; enum { wTos, wCandle }; void onWakeup(int msgId); void onTos(); void onCandle(); void makeCurrent(); static void get(Accumulator const &accumulator, bool &valid, double &mlr, double &stdDev, int lastX); static void get(Accumulator const &accumulator, bool &valid, double &mlr, int lastX); static void getSlopeAndRSquared(Accumulator const &accumulator, bool &valid, double &m, double &rr, int lastX); Accumulator fillAccumulator(bool live); SmbLRBase(DataNodeArgument const &args); friend class DataNode; public: // We should be valid any time we have enough data points. We check for // other problems, just to be Safe. // // mlr is Moving Linear regression, or where the regression line suggests we // should be right now. // // We pack the stdDev with the mlr because we know how this data is normally // used. Also to avoid duplicated effort in the valid processing. void get(bool &valid, double &mlr, double &stdDev); void get(bool &valid, double &mlr); void getSlopeAndRSquared(bool &valid, double &m, double &rr); static DataNodeLink *find(DataNodeListener *listener, int msgId, SmbLRBase *&node, std::string const &symbol, int minutesPerBar, int bars, bool strict = true); static DataNodeLink *find(SmbLRBase *&node, std::string const &symbol, int minutesPerBar, int bars, bool strict = true); }; #endif