#include #include "../alert_framework/AlertBase.h" #include "../data_framework/SimpleMarketData.h" #include "../data_framework/GenericL1Data.h" #include "../../shared/MarketHours.h" #include "../misc_framework/CsvFileDataNodes.h" #include "LocksAndCrosses.h" /* These are very fast, very noisy alerts. Most of the logic is just for * filtering. These made more sense, maybe, a few years back where the * NASDAQ worked differently and they happened less frequently. But people * ask for them, so... */ //////////////////////////////////////////////////////////////////// // LockedOrCrossed //////////////////////////////////////////////////////////////////// class LockedOrCrossed : public Alert { public: enum State { locsBad, locsWaiting, locsActive, locsOvershot, locsOvershotPrimed }; private: GenericL1DataNode *_l1Data; State _state; time_t _lastEndTime; void onWakeup(int msgId); protected: LockedOrCrossed(DataNodeArgument const &args); L1Data const &getL1() { return _l1Data->getCurrent(); } bool l1Valid() { return _l1Data->getValid(); } virtual State getState(L1Data const &data) =0; virtual void reportNow() =0; virtual bool higherQuality(); }; bool LockedOrCrossed::higherQuality() { return false; } LockedOrCrossed::LockedOrCrossed(DataNodeArgument const &args) : _state(locsBad), _lastEndTime(0) { addAutoLink(GenericL1DataNode::find(this, 0, _l1Data, args.getStringValue())); } inline bool primed(LockedOrCrossed::State state) { return (state == LockedOrCrossed::locsWaiting) || (state == LockedOrCrossed::locsOvershotPrimed); } void LockedOrCrossed::onWakeup(int msgId) { State previousState = _state; _state = locsBad; if (_l1Data->getValid()) { L1Data const ¤t = _l1Data->getCurrent(); if ((current.bidPrice > 0) && (current.askPrice > 0)) _state = getState(current); } if ((_state == locsOvershot) && primed(previousState)) _state = locsOvershotPrimed; else if ((_state == locsActive) && higherQuality()) reportNow(); else if ((_state == locsActive) && (previousState != locsActive)) { const time_t idleTime = getSubmitTime() - _lastEndTime; if (idleTime > MARKET_HOURS_MINUTE*5) reportNow(); } if (!(primed(_state) && primed(previousState))) _lastEndTime = getSubmitTime(); } //////////////////////////////////////////////////////////////////// // MarketLocked //////////////////////////////////////////////////////////////////// class MarketLocked : public LockedOrCrossed { private: MarketLocked(DataNodeArgument const &args) : LockedOrCrossed(args) { } friend class GenericDataNodeFactory; protected: State getState(L1Data const &data); void reportNow() { report("Market Locked"); } }; LockedOrCrossed::State MarketLocked::getState(L1Data const &data) { if (data.bidPrice == data.askPrice) return locsActive; if (data.bidPrice > data.askPrice) return locsOvershot; return locsWaiting; } //////////////////////////////////////////////////////////////////// // MarketCrossedBase //////////////////////////////////////////////////////////////////// class MarketCrossedBase : public LockedOrCrossed { public: enum CrossType { mctDown, mctUp, mctOther }; private: std::string _primaryMarket; double _highestReportedCross, _currentCross; CrossType _crossType; MarketCrossedBase(DataNodeArgument const &args); friend class GenericDataNodeFactory; protected: State getState(L1Data const &data); void reportNow(); bool higherQuality(); public: CrossType getCrossType() const { return _crossType; } }; MarketCrossedBase::MarketCrossedBase(DataNodeArgument const &args) : LockedOrCrossed(args), _highestReportedCross(std::numeric_limits< double >::max()) { const std::string listedExchange = getListedExchange(args.getStringValue()); if (listedExchange == s_NYSE) _primaryMarket = nyseOnDataFeed(); else if (listedExchange == s_AMEX) _primaryMarket = amexOnDataFeed(); else if (listedExchange == s_NASD) _primaryMarket = nasdaqOnDataFeed(); else if (listedExchange == s_ARCA) _primaryMarket = arcaOnDataFeed(); } LockedOrCrossed::State MarketCrossedBase::getState(L1Data const &data) { if (data.bidPrice > data.askPrice) { _currentCross = data.bidPrice - data.askPrice; return locsActive; } return locsWaiting; } static const std::string mcMessage[] = { "Market Crossed Down", "Market Crossed Up", "Market Crossed" }; void MarketCrossedBase::reportNow() { _crossType = mctOther; if (l1Valid() && !_primaryMarket.empty()) { const bool bidPrimary = getL1().bidExchange == _primaryMarket; const bool askPrimary = getL1().askExchange == _primaryMarket; if (bidPrimary && !askPrimary) _crossType = mctDown; else if (askPrimary && !bidPrimary) _crossType = mctUp; } report(mcMessage[_crossType], _currentCross); _highestReportedCross = _currentCross; } bool MarketCrossedBase::higherQuality() { return _currentCross > _highestReportedCross; } //////////////////////////////////////////////////////////////////// // MarketCrossedSelector //////////////////////////////////////////////////////////////////// class MarketCrossedSelector : public Alert { private: MarketCrossedBase::CrossType _crossType; MarketCrossedBase *_base; void onWakeup(int msgId); MarketCrossedSelector(DataNodeArgument const &args); friend class GenericDataNodeFactory; }; MarketCrossedSelector::MarketCrossedSelector(DataNodeArgument const &args) { DataNodeArgumentVector const &argList = args.getListValue(); assert(argList.size() == 2); // Expected params: (Symbol, CrossType) _crossType = (MarketCrossedBase::CrossType)argList[1].getIntValue(); addAutoLink(findGeneric(this, 0, _base, argList[0])); } void MarketCrossedSelector::onWakeup(int msgId) { if (_base->getCrossType() == _crossType) { double quality; bool qualityValid; _base->getDouble(qualityValid, quality); if (qualityValid) report(_base->getMsg(), quality); else report(_base->getMsg()); } } //////////////////////////////////////////////////////////////////// // Global //////////////////////////////////////////////////////////////////// void initializeLocksAndCrosses() { GenericDataNodeFactory::storeStandardFactory< MarketLocked >("MarketLocked"); GenericDataNodeFactory::sf< MarketCrossedSelector > ("MarketCrossedDown", symbolPlaceholderObject, MarketCrossedBase::mctDown); GenericDataNodeFactory::sf< MarketCrossedSelector > ("MarketCrossedUp", symbolPlaceholderObject, MarketCrossedBase::mctUp); GenericDataNodeFactory::sf< MarketCrossedSelector > ("MarketCrossed", symbolPlaceholderObject, MarketCrossedBase::mctOther); }