#include #include "../misc_framework/GenericDataNodes.h" #include "../misc_framework/StandardPlaceholders.h" #include "SmbLR.h" //////////////////////////////////////////////////////////////////// // SmbLRBase::Accumulator //////////////////////////////////////////////////////////////////// void SmbLRBase::Accumulator::addPoint(double x, double y) { _sx += x; _sxx += x*x; _sy += y; _syy += y*y; _sxy += x*y; _count++; } void SmbLRBase::Accumulator::removePoint(double x, double y) { _sx -= x; _sxx -= x*x; _sy -= y; _syy -= y*y; _sxy -= x*y; _count--; } SmbLRBase::Accumulator::Accumulator() { reset(); } double SmbLRBase::Accumulator::getStdDev() const { // This formula comes from http://www.westgard.com/lesson34.htm return sqrt((_count * _syy - _sy*_sy) / (_count * (_count - 1))); } void SmbLRBase::Accumulator::getMAndB(double &m, double &b) const { // This formula comes from http://science.widener.edu/svb/stats/regress.html m = (_sxy - _sx * _sy / _count) / (_sxx - _sx * _sx / _count); b = (_sy - m * _sx) / _count; } void SmbLRBase::Accumulator::getRSquared(double &rr) const { // I'm not sure of the original source of this formuala. I copied it from // ../request_history/ProcessData.C. Presumably I had copied that from // the Delphi version. This doesn't seem to match the SMB code or wikipedia. rr = _sxy * _sxy / _sxx / _syy; } double SmbLRBase::Accumulator::getEstimated(double x) const { double m; double b; getMAndB(m, b); return m * x + b; } void SmbLRBase::Accumulator::reset() { _sx = 0; _sxx = 0; _sy = 0; _syy = 0; _sxy = 0; _count = 0; } //////////////////////////////////////////////////////////////////// // SmbLRBase //////////////////////////////////////////////////////////////////// void SmbLRBase::onWakeup(int msgId) { switch (msgId) { case wTos: onTos(); break; case wCandle: onCandle(); break; } } void SmbLRBase::onTos() { notifyListeners(); } void SmbLRBase::onCandle() { makeCurrent(); notifyListeners(); } void SmbLRBase::makeCurrent() { if (_lastEpoch == _candleData->getEpoch()) return; _lastEpoch = _candleData->getEpoch(); if (_candleData->historicalCandleCount() < _bars - 1) // Insufficient data. _accumulator.reset(); else if ((_accumulator.getCount() != _bars - 1) || (_candleData->getLastTransition() != StandardCandles::ltNewCandle)) { // Start fresh. Store the most recent N-1 complete candles. We will add // one more complete candle from way back in history, or we will add the // candle in progress, to get a total of N. _accumulator.reset(); StandardCandles::CandleArray const &candles = _candleData->getHistory(); for (int i = candles.size() - 1; _accumulator.getCount() < _bars - 1; i--) { assert(i >= 0); _accumulator.addPoint(i, candles[i].close); } } else { // Add the most recent candle. Remove the oldest one. StandardCandles::CandleArray const &candles = _candleData->getHistory(); _accumulator.addPoint(candles.size() - 1, candles[candles.size() - 1].close); _accumulator.removePoint(candles.size() - _bars, candles[candles.size() - _bars].close); } } void SmbLRBase::get(Accumulator const &accumulator, bool &valid, double &mlr, double &stdDev, int lastX) { if (accumulator.empty()) valid = false; else { mlr = accumulator.getEstimated(lastX); stdDev = accumulator.getStdDev(); valid = finite(mlr) && finite(stdDev); } } void SmbLRBase::get(Accumulator const &accumulator, bool &valid, double &mlr, int lastX) { if (accumulator.empty()) valid = false; else { mlr = accumulator.getEstimated(lastX); valid = finite(mlr); } } void SmbLRBase::getSlopeAndRSquared(Accumulator const &accumulator, bool &valid, double &m, double &rr, int lastX) { if (accumulator.empty()) valid = false; else { double b; accumulator.getMAndB(m, b); accumulator.getRSquared(rr); valid = finite(m) && finite(rr); } } SmbLRBase::Accumulator SmbLRBase::fillAccumulator(bool live) { if (live) { if ((_candleData->historicalCandleCount() + 1 < _bars) || !_tosData->getValid()) // not enough data return Accumulator(); Accumulator live = _accumulator; live.addPoint(_candleData->historicalCandleCount(), _tosData->getLast().price); return live; } else { // All historical const int firstIndex = _candleData->historicalCandleCount() - _bars; if (firstIndex < 0) // not enough data return Accumulator(); Accumulator historical = _accumulator; historical.addPoint(firstIndex, _candleData->getHistory()[firstIndex].close); return historical; } } SmbLRBase::SmbLRBase(DataNodeArgument const &args) : _lastEpoch(0) { DataNodeArgumentVector const &argList = args.getListValue(); assert(argList.size() == 4); // symbol, minutesPerBar, bars, strict std::string const &symbol = argList[0].getStringValue(); const int minutesPerBar = argList[1].getIntValue(); _bars = argList[2].getIntValue(); const bool strict = argList[3].getBooleanValue(); assert(_bars > 1); addAutoLink(StandardCandles::find(this, wCandle, _candleData, symbol, minutesPerBar, strict)); addAutoLink(GenericTosDataNode::find(this, wTos, _tosData, symbol)); makeCurrent(); } void SmbLRBase::get(bool &valid, double &mlr, double &stdDev) { makeCurrent(); const bool live = _candleData->shouldUseLive(); const Accumulator a = fillAccumulator(live); int last = _candleData->historicalCandleCount(); if (!live) last--; get(a, valid, mlr, stdDev, last); } void SmbLRBase::get(bool &valid, double &mlr) { makeCurrent(); const bool live = _candleData->shouldUseLive(); const Accumulator a = fillAccumulator(live); int last = _candleData->historicalCandleCount(); if (!live) last--; get(a, valid, mlr, last); } void SmbLRBase::getSlopeAndRSquared(bool &valid, double &m, double &rr) { makeCurrent(); const bool live = _candleData->shouldUseLive(); const Accumulator a = fillAccumulator(live); int last = _candleData->historicalCandleCount(); if (!live) last--; getSlopeAndRSquared(a, valid, m, rr, last); } DataNodeLink *SmbLRBase::find(DataNodeListener *listener, int msgId, SmbLRBase *&node, std::string const &symbol, int minutesPerBar, int bars, bool strict) { return findHelper(listener, msgId, node, argList(symbol, minutesPerBar, bars, strict)); } DataNodeLink *SmbLRBase::find(SmbLRBase *&node, std::string const &symbol, int minutesPerBar, int bars, bool strict) { return find(NULL, 0, node, symbol, minutesPerBar, bars, strict); }