#include #include #include #include #include #include #include #include #include "DataFromSpryWare.h" #include "DataFormats.h" #include #include #include #include #include #include "../../for_spryware/SpryWareSimple.h" #include "../../../shared/MiscSupport.h" #include "../../data_framework/MarketHours.h" #define TZ_OFFSET -3 time_t dateFromSpryWare(Database::Date *date) { struct tm t; t.tm_year = date->GetYear() - 1900; t.tm_mon = date->GetMonth() - 1; t.tm_mday = date->GetDay(); t.tm_hour = 0; t.tm_min = 0; t.tm_sec = 0; t.tm_isdst = -1; return mktime(&t); } bool symbolIsIndex(const std::string &symbol) { if (symbol.size() > 0) { if (symbol[0] == '$') return true; } return false; } void DataFromSpryWare::connect() { std::string str; // Create the directory object pDirectory = CreateMisDirectory(); if (0==pDirectory) { fprintf(stderr,"Error: Unable to Create MisDirectory\n"); return; } // Open and parse the config file if (0 == pDirectory->GetConfigFile(str) && true==File::IsExist(str.c_str())) { fprintf(stderr,"Loaded config file %s\n", str.c_str()); } else if (0 == pDirectory->GetConfigFile(str) && false==File::IsExist(str.c_str())) fprintf(stderr,"Config file %s does not exist\n", str.c_str()); connectTable(pTableHistory, keyHistory, recordHistory, TABLE_EQUITY_HISTORY); connectTable(pTable1Min, key1Min, record1Min, TABLE_EQUITY_BAR); connectTable(pTableCorporateActions, keyCorporateActions, recordCorporateActions, TABLE_CORPORATE_ACTIONS, 1); connectTable(pTableFundamentalPrice, keyFundamentalPrice, recordFundamentalPrice, TABLE_FUNDAMENTAL_PRICE); } void DataFromSpryWare::disconnect() { pDirectory->Disconnect(pTable1Min); pDirectory->Disconnect(pTableHistory); pDirectory->Disconnect(pTableCorporateActions); pDirectory->Disconnect(pTableFundamentalPrice); delete pDirectory; } void DataFromSpryWare::connectTable(Database::ITable * &pTable, Database::Key * &key, Database::Record * &record, const std::string &tableName, const int &indexNumber /* = 0 */) { std::string str; std::string userName; std::string host; std::string passWord; std::string domain; unsigned rc = 0; // Create an instance of the table, and attempt to open it rc = pDirectory->Connect(tableName.c_str(), pTable, domain.c_str(), userName.c_str(), passWord.c_str(), host.c_str()); if((!pTable) || (rc != RETURN_CODE_SUCCESS)) { pTable->GetHostName(str); std::cerr << "Unable to Connect to " << tableName << ": " << rc << " - " << MIS::ERR::ToString(rc) << std::endl; exit(1); } else { pTable->GetHostName(str); std::cerr << "Connected to " << tableName << " on " << str << std::endl; record = new Database::Record; record->Initialize(pTable); key = new Database::Key; key->Initialize(pTable, indexNumber); } } void DataFromSpryWare::getDailyBars(const std::string &symbol, BarList &bars) { std::string str; std::string spryWareSymbol = symbolToSpryWare(symbol); std::string barSymbol; BarData bar; unsigned int rc = 0; Database::IField *field; Database::Value *value; Database::Date *date; Database::Sku *sku; Database::NativeType *volume; Database::IndexPosition position = {0}; Database::Date yearAgo, lastDate; unsigned year, month, day; yearAgo.Now(); lastDate.Now(); yearAgo.Get(year, month, day); //TODO: fix this to be a little more smart... at least round to the nearest midnight first. //yearAgo.Set(year - 1, month - 1, day); lastDate.Set(year-1000, month, day); //std::cout << yearAgo.ToString() << " - year " << year << ", month " << month << ", day" << day // << '\t' <FromString(spryWareSymbol); assert(rc == RETURN_CODE_SUCCESS); rc = pTableHistory->GetEqual(*keyHistory, *recordHistory, false, &position); if (rc != RETURN_CODE_SUCCESS) { std::cerr << "Failed to get Daily Bars for \'" << spryWareSymbol << "\': " << rc << " - "<< MIS::ERR::ToString(rc) << std::endl; return; } while (rc == RETURN_CODE_SUCCESS) { bool dataError = false; rc = recordHistory->GetField(MIS::FID::CLOSE_DATE , field); assert(rc == RETURN_CODE_SUCCESS); date = dynamic_cast< Database::Date * >(field); assert(date); if (*date <= lastDate) { std::cerr << symbol << " - Out of Order Daily Bar - Current: " << date->ToString() << " vs Last: " << lastDate.ToString() << std::endl; dataError = true; } bar.startTime = dateFromSpryWare(date); rc = recordHistory->GetField(MIS::FID::SKU, field); assert(rc == RETURN_CODE_SUCCESS); sku = dynamic_cast< Database::Sku * >(field); assert(sku); barSymbol = sku->GetSymbol(); lastDate = *date; assert(rc == RETURN_CODE_SUCCESS); if (dataError) { rc = pTableHistory->GetNext(*keyHistory, *recordHistory, false, &position); continue; } //if (*date > yearAgo) //{ rc = recordHistory->GetField(MIS::FID::OPEN , field); assert(rc == RETURN_CODE_SUCCESS); value = dynamic_cast< Database::Value * >(field); assert(value); rc = value->Get(bar.open); assert(rc == RETURN_CODE_SUCCESS); rc = recordHistory->GetField(MIS::FID::HIGH , field); assert(rc == RETURN_CODE_SUCCESS); rc = value->Get(bar.high); assert(rc == RETURN_CODE_SUCCESS); rc = recordHistory->GetField(MIS::FID::LOW , field); assert(rc == RETURN_CODE_SUCCESS); rc = value->Get(bar.low); assert(rc == RETURN_CODE_SUCCESS); rc = recordHistory->GetField(MIS::FID::CLOSE , field); assert(rc == RETURN_CODE_SUCCESS); rc = value->Get(bar.close); assert(rc == RETURN_CODE_SUCCESS); rc = recordHistory->GetField(MIS::FID::VOLUME, field); assert(rc == RETURN_CODE_SUCCESS); volume = dynamic_cast< Database::NativeType * >(field); assert(volume); rc = volume->Get(bar.volume); assert(rc == RETURN_CODE_SUCCESS); bar.printCount = 0; bars.push_back(bar); //} rc = pTableHistory->GetNext(*keyHistory, *recordHistory, false, &position); } assert(rc == RETURN_CODE_END_OF_DB); } void DataFromSpryWare::get1MinBars(const std::string &symbol, BarList &bars) { std::string str; std::string spryWareSymbol = symbolToSpryWare(symbol); std::string barSymbol; BarData bar1Min; unsigned int rc = 0; Database::IField *field; Database::Date date; Database::IntradayBar *bar; Database::Price price; Database::IndexPosition position = {0}; Database::Date lastDate; unsigned lastTime = 0, currentTime; unsigned hour, minute, second; struct tm t; bars.clear(); lastDate.Now(); lastDate.Set(lastDate.GetYear() - 1000, 1, 1); rc = key1Min->FromString(spryWareSymbol); assert(rc == RETURN_CODE_SUCCESS); rc = pTable1Min->GetEqual(*key1Min, *record1Min, false, &position); if (rc != RETURN_CODE_SUCCESS) { std::cout << "Failed to get 1 Minute Bars for \'" << spryWareSymbol << "\': " << rc << " - "<< MIS::ERR::ToString(rc) << std::endl; return; } while (rc == RETURN_CODE_SUCCESS) { rc = record1Min->GetField(MIS::FID::INTRADAY_BAR , field); assert(rc == RETURN_CODE_SUCCESS); bar = dynamic_cast< Database::IntradayBar * >(field); assert(bar); bar->GetDate(date); t.tm_year = date.GetYear() - 1900; t.tm_mon = date.GetMonth() - 1; t.tm_mday = date.GetDay(); bar->GetTime(hour, minute, second); currentTime = 60 * 60 * (hour + TZ_OFFSET) + 60*minute + second; t.tm_hour = hour + TZ_OFFSET; t.tm_min = minute; t.tm_sec = second; t.tm_isdst = -1; bar1Min.startTime = mktime(&t); if ((date < lastDate) || (date == lastDate) && (lastTime > currentTime)) { std::cout << symbol << " - Out of Order 1 Minute Bar, Current: " << date.ToString() << ':' << currentTime << " vs Last: " << lastDate.ToString() << ':' << lastTime << std::endl; } bar->GetOpen(price); price.GetPrice(bar1Min.open); bar->GetHigh(price); price.GetPrice(bar1Min.high); bar->GetLow(price); price.GetPrice(bar1Min.low); bar->GetClose(price); price.GetPrice(bar1Min.close); bar1Min.volume = (unsigned int) bar->GetVolume(); bar1Min.printCount = (unsigned int) bar->GetTickCount(); // We sometimes get a final bar of the day right at the close that appears // to be within market hours so we combine it with the 12:59:00 bar if(currentTime == MARKET_HOURS_CLOSE && lastTime == MARKET_HOURS_CLOSE - MARKET_HOURS_MINUTE && lastDate == date) { BarData &previousBar = bars.back(); previousBar.high = std::max(previousBar.high, bar1Min.high); previousBar.low = std::min(previousBar.low, bar1Min.low); previousBar.close = bar1Min.close; previousBar.volume += bar1Min.volume; previousBar.printCount += bar1Min.printCount; } else { // In case we get the 1:00:00 bar but don't have a 12:59:00 bar // I don't know if this case will ever actually happen if(currentTime == MARKET_HOURS_CLOSE) { bar1Min.startTime -= MARKET_HOURS_MINUTE; } bars.push_back(bar1Min); } lastDate = date; lastTime = currentTime; rc = pTable1Min->GetNext(*key1Min, *record1Min, false, &position); } assert(rc == RETURN_CODE_END_OF_DB); } void DataFromSpryWare::getCorporateActions(const std::string &symbol, CorporateActions &corporateActions) { std::string spryWareSymbol = symbolToSpryWare(symbol); Database::IndexPosition position = {0}; Database::CorporateAction *corporateAction; Database::Value dividendValue; Database::IField *field; double splitFactorSpryWare; Database::Date *date; Split split, previousSplit; previousSplit.date = 0; previousSplit.splitFactor = 1.0; bool first = true; corporateActions.splits.clear(); int rc = keyCorporateActions->FromString(spryWareSymbol); assert(rc == RETURN_CODE_SUCCESS); rc = pTableCorporateActions->GetFirstPartial(*keyCorporateActions, 32, *recordCorporateActions, false, &position); if (rc != RETURN_CODE_SUCCESS) { assert(rc == RETURN_CODE_NOT_FOUND); return; } while (rc == RETURN_CODE_SUCCESS) { rc = recordCorporateActions->GetField(MIS::FID::CORPORATE_ACTION, field); assert(rc == RETURN_CODE_SUCCESS); corporateAction = dynamic_cast< Database::CorporateAction * >(field); if (corporateAction->IsDividend()) { uint32_t dividendType; rc = corporateAction->GetDividendType(dividendType); assert(rc == RETURN_CODE_SUCCESS); if(dividendType == MIS::DVT::SPLIT) { rc = corporateAction->GetDividend(dividendValue); assert(rc == RETURN_CODE_SUCCESS); dividendValue.Get(splitFactorSpryWare); // sanity check, ARA had a 0.0 split if(splitFactorSpryWare > 0.0) { split.splitFactor = splitFactorSpryWare; rc = recordCorporateActions->GetField(MIS::FID::ACTIVITY_DATE, field); assert(rc == RETURN_CODE_SUCCESS); date = dynamic_cast< Database::Date * >(field); split.date = dateFromSpryWare(date); assert(split.date > previousSplit.date); corporateActions.splits.push_back(split); } else { std::cerr << symbol << " - Bad split factor: " << splitFactorSpryWare << std::endl; } } } rc = pTableCorporateActions->GetNextPartial(*keyCorporateActions, 32, *recordCorporateActions, false, &position); } assert(rc == RETURN_CODE_NOT_FOUND); } void DataFromSpryWare::getFundamentalData(const std::string &symbol, FundamentalData &fundamentalData) { unsigned int rc = 0; std::string spryWareSymbol = symbolToSpryWare(symbol); Database::IndexPosition position = {0}; Database::IField *field; Database::Price *price; Database::Value *value; /* select the correct database if (symbolIsIndex(symbol)) { pTableFundamental = pTableIndexFundamental; keyFundamental = keyIndexFundamental; recordFundamental = recordIndexFundamental; } else { pTableFundamental = pTableEquityFundamental; keyFundamental = keyEquityFundamental; recordFundamental = recordEquityFundamental; }*/ rc = keyFundamentalPrice->FromString(spryWareSymbol); assert(rc == RETURN_CODE_SUCCESS); rc = pTableFundamentalPrice->GetEqual(*keyFundamentalPrice, *recordFundamentalPrice, false, &position); if (rc != RETURN_CODE_SUCCESS) { std::cout << "Failed to get fundamentals for \'" << spryWareSymbol << "\': " << rc << " - "<< MIS::ERR::ToString(rc) << std::endl; return; } rc = recordFundamentalPrice->GetField(MIS::FID::ISSUER_NAME, field); assert(rc == RETURN_CODE_SUCCESS); fundamentalData.companyName = field->ToString(); rc = recordFundamentalPrice->GetField(MIS::FID::PRIMARY_EXCHANGE, field); assert(rc == RETURN_CODE_SUCCESS); fundamentalData.listedExchange = field->ToString(); rc = recordFundamentalPrice->GetField(MIS::FID::HIGH_52, field); assert(rc == RETURN_CODE_SUCCESS); price = dynamic_cast< Database::Price * >(field); assert(price); rc = price->GetPrice(fundamentalData.high52Week); assert(rc == RETURN_CODE_SUCCESS); rc = recordFundamentalPrice->GetField(MIS::FID::LOW_52, field); assert(rc == RETURN_CODE_SUCCESS); price = dynamic_cast< Database::Price * >(field); assert(price); rc = price->GetPrice(fundamentalData.low52Week); assert(rc == RETURN_CODE_SUCCESS); rc = recordFundamentalPrice->GetField(MIS::FID::BETA, field); assert(rc == RETURN_CODE_SUCCESS); value = dynamic_cast< Database::Value * >(field); assert(value); rc = value->Get(fundamentalData.beta); assert(rc == RETURN_CODE_SUCCESS); }