#ifndef __RecentHighsAndLows_h_ #define __RecentHighsAndLows_h_ /* This data node was primarily invented to make the code work the same way * with TAL as it did with eSignal. Now, with Activ, the data might be coming * in a third way, but most of the code does not have to care. The following * notes come from the original TAL code. * * This provides access to the daily highs and lows. This offers two * advantages over going directly to the TOS data. 1) The primary advantage is * that it caches the value of yesterday's low, so we don't lose it at 4:55am. * 2) It * also caches the changes so it doesn't sound off except when the value * actually changes. * * #1 Any time the value is reported from TOS is 0 or not valid, we assume that * the value is not valid. In that case we continue to report the last good * value that we have. We only report invalid if we've never recieved a valid * value. * * Ideally we'd report that we don't know the value when the TOS data is not * valid. But that's inconsistant with our goal of not giving up a good value. * If the network goes down for a second in the morning, we don't want to * give everything up. So we do our best not to pass on the invalid notice. * * One of the primary reasons that people watch for the invalid bit is to look * for things that are now valid but were not previously valid. If the data * feed goes down for a while then goes up, everyone just displaying data * should immediately display the current value. But we don't want to report * a lot of new high and similar alerts at this time. Those alerts actually * happened while we were down, and are lost. So we keep track of the * previously down bit. * * #2 As long as we're at it, we cache the changes. Several data nodes just * watch the high or the low. The TOS data updates a lot more often than * either of these two values. We do this mostly because most of the work was * already done, so why not take advantage of it. It's less important now that * high and low have moved from L1 to TOS, but still helpful. * * Note, this only prevents us from calling the OnChange callback any more than * required. Using this data node can actually cause more calls to read the * TOS data. Every request to read from this data node requires a call to read * the TOS data, and every time the L1 data changes, this node reads the L1 * data. * * Note: As of 8/2/2009 we are reading the previous day's high and low from * a CSV file. This does the same thing as the original version, documented * above, but it's more reliable. */ #include "GenericTosData.h" class RecentHighsAndLows : public DataNode { private: bool _high; bool _tosValid; bool _previouslyValid; double _lastValue; GenericTosDataNode *_tosData; void onWakeup(int msgId); double currentInput(); RecentHighsAndLows(DataNodeArgument const &args); friend class DataNode; public: // The most recent high or low. Before the open the refers to yesterday. // If there is no valid value, return 0. double getCurrentValue(); // This refers to the underlying TOS data feed. This means that we were // connected. This does not mean that we have any interesting data. This // helps us seperate two different events: Did the actual values changes, // or are we only seeing a change because we finally connected. // // This really only makes sense in the OnChange callback. We call // notifyListeners() every time the CurrentValue changes, but not every time // that the PreviouslyValid flag changes. bool getPreviouslyValid() const { return _previouslyValid; } static DataNodeLink *find(DataNodeListener *listener, int msgId, RecentHighsAndLows *&, bool high, std::string const &symbol); }; #endif