#include #include "../../shared/SimpleLogFile.h" #include "../../shared/MarketHours.h" #include "../../shared/ThreadMonitor.h" #include "SynchronizedTimers.h" //////////////////////////////////////////////////////////////////// // SynchronizedTimer //////////////////////////////////////////////////////////////////// void SynchronizedTimer::setTimeImpl(time_t remoteTime) { if (remoteTime >= _nextToReport) { TclList debug; debug<<__FILE__<<__LINE__<<__FUNCTION__ <setTimeImpl(remoteTime); } void SynchronizedTimer::safeSetTime(time_t remoteTime) { // This was a big deal in TAL. We definately saw some seriously messed up // stuff. I don't know if we will see this in Activ or not. //TclList debug; //debug<<__FILE__<<__LINE__<<__FUNCTION__ // <getSubmitTime(); const time_t error = remoteTime - now; // We only worry about prints that are in the future. Prints that are in // the past are actually valid, and are filtered out later. if (error > MAX_ERROR) { static int fishyPrintCount = 0; static int displayFishyPrintCount = 0; static time_t worstFishyPrint = 0; fishyPrintCount++; if ((fishyPrintCount >= displayFishyPrintCount) || ( error > worstFishyPrint)) { TclList msg; msg<<"SynchronizedTimers.C"<<"SynchronizedTimer::safeSetTime()" <<"fishyPrintCount"< worstFishyPrint) worstFishyPrint = error; displayFishyPrintCount = fishyPrintCount * 2; } ThreadMonitor::find().increment("SynchronizedTimers far future"); } else if (error > 0) { // DTN is almost always about a half second ahead of local time. That // caused problems because a lot of alerts went off at 11:59:59 when we'd // expect to see them at noon. // // This logic (using external time rather than local time to organize the // candles) was originally written based on the assumption that we'd // typically be slightly behind, getting the data a little late. The test // for early prints, listed above, was based on a handleful of completely // crazy prints. Those are clearly mistakes and need to be thrown away. // if a print is just .4 seconds ahead, assume that our clocks are not all // in sync, or something like that. // // We can't just ignore these prints or we'd get almost no time updates! // This seems to make the code work best. setTime(now); ThreadMonitor::find().increment("SynchronizedTimers near future"); } else { setTime(remoteTime); ThreadMonitor::find().increment("SynchronizedTimers normal"); } } SynchronizedTimer::SynchronizedTimer(DataNodeArgument const &args) : _startTime(0), _nextToReport(0), _minutes(BarCounter::UNKNOWN_TIME), _timePhase(BarCounter::tpNotActive) { // The instance variable is used by producers. Consumers use find() just // like for any normal data node. instance = this; } __thread SynchronizedTimer *SynchronizedTimer::instance = NULL; //////////////////////////////////////////////////////////////////// // BarCounter //////////////////////////////////////////////////////////////////// const int BarCounter::UNKNOWN_TIME = std::numeric_limits< int >::max(); BarCounter::BarCounter(DataNodeArgument const &args) : _minutesPerBar(args.getIntValue()), _offset(0), _currentBar(UNKNOWN_TIME), _previousBar(UNKNOWN_TIME), _lastTransition(bctNone), _ignoreIfBefore(0), _timePhase(tpNotActive), _notifyRequired(false) { assert(_minutesPerBar > 0); addAutoLink(SynchronizedTimer::find(this, 0, _basicTimer)); } DataNodeLink *BarCounter::find(DataNodeListener *listener, int msgId, BarCounter *&node, int minutesPerBar) { return findHelper(listener, msgId, node, minutesPerBar); } //int BarCounter::getBarsPerDay() const //{ //} bool BarCounter::isUpdating() const { return (_basicTimer->getTimePhase() != tpNotActive) && (_basicTimer->getMinutes() >= 0) && (_basicTimer->getMinutes() <= MINUTES_OF_TRADING) && (((_basicTimer->getMinutes() % _minutesPerBar) == _offset) || (_basicTimer->getMinutes() == 0)); } void BarCounter::onWakeup(int msgId) { TclList debug; //debug<<__FILE__<<__LINE__<<__FUNCTION__ // <<"_timePhase"<<_basicTimer->getTimePhase() // <<"getMinutes()"<<_basicTimer->getMinutes() // <<"_minutesPerBar"<<_minutesPerBar; //sendToLogFile(debug); if (_basicTimer->getTimePhase() == tpUpdate) { _notifyRequired = false; _timePhase = tpUpdate; if ((_basicTimer->getMinutes() < 0) || (_basicTimer->getMinutes() >= MINUTES_OF_TRADING)) { if ((_lastTransition != bctNone) && (_lastTransition != bctEnd)) { _currentBar = UNKNOWN_TIME; _lastTransition = bctEnd; notifyListeners(); _notifyRequired = true; } } else { _ignoreIfBefore = _basicTimer->getStartTime(); const int newBar = (_basicTimer->getMinutes() + _offset) / _minutesPerBar; if (newBar != _currentBar) { if (_lastTransition == bctNone) _lastTransition = bctFirst; else if (newBar == _currentBar + 1) _lastTransition = bctNext; else _lastTransition = bctSkip; _previousBar = _currentBar; _currentBar = newBar; notifyListeners(); _notifyRequired = true; } } } else if (_basicTimer->getTimePhase() == tpNotify) if (_notifyRequired) { //debug.clear(); //debug<<"notify/notify"; //sendToLogFile(debug); _timePhase = tpNotify; notifyListeners(); } _timePhase = tpNotActive; }