#include #include "../data_framework/GenericL1Data.h" #include "../data_framework/GenericTosData.h" #include "../data_framework/SimpleMarketData.h" #include "../../shared/MarketHours.h" #include "../alert_framework/AlertBase.h" #include "FastRunning.h" ///////////////////////////////////////////////////////////////////// // RunningCommon ///////////////////////////////////////////////////////////////////// class RunningCommon : public DataNode { private: const double _tickVolatility; const double _cutOff; Alert::AboveOrBelow _state; double _priceIncrease; double _quality; double _ppHigh, _pHigh, _high, _ppLow, _pLow, _low; double _bid, _ask; time_t _updateTimeTag; bool _init; protected: RunningCommon(std::string const &symbol); virtual void getCurrentValues(bool &valid, double &lowerValue, double &higherValue) =0; void refreshTimeTag(); void onWakeup(int msgId); public: Alert::AboveOrBelow getState() const { return _state; } double getPriceIncrease() const { return _priceIncrease; } double getQuality() const { return _quality; } }; RunningCommon::RunningCommon(std::string const &symbol) : _tickVolatility(getTickVolatility(symbol)), _cutOff(_tickVolatility / sqrt(5.0)), _state(Alert::ccEqual), _priceIncrease(0.0), _quality(0.0), _ppHigh(0.0), _pHigh(0.0), _high(0.0), _ppLow(0.0), _pLow(0.0), _low(0.0), _bid(0.0), _ask(0.0), _updateTimeTag(0), _init(false) { } void RunningCommon::refreshTimeTag() { time_t time = secondOfTheDay(getSubmitTime()); time = (time + 29) / 30 * 30; // Round up. _updateTimeTag = midnight(getSubmitTime()) + time; } void RunningCommon::onWakeup(int msgId) { _state = Alert::ccEqual; bool newDataValid; double newBid, newAsk; getCurrentValues(newDataValid, newBid, newAsk); if ((_tickVolatility < MIN_VOLATILITY) || (!newDataValid)) { _init = false; return; } double lastBid = _bid; double lastAsk = _ask; _bid = newBid; _ask = newAsk; const time_t currentTimeTag = getSubmitTime(); if ((!_init) || (currentTimeTag + MARKET_HOURS_MINUTE < _updateTimeTag)) { // The current time should be no more than 30 seconds before // UpdateTimeTag. If the time is futher back, this must be the start of // a playback. _ppHigh = _ask; _pHigh = _ask; _high = _ask; _ppLow = _bid; _pLow = _bid; _low = _bid; refreshTimeTag(); _init = true; return; } if (currentTimeTag > _updateTimeTag + MARKET_HOURS_MINUTE) { _ppHigh = lastAsk; _pHigh = lastAsk; _high = lastAsk; _ppLow = lastBid; _pLow = lastBid; _low = lastBid; refreshTimeTag(); } else if (currentTimeTag > _updateTimeTag + 30) { _ppHigh = _high; _pHigh = _high; _high = lastAsk; _ppLow = _low; _pLow = _low; _low = lastBid; refreshTimeTag(); } else if (currentTimeTag > _updateTimeTag) { _ppHigh = _pHigh; _pHigh = _high; _high = lastAsk; _ppLow = _pLow; _pLow = _low; _low = lastBid; refreshTimeTag(); } if (_ppLow - _ask > _cutOff) { _priceIncrease = _bid - _ppLow; _quality = sqrt(MARKET_HOURS_MINUTE / (MARKET_HOURS_MINUTE - (_updateTimeTag - currentTimeTag) + 0.0)) * ((_ppLow - _ask) / _cutOff); _state = Alert::ccBelow; notifyListeners(); _ppLow = _bid; _pLow = _bid; _low = _bid; } else if (_bid - _ppHigh > _cutOff) { _priceIncrease = _ask - _ppHigh; _quality = sqrt(MARKET_HOURS_MINUTE / (MARKET_HOURS_MINUTE - (_updateTimeTag - currentTimeTag) + 0.0)) * ((_bid - _ppHigh) / _cutOff); _state = Alert::ccAbove; notifyListeners(); _ppHigh = _ask; _pHigh = _ask; _high = _ask; } _low = std::min(_low, _bid); _high = std::max(_high, _ask); } ///////////////////////////////////////////////////////////////////// // RunningCommonBBO ///////////////////////////////////////////////////////////////////// class RunningCommonBBO : public RunningCommon { private: GenericL1DataNode *_l1Data; RunningCommonBBO(DataNodeArgument const &args); friend class DataNode; protected: void getCurrentValues(bool &valid, double &lowerValue, double &higherValue); public: static DataNodeLink *find(DataNodeListener *listener, int msgId, RunningCommon *&node, std::string const &symbol); }; RunningCommonBBO::RunningCommonBBO(DataNodeArgument const &args) : RunningCommon(args.getStringValue()) { addAutoLink(GenericL1DataNode::find(this, 0, _l1Data, args.getStringValue())); } void RunningCommonBBO::getCurrentValues(bool &valid, double &lowerValue, double &higherValue) { valid = _l1Data->getValid(); if (valid) { double bid = _l1Data->getCurrent().bidPrice; double ask = _l1Data->getCurrent().askPrice; if (bid < ask) { lowerValue = bid; higherValue = ask; } else { lowerValue = ask; higherValue = bid; } valid = lowerValue > 0.0; } } DataNodeLink *RunningCommonBBO::find(DataNodeListener *listener, int msgId, RunningCommon *&node, std::string const &symbol) { return findHelper(listener, msgId, (RunningCommonBBO *&)node, symbol); } ///////////////////////////////////////////////////////////////////// // RunningCommonTosOnly ///////////////////////////////////////////////////////////////////// class RunningCommonTosOnly : public RunningCommon { private: GenericTosDataNode *_tosData; RunningCommonTosOnly(DataNodeArgument const &args); friend class DataNode; protected: void getCurrentValues(bool &valid, double &lowerValue, double &higherValue); public: static DataNodeLink *find(DataNodeListener *listener, int msgId, RunningCommon *&node, std::string const &symbol); }; RunningCommonTosOnly::RunningCommonTosOnly(DataNodeArgument const &args) : RunningCommon(args.getStringValue()) { addAutoLink(GenericTosDataNode::find(this, 0, _tosData, args.getStringValue())); } void RunningCommonTosOnly::getCurrentValues(bool &valid, double &lowerValue, double &higherValue) { valid = _tosData->getValid(); if (valid) { lowerValue = _tosData->getLast().price; higherValue = lowerValue; valid = lowerValue > 0.0; } } DataNodeLink *RunningCommonTosOnly::find(DataNodeListener *listener, int msgId, RunningCommon *&node, std::string const &symbol) { return findHelper(listener, msgId, (RunningCommonTosOnly *&)node, symbol); } ///////////////////////////////////////////////////////////////////// // Running ///////////////////////////////////////////////////////////////////// class Running : public Alert { private: RunningCommon *_data; bool _up; void onWakeup(int msgId); Running(DataNodeArgument const &args); friend class GenericDataNodeFactory; }; Running::Running(DataNodeArgument const &args) { DataNodeArgumentVector const &argList = args.getListValue(); assert(argList.size() == 2); // Expected params: (Symbol, Up) std::string const &symbol = argList[0].getStringValue(); _up = argList[1].getBooleanValue(); if (symbolIsIndex(symbol)) addAutoLink(RunningCommonTosOnly::find(this, 0, _data, symbol)); else addAutoLink(RunningCommonBBO::find(this, 0, _data, symbol)); } void Running::onWakeup(int msgId) { const double pi = _data->getPriceIncrease(); if (_up && (_data->getState() == ccAbove)) report("Running up: " + formatPrice(pi, true) + " in less than one minute.", "pi=" + formatPrice(pi), _data->getQuality()); else if ((!_up) && (_data->getState() == ccBelow)) report("Running down: " + formatPrice(pi, true) + " in less than one minute.", "pi=" + formatPrice(pi), _data->getQuality()); } ///////////////////////////////////////////////////////////////////// // Global ///////////////////////////////////////////////////////////////////// void initializeFastRunning() { GenericDataNodeFactory::sf< Running > ("RunningUp", symbolPlaceholderObject, true); GenericDataNodeFactory::sf< Running > ("RunningDown", symbolPlaceholderObject, false); }