#ifndef __FieldLists_h_ #define __FieldLists_h_ #include #include "../shared/DatabaseSupport.h" #include "DataFormat.h" /* In C++ code we usually use an enum to reference a specific field type. * * In the Record object, this is converted to a uint16_t. That's the format * used to store these on disk and to share them across the network. So the * numerical value of each enum should never change. * * The Record class doesn't know or care about the enums, only the numeric * values. The Record class is like a table in MySQL. It's just a container * and you can store different things in different tables. */ // These are the fields available in the alerts and/or top list. Most of the // fields are common to both. struct MainFields { // The struct gives us a namespace, like "enum class" would. But it doesn't // do strict type checking. In this case strict type checking causes more // problems than it solves. enum { id, alert_type, symbol, description, timestamp, price, last, spread, fake, bid_size, ask_size, relvol, quality, most_recent_close, expected_open, num, tvol, rsi_5, rsi_15, up_5, up_10, up_15, up_30, sale_condition, distance_from_nbbo, t_high, t_low, p_up_1, p_up_5, p_up_10, p_up_15, p_up_30, p_up_60, p_up_120, v_up_1, v_up_5, v_up_10, v_up_15, v_up_30, sma_2_8, sma_2_20, sma_2_200, sma_5_8, sma_5_20, sma_5_200, sma_15_8, sma_15_20, sma_15_200, range_30, range_60, range_120, qqqq_5, qqqq_10, qqqq_15, qqqq_30, qqqq_d, spy_5, spy_10, spy_15, spy_30, spy_d, dia_5, dia_10, dia_15, dia_30, dia_d, up_60, sma_60_8, sma_60_20, sma_60_200, range_15, std_5_20, std_15_20, std_60_20, alt_description, vwap, rsi_1, rsi_2, prange_5, prange_15, prange_30, prange_60, put_v, call_v, p_up_2, range_2, range_5, social_rv, up_1, up_2, bid, ask, sma_2_5, sma_5_5, sma_15_5, pm_volume, rsi_60, sma_15_130, high_pre, low_pre, limit_up, limit_down, v_up_2, sma_2_10, sma_5_10, sma_15_10, sma_60_10, }; }; struct DailyFields { enum { d_symbol, date, advol, advol_5d, list_exch, up_days, volatility, range_contraction, sma_200, sma_50, sma_20, rsi_d, bright_volatility, high_p, low_p, close_p, open_p, volume_p, high_52w, low_52w, std_20, bunny_130, consolidation_days, consolidation_high, consolidation_low, average_true_range, last_price, high_life, low_life, prev_put_volume, prev_call_volume, avg_put_call_volume, debt, assets, eps, pe_ratio, revenue, income, earnings, market_cap, beta, shares_out, yield, dividend, trailing_dividend_rate, forward_dividend_rate, high_5d, low_5d, close_5d, high_10d, low_10d, close_10d, high_20d, low_20d, close_20d, adx_14d, pdi_14d, mdi_14d, shares_per_print, short_interest, earning_day, sector, close_1y, advol_3m, sma_8, social_average, // Currently 6 weeks, was 3 weeks, want to get rid of it close_last_year, revenue_growth, earnings_growth, held_by_insiders, held_by_institutions, short_ratio, short_float, cash, enterprise_value, peg, estimated_quarterly_eps_growth, estimated_annual_eps_growth, short_growth, cusip, flt, // float. social_q, // quarterly social_m, // monthly social_w, // weekly social_d, // previous trading day high_104w, low_104w, high_13w, low_13w, high_26w, low_26w, high_39w, low_39w, avwap_2_pv, avwap_2_tv, avwap_3_pv, avwap_3_tv, avwap_4_pv, avwap_4_tv, avwap_5_pv, avwap_5_tv, sma_10, days_to_cover, interest_income, }; }; // This is mostly used when we want to copy data from our Record format into // the MySQL database. class DatabaseFieldInfo { public: enum Type { String, Int, ID, // Like Int, but always padded to 64 bits. DateTime, Date, Float, BooleanYN /* Y for yes, N for no. */ }; private: static volatile bool _initialized; static pthread_once_t _once; static std::vector< DatabaseFieldInfo > _alertFields; static std::vector< DatabaseFieldInfo > _topListFields; static std::vector< DatabaseFieldInfo > _dailyFields; static void init(); static void initOnce(); std::string _databaseName; FieldId _id; Type _type; public: std::string const &databaseName() const { return _databaseName; } Type type() const { return _type; } FieldId id() const { return _id; } void appendSql(std::string &destination, Record::Ref const &source) const; DatabaseFieldInfo(std::string const &databaseName, FieldId id, Type type) : _databaseName(databaseName), _id(id), _type(type) { } static std::vector< DatabaseFieldInfo > const &getAlertFields(); static std::vector< DatabaseFieldInfo > const &getTopListFields(); static std::vector< DatabaseFieldInfo > const &getDailyFields(); // This is ideal for a SELECT, INSERT or REPLACE statement. The result // will be something like "id,price,advol". fields cannot be empty. static std::string makeSqlFieldList(std::vector< DatabaseFieldInfo > const &fields); // Reads the current row from the database. Formats it into a record. // // The result will never be NULL. (It might be Record::EMPTY.) // // This will efficiently check for (and optimize for) a missing row, so // there's no reason to check before calling this function. static Record::Ref makeRecord(MysqlResultRef source, std::vector< DatabaseFieldInfo > const &fields); // This turns a record into a list of values suitable for an insert or // replace statement. This should be compatible with makeSqlFieldList(). // The result will look something like ("ab", 12, DEFAULT). Notice that we // are using "DEFAULT" when other servers use "NULL" This is (more or // less) the inverse of makeRecord(). static std::string makeSql(Record::Ref const &record, std::vector< DatabaseFieldInfo > const &fields); static std::string debugDump(Record const *record, std::vector< DatabaseFieldInfo > const &fields); static std::string debugDump(Record::Ref const &record, std::vector< DatabaseFieldInfo > const &fields) { return debugDump(&*record, fields); } }; #endif