#include "IntradayEma.h" void IntradayEma::onWakeup(int msgId) { switch (msgId) { case wTos: onTos(); break; case wCandle: onCandle(); break; } } void IntradayEma::onTos() { // We could make this smarter. Sometimes we don't care about a TOS event. // However, it's always safe to send extra messages. And the expected case // is that no one will be listing to these events. Someone will listen to // other events. Currently the PTS alert class is the only class that uses // this class. notifyListeners(); } void IntradayEma::onCandle() { makeCurrent(); notifyListeners(); } void IntradayEma::makeCurrent() { if (_candleData->getEpoch() == _lastEpoch) // No change. return; _lastEpoch = _candleData->getEpoch(); StandardCandles::CandleArray const &candles = _candleData->getHistory(); if ((_currentBarCount == 0) || (_candleData->getLastTransition() != StandardCandles::ltNewCandle)) { // Start from scratch. _currentBarCount = 0; _accumulator = 0.0; for (StandardCandles::CandleArray::const_iterator it = candles.begin(); it != candles.end(); it++) addValue(it->close); } else // Add one candle. addValue(candles.rbegin()->close); } void IntradayEma::addValue(double value) { if (_currentBarCount) _accumulator = getValue(value); else _accumulator = value; _currentBarCount++; } double IntradayEma::getValue(double last) const { return last * _portionOfNewValue + _accumulator * (1.0 - _portionOfNewValue); } IntradayEma::IntradayEma(DataNodeArgument const &args) : _lastEpoch(0), _currentBarCount(0), _accumulator(0.0) { DataNodeArgumentVector const &argList = args.getListValue(); assert(argList.size() == 3); // symbol, minutesPerBar, bars std::string const &symbol = argList[0].getStringValue(); const int minutesPerBar = argList[1].getIntValue(); _bars = argList[2].getIntValue(); assert(_bars > 0); _portionOfNewValue = 2.0 / (1.0 + _bars); addAutoLink(StandardCandles::find(this, wCandle, _candleData, symbol, minutesPerBar)); addAutoLink(GenericTosDataNode::find(this, wTos, _tosData, symbol)); makeCurrent(); } bool IntradayEma::getLastValid() { makeCurrent(); return _currentBarCount >= _bars; } double IntradayEma::getLastValue() { makeCurrent(); return _accumulator; } bool IntradayEma::getCurrentValid() { makeCurrent(); if (_candleData->isActive()) // Use a partial bar plus all the finished bars. return _tosData->getValid() && (_currentBarCount + 1 >= _bars); else // Use only the finished bars. return _currentBarCount >= _bars; } double IntradayEma::getCurrentValue() { makeCurrent(); if (_candleData->isActive()) // Use a partial bar plus all the finished bars. return getValue(_tosData->getLast().price); else return _accumulator; } DataNodeLink *IntradayEma::find(DataNodeListener *listener, int msgId, IntradayEma *&node, std::string const &symbol, int minutesPerBar, int bars) { return findHelper(listener, msgId, node, argList(symbol, minutesPerBar, bars)); } DataNodeLink *IntradayEma::find(IntradayEma *&node, std::string const &symbol, int minutesPerBar, int bars) { return find(NULL, 0, node, symbol, minutesPerBar, bars); }