#ifndef __CandleTimer_h_ #define __CandleTimer_h_ #include #include "../shared/ThreadSafeRefCount.h" class CandleTimer { public: // These objects are likely to be shared, possibly across threads. One will // be created for the prototype, and can be used by each of the instances. typedef TSRefCount< CandleTimer > Ref; // How many rows should we be displaying. This assumes that we display a row // as soon as the corresponding candle closes, no sooner. // // Note 0 means the table should be empty. 2 means that we should have two // rows. Those would be rows #0 and #1. Row #2 will be used by the next // complete candle. virtual int getTotalRowCount(time_t time) const =0; // This says how many candles have at least started. This lets you start // something that you are likely redo later. virtual int getPreviewRowCount(time_t time) const =0; // This gives us the start and end times for a row. The first row is 0. // The times are perfect for CandleManager::get(). virtual void getTimes(int row, time_t &start, time_t &end) const =0; static const std::string DAILY; static const std::string INTRADAY; // What type of data to request. DAILY and INTRADAY are obvious choices. virtual std::string dataType() const =0; virtual ~CandleTimer() { } virtual std::string debugDump() const; // Create a new one just like the current one, but change the offset. // I.e. I have the right settings to show me 100 rows right now, but the // user scrolled back, so I need to add 50 more at the beginning. virtual Ref reanchor(int completeRows, time_t atDateTime) const =0; }; // This is a very simple version aimed mostly at testing. // Each candle is one minute long, // only works during market hours, // and only works for one day. class SimpleCandleTimer : CandleTimer { private: const time_t _offset; public: virtual int getTotalRowCount(time_t time) const; virtual int getPreviewRowCount(time_t time) const; virtual void getTimes(int row, time_t &start,time_t &end) const; virtual std::string dataType() const { return INTRADAY; } virtual std::string debugDump() const; virtual Ref reanchor(int completeRows, time_t atDateTime) const { return NULL; } // No obvious answer. SimpleCandleTimer(time_t startDate); static CandleTimer::Ref Tomorrow(); static CandleTimer::Ref Today(); static CandleTimer::Ref Round(); }; class IntradayCandleTimer : public CandleTimer { private: // Always midnight on a Monday. The date is based on the oldest data we // have, not the current request. static time_t _baseDate; static void initBaseDate(); // The start time of the first candle of the day, and the end time of the // last candle of the day. If all the candles were the same size, these // would be not be necessary. These are helpful with 60 minute candles, // where typically we have 6 full candles and 1 half candle. int _startTime; int _endTime; // This is where the first candle starts if it's a full candle. If the first // candle is short, then we tack the extra minutes onto the beginning and // ask where would it start. If we are looking at N minute candles, the // second candle starts at midnight + _dailyOffset + N * 60. int _dailyOffset; int _secondsPerCandle; // _rowOffset = 0 means that _baseDate + _dailyOffset is the start of the // first candle. (Or it would be if the first candle was a normal size.) 1 // means that the first row is one row after that. If N is small, _rowOffset // = N means that the first row starts at _baseDate + _dailyOffset + N * // _secondsPerCandle. However, N can span multiple days, in which case that // last formula is not right. int _rowOffset; int _candlesPerDay; int getRowCount(time_t time, bool completeOnly) const; // Used with reanchor(). IntradayCandleTimer(IntradayCandleTimer const &other, int completeRows, time_t atDateTime); public: virtual int getTotalRowCount(time_t time) const; virtual int getPreviewRowCount(time_t time) const; virtual void getTimes(int row, time_t &start,time_t &end) const; virtual std::string dataType() const { return INTRADAY; } virtual std::string debugDump() const; virtual Ref reanchor(int completeRows, time_t atDateTime) const; IntradayCandleTimer(int completeRows, // How many rows to start with. time_t atDateTime, // We expect completeRows to be done at this time. 0 means now. int minutesPerCandle, // Size of most candles. int startOffset, // 0 means start at the open, 1 means start one minute before. int endOffset, // 0 means end at the close, 1 means end one minute later. // The missing space will be divided between the first // and last candle. But you can't do anything else. // I.e., if you divide 6.5 hours into 1 hour candles, you // can make the first one 44 minutes and the last one 46 // minutes. But you can't make the first one 61 minutes. // If you divide 6.5 hours into 30 minute candles, this // value is ignored. A very large value will mean the // first candle is full. A very small value will mean // that the last candle is full. int firstCandleSize); }; class DailyCandleTimer : public CandleTimer { private: // the preferred / canonical time is always at the open. static time_t _baseDate; // _baseDate is always midnight on a Monday static void initBaseDate(); // 0 means that _baseDate is the first row. // 1 means that _baseDate comes one row before the first row. Stated another // way, the first row is one weekday after _baseDate. int _rowOffset; int getRowCount(time_t time, int cutoff) const; public: // This updates at the close. virtual int getTotalRowCount(time_t time) const; // This updates at the open. virtual int getPreviewRowCount(time_t time) const; // This returns the open and the close of the given day. virtual void getTimes(int row, time_t &start,time_t &end) const; virtual std::string dataType() const { return DAILY; } virtual std::string debugDump() const; virtual Ref reanchor(int completeRows, time_t atDateTime) const; // If lastTime is 0, then then we use the current time. // This is meant to match getTotalRowCount(), not getPreviewRowCount(). // if you call getTotalRowCount(lastTime), you'd expect to get rowCount // as a result. DailyCandleTimer(int rowCount, time_t lastTime = 0); }; class WeeklyCandleTimer : public CandleTimer { private: static time_t _baseDate; // _baseDate is always midnight on a Monday static void initBaseDate(); // 0 means that _baseDate is the first row. // 1 means that _baseDate comes one row before the first row. Stated another // way, the first row is one week after _baseDate. int _rowOffset; enum class Cutoff { Total, Preview }; int getRowCount(time_t time, Cutoff cutoff) const; public: // This updates Friday at the close. virtual int getTotalRowCount(time_t time) const; // This updates Monday at the open. virtual int getPreviewRowCount(time_t time) const; // This returns the time of the open on Monday and the time of the close // on Friday. virtual void getTimes(int row, time_t &start,time_t &end) const; // The names are a bit confusing. DailyCandleTimer, WeeklyCandleTimer, // and MonthlyCandleTimer all get their data from DailyCandles. // IntradayCandleTimer gets its data from OneMinuteCanles. virtual std::string dataType() const { return DAILY; } virtual std::string debugDump() const; virtual Ref reanchor(int completeRows, time_t atDateTime) const; // If lastDay is 0, then then we use the current time. // This is meant to match getTotalowCount(), not getPreviewRowCount(). // If you call getTotalRowCount(lastTime), you'd expect to get rowCount // as a result. WeeklyCandleTimer(int rowCount, time_t lastTime = 0); }; class MonthlyCandleTimer : public CandleTimer { private: // The base date is January 1900. This is somewhat arbitary. When using // localtime(), mktime() and related functions, January is stored as month 0 // and 1900 is stored as year 0. // // 0 for _rowOffset means that we want January 1900 to be our first row, // row 0. // 14 (12 + 2) for _rowOffset means that we want January 1900 to be 14 rows // before our first row. So our first row, row 0, would be March 1901. int _rowOffset; time_t getStartTime(int rowCount) const; time_t getEndTime(int rowCount) const; enum class Cutoff { Start, End }; time_t getTime(int rowCount, Cutoff cutoff) const; int getRowCount(time_t time, Cutoff cutoff) const; public: // This updates at the close. virtual int getTotalRowCount(time_t time) const; // This updates at the open. virtual int getPreviewRowCount(time_t time) const; // This returns the open and the close of the given day. virtual void getTimes(int row, time_t &start,time_t &end) const; virtual std::string dataType() const { return DAILY; } virtual std::string debugDump() const; virtual Ref reanchor(int completeRows, time_t atDateTime) const; // If lastDay is 0, then then we use the current time. // This is meant to match getTotalRowCount(), not getPreviewRowCount(). // if you call getTotalRowCount(lastTime), you'd expect to get rowCount // as a result. MonthlyCandleTimer(int rowCount, time_t lastTime = 0); }; #endif