#pragma once typedef char ExchangeCode[8]; typedef char SymbolString[20]; typedef uint8_t byte; typedef unsigned long long int ticks_t; constexpr auto NxTCF_NOLAST = 0x01; ////////////////////////////////////////////////////////////////////// ///////// Exchange constants////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// enum NxEXCH { NxEXCH_NQEX = 1, NxEXCH_NQAD = 2, NxEXCH_NYSE = 3, NxEXCH_AMEX = 4, NxEXCH_CBOE = 5, NxEXCH_ISEX = 6, NxEXCH_PACF = 7, NxEXCH_CINC = 8, NxEXCH_PHIL = 9, NxEXCH_OPRA = 10, NxEXCH_BOST = 11, NxEXCH_NQNM = 12, NxEXCH_NQSC = 13, NxEXCH_NQBB = 14, NxEXCH_NQPK = 15, NxEXCH_NQAG = 16, NxEXCH_CHIC = 17, NxEXCH_TSE = 18, NxEXCH_CDNX = 19, NxEXCH_CME = 20, NxEXCH_NYBT = 21, NxEXCH_NYBA = 22, NxEXCH_COMX = 23, NxEXCH_CBOT = 24, NxEXCH_NYMX = 25, NxEXCH_KCBT = 26, NxEXCH_MGEX = 27, NxEXCH_WCE = 28, NxEXCH_ONEC = 29, NxEXCH_DOWJ = 30, NxEXCH_NNEX = 31, NxEXCH_SIMX = 32, NxEXCH_FTSE = 33, NxEXCH_EURX = 34, NxEXCH_ENXT = 35, NxEXCH_DTN = 36, NxEXCH_LMT = 37, NxEXCH_LME = 38, NxEXCH_IPEX = 39, NxEXCH_MSE = 40, NxEXCH_WSE = 41, NxEXCH_ISLD = 42, NxEXCH_MDAM = 43, NxEXCH_CLRP = 44, NxEXCH_BARK = 45, NxEXCH_TULL = 46, NxEXCH_CQTS = 47, NxEXCH_HOTS = 48, NxEXCH_EUUS = 49, NxEXCH_EUEU = 50, NxEXCH_ENCM = 51, NxEXCH_ENID = 52, NxEXCH_ENIR = 53, NxEXCH_CFE = 54, NxEXCH_PBOT = 55, NxEXCH_HWTB = 56, NxEXCH_NQNX = 57, NxEXCH_BTRF = 58, NxEXCH_NTRF = 59, NxEXCH_BATS = 60, NxEXCH_NYLF = 61, NxEXCH_PINK = 62, NxEXCH_BATY = 63, NxEXCH_EDGE = 64, NxEXCH_EDGX = 65, }; std::string regionalExgFromNxCore(NxEXCH exchID) { switch(exchID) { case NxEXCH_NQEX: return "NASD"; case NxEXCH_NQAD: return "NASD"; case NxEXCH_NQNM: return "NASD"; case NxEXCH_NQSC: return "NASD"; case NxEXCH_NYSE: return "NYSE"; case NxEXCH_AMEX: return "AMEX"; case NxEXCH_CBOE: return "CBOE"; case NxEXCH_ISEX: return "ISEX"; case NxEXCH_PACF: return "ARCA"; case NxEXCH_CINC: return "CINC"; case NxEXCH_PHIL: return "PHIL"; case NxEXCH_BOST: return "BOST"; case NxEXCH_NQBB: return "OTC"; case NxEXCH_NQPK: return "PINK"; case NxEXCH_CHIC: return "CHIC"; case NxEXCH_TSE : return "CAT"; case NxEXCH_CDNX: return "CAV"; case NxEXCH_BATS: return "BATS"; case NxEXCH_BATY: return "BATS"; case NxEXCH_NTRF: return "NTRF"; case NxEXCH_EDGE: return "EDGA"; case NxEXCH_EDGX: return "EDGX"; default : return ""; } } std::string listedExgFromNxCore(char symbolType, NxEXCH exchID) { if (symbolType == 'i') return "$NDX"; switch (exchID) { case NxEXCH_NQEX: return "NASD"; case NxEXCH_NQAD: return "NASD"; case NxEXCH_NQNM: return "NASD"; case NxEXCH_NQSC: return "NASD"; case NxEXCH_NYSE: return "NYSE"; case NxEXCH_AMEX: return "AMEX"; case NxEXCH_PACF: return "ARCA"; case NxEXCH_NQBB: return "OTC"; case NxEXCH_NQPK: return "PINK"; case NxEXCH_TSE : return "CAT"; case NxEXCH_CDNX: return "CAV"; case NxEXCH_BATS: return "BATS"; case NxEXCH_BATY: return "BATS"; default : return ""; } } struct KafkaDataV2 { byte tradePriceType; int32_t price; ticks_t time; // this comes in as "ticks" from NxCore rather than the time_t we are used to in C++ int32_t size; ExchangeCode exchange; byte priceFlags; byte tradeCondition; byte conditionFlags; int32_t tickVolume; int64_t totalVolume; int32_t open, high, low; char symbolType; SymbolString symbol; int32_t last; ushort listedExchangeCode; ushort reportingExchangeCode; byte quotePriceType; byte quoteCondition; int32_t bidSize; int32_t bid; ushort bidExchange; int32_t askSize; int32_t ask; ushort askExchange; } __attribute__((__packed__)); // This implementation is based off of NxCore documentation. We find that doing the math this way results // in some rounding issues. double nxCorePriceToDoubleOrig(const int32_t &price, const byte &priceType) { switch (priceType) { case 1: return price * 0.000000001; case 2: return price * 0.00000001; case 3: return price * 0.0000001; case 4: return price * 0.000001; case 5: return price * 0.00001; case 6: return price * 0.0001; case 7: return price * 0.001; case 8: return price * 0.01; case 9: return price * 0.1; case 10: return price * 1.0; case 11: return price * 10.0; case 12: return price * 100.0; case 13: return price * 1000.0; case 14: return price * 10000.0; case 15: return price * 100000.0; case 16: return price * 1000000.0; case 17: return price * 10000000.0; case 18: return price * 100000000.0; case 19: return price * 1000000000.0; case 20: return price * 0.0009765625; case 21: return price * 0.001953125; case 22: return price * 0.00390625; case 23: return price * 0.0078125; case 24: return price * 0.015625; case 25: return price * 0.03125; case 26: return price * 0.0625; case 27: return price * 0.125; case 28: return price * 0.25; case 29: return price * 0.50; case 30: return price * 1.0; case 31: return price * 2.0; case 32: return price * 4.0; case 33: return price * 8.0; case 34: return price * 16.0; case 35: return price * 32.0; case 36: return price * 64.0; case 37: return price * 126.0; case 38: return price * 256.0; case 39: return price * 512.0; default: return price * 0.0; // Undefined behavior } } // standard trick using an int type to round a double to 6 decimals in a consistent repeatable way double nxCorePriceToDouble(const int32_t &price, const byte &priceType) { double a = nxCorePriceToDoubleOrig(price, priceType); int64_t c = (int64_t)(a * 10000 + 0.5d); double b = c/10000.0; return b; } // Convert C# DateTime to C++ date time copied/modified from // https://www.codeproject.com/Tips/694874/Exchange-Date-Time-between-Native-Cplusplus-and-Cs time_t fromDateTimeTicks(ticks_t time) { // Thursday, January 01, 1970 12:00:00 AM const unsigned long long int unixEpoch = 0x089f7ff5f7b58000; time_t t = (time_t)((time - unixEpoch) / 10000000); // tm = gmtime(&t); // printf("%s \n", asctime(tm)); return t; }