#include "StandardCandles.h" #include "../misc_framework/GenericDataNodes.h" #include "UpCandles.h" class UpCandles : GenericDataNode { private: enum Direction { dEnd, /* Not enough data to make a comparison. If we run * out of data before we have an answer, then we don't * know the answer. Our output cannot be valid. */ dUp, // This candle is higher than the previous one. dDown, // This candle is lower than the previous one. dNeither // This candle is not clearly above or below. }; StandardCandles *_candleData; // These are all cached values. We update the cache when required. That // might be done during a const operation. mutable int _value; // We enforce a limit on this size of this, so we know it won't need 64 bits! mutable bool _valid; mutable StandardCandles::Epoch _epoch; void verifyCurrent() const; // i=0 compares the last candle to the previous one. i=1 compares the // second to last candle to the one before that. etc. Direction describeCandle(int i) const; UpCandles(DataNodeArgument const &args); friend class GenericDataNodeFactory; public: void getInteger(bool &valid, Integer &value) const; }; UpCandles::Direction UpCandles::describeCandle(int i) const { StandardCandles::CandleArray const &candles = _candleData->getHistory(); const int latter = candles.size() - i - 1; const int former = latter - 1; if (former < 0) return dEnd; if ((candles[latter].high > candles[former].high) && (candles[latter].low > candles[former].low)) return dUp; if ((candles[latter].high < candles[former].high) && (candles[latter].low < candles[former].low)) return dDown; return dNeither; } void UpCandles::verifyCurrent() const { // We must check the epoch to know if we are out of date. Listening for // a change notification, and keeping our own flag to know if the cache // is valid would never work. Too many things are all listening to the // new candle data. We could not gaurentee that we are not giving out old // data. if (_epoch == _candleData->getEpoch()) return; _epoch = _candleData->getEpoch(); const Direction initialDirection = describeCandle(0); Direction currentDirection = initialDirection; _value = 0; while (true) { if ((currentDirection == dEnd) || (_value > 100)) { _valid = false; break; } if ((currentDirection == dNeither) || (currentDirection != initialDirection)) { _valid = true; if (initialDirection == dDown) _value = -_value; break; } _value++; currentDirection = describeCandle(_value); } } UpCandles::UpCandles(DataNodeArgument const &args) : _value(0), _valid(false), _epoch(0) { DataNodeArgumentVector const &argList = args.getListValue(); assert(argList.size() == 2); // symbol, minutesPerBar std::string const &symbol = argList[0].getStringValue(); const int minutesPerBar = argList[1].getIntValue(); addAutoLink(StandardCandles::find(this, 0, _candleData, symbol, minutesPerBar)); } void UpCandles::getInteger(bool &valid, Integer &value) const { verifyCurrent(); valid = _valid; value = _value; } void initializeUpCandles() { GenericDataNodeFactory::sf< UpCandles > ("UpCandles1", symbolPlaceholderObject, 1); GenericDataNodeFactory::sf< UpCandles > ("UpCandles2", symbolPlaceholderObject, 2); GenericDataNodeFactory::sf< UpCandles > ("UpCandles5", symbolPlaceholderObject, 5); GenericDataNodeFactory::sf< UpCandles > ("UpCandles10", symbolPlaceholderObject, 10); GenericDataNodeFactory::sf< UpCandles > ("UpCandles15", symbolPlaceholderObject, 15); GenericDataNodeFactory::sf< UpCandles > ("UpCandles30", symbolPlaceholderObject, 30); GenericDataNodeFactory::sf< UpCandles > ("UpCandles60", symbolPlaceholderObject, 60); }