#include<onepiece/configmakercore/ConfigMakerCore.h>
#include <boost/filesystem.hpp>
#include <rapidjson/document.h>
#include <fstream>
#include <sstream>
#include <boost/regex.hpp>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
using namespace rapidjson;
ConfigMakerCore::ConfigMakerCore(string marketDepthDataConfigPath): m_marketDepthDataConfigPath(make_shared<string>(marketDepthDataConfigPath)), m_marketDepthDataCSVPath(nullptr) {
string fileName = string("./log/") + string("configmakercore") + string(".log");
this->m_coreLogger = make_shared<spdlog::logger>("ConfigMakerCoreLogger", make_shared<spdlog::sinks::basic_file_sink_mt>(fileName.c_str()));
this->m_coreLogger->set_level(spdlog::level::info);
this->m_coreLogger->flush_on(spdlog::level::info);
this->m_sourceTradingTimeConfigPath = make_shared<string>("./config/source_trading_time.json");
}
bool ConfigMakerCore::Check() {
if (!boost::filesystem::exists(this->m_sourceTradingTimeConfigPath->data())) {
this->m_coreLogger->error("[ConfigMakerCore Check]: source trading time config path: {0} is not exist.", this->m_sourceTradingTimeConfigPath->data());
cout << "[ConfigMakerCore Check]: source trading time config path: " << this->m_sourceTradingTimeConfigPath->data() << " is not exist." << endl;
return false;
}
if (!this->InitSourceTradingTimeMap()) return false;
if (!boost::filesystem::exists(this->m_marketDepthDataConfigPath->data())) {
this->m_coreLogger->error("[ConfigMakerCore Check]: market depth data config path: {0} is not exist.", this->m_marketDepthDataConfigPath->data());
cout << "[ConfigMakerCore Check]: market depth data config path: " << this->m_marketDepthDataConfigPath->data() << " is not exist." << endl;
return false;
}
ifstream marketDepthDataIfs((*this->m_marketDepthDataConfigPath).c_str());
string marketDepthDataContent((istreambuf_iterator<char>(marketDepthDataIfs)), (istreambuf_iterator<char>()));
marketDepthDataIfs.close();
Document marketDepthDataDocument;
marketDepthDataDocument.Parse(marketDepthDataContent.c_str());
this->m_csvName = (marketDepthDataDocument.HasMember("csv_name") && marketDepthDataDocument["csv_name"].IsString()) ? make_unique<string>(marketDepthDataDocument["csv_name"].GetString()) : nullptr;
if (!this->m_csvName) {
this->m_coreLogger->error("market depth data config file: {0} has no csv_name key.", this->m_marketDepthDataConfigPath->data());
cout << "[ConfigMakerCore Check]: market depth data config file: " << this->m_marketDepthDataConfigPath->data() << " has no csv_name key." << endl;
return false;
}
this->m_marketDepthDataCSVPath = make_shared<string>(("../datacore/ret_data/" + (*this->m_csvName)));
if (!boost::filesystem::exists(this->m_marketDepthDataCSVPath->data())) {
this->m_coreLogger->error("[ConfigMakerCore Check]: market depth data csv file: {0} is not exist.", this->m_marketDepthDataCSVPath->data());
cout << "[ConfigMakerCore Check]: market depth data csv file: " << this->m_marketDepthDataCSVPath->data() << " is not exist." << endl;
return false;
}
return true;
}
bool ConfigMakerCore::InitSourceTradingTimeMap() {
ifstream sourceTradingTimeIfs((*this->m_sourceTradingTimeConfigPath).c_str());
string sourceTradingTimeContent((istreambuf_iterator<char>(sourceTradingTimeIfs)), (istreambuf_iterator<char>()));
sourceTradingTimeIfs.close();
Document sourceTradingTimeDocument;
sourceTradingTimeDocument.Parse(sourceTradingTimeContent.c_str());
for (rapidjson::Value::ConstMemberIterator itr = sourceTradingTimeDocument.MemberBegin(); itr != sourceTradingTimeDocument.MemberEnd(); ++itr) {
// day.
if (!sourceTradingTimeDocument[itr->name.GetString()].HasMember("day")) {
this->m_coreLogger->error("[ConfigMakerCore InitSourceTradingTimeMap]: source trading time json file: {0} has no day key.", itr->name.GetString());
cout << "[ConfigMakerCore InitSourceTradingTimeMap]: source trading time json file: " << itr->name.GetString() << " has no day key." << endl;
return false;
}
const Value& daySessionsValue = sourceTradingTimeDocument[itr->name.GetString()]["day"];
if (!daySessionsValue.IsArray()) {
this->m_coreLogger->error("[ConfigMakerCore InitSourceTradingTimeMap]: {0} daySessionsValue is not array.", itr->name.GetString());
cout << "[ConfigMakerCore InitSourceTradingTimeMap]: " << itr->name.GetString() << " daySessionsValue is not array." << endl;
return false;
}
vector<vector<string>> daySessions;
for (SizeType i = 0; i < daySessionsValue.Size(); i++) {
vector<string> daySession;
if (daySessionsValue[i].IsArray()) {
for (SizeType j = 0; j < daySessionsValue[i].Size(); j++) {
if (daySessionsValue[i][j].IsString()) {
daySession.push_back(daySessionsValue[i][j].GetString());
} else {
this->m_coreLogger->error("[ConfigMakerCore InitSourceTradingTimeMap]: {0} daySessionsValue [{1},{2}] is not string.", itr->name.GetString(), i, j);
cout << "[ConfigMakerCore InitSourceTradingTimeMap]: " << itr->name.GetString() << " daySessionsValue [" << i << "]" << "[" << j << "]" << " is not string." << endl;
return false;
}
}
} else {
this->m_coreLogger->error("[ConfigMakerCore InitSourceTradingTimeMap]: {0} daySessionsValue [{1}] is not array.", itr->name.GetString(), i);
cout << "[ConfigMakerCore InitSourceTradingTimeMap]: " << itr->name.GetString() << " daySessionsValue [" << i << "]" << " is not array." << endl;
return false;
}
daySessions.push_back(daySession);
}
// night.
if (!sourceTradingTimeDocument[itr->name.GetString()].HasMember("night")) {
this->m_coreLogger->error("[ConfigMakerCore InitSourceTradingTimeMap]: source trading time json file: {0} has no night key.", itr->name.GetString());
cout << "[ConfigMakerCore InitSourceTradingTimeMap]: source trading time json file: " << itr->name.GetString() << " has no night key." << endl;
return false;
}
const Value& nightSessionsValue = sourceTradingTimeDocument[itr->name.GetString()]["night"];
if (!nightSessionsValue.IsArray()) {
// log
this->m_coreLogger->error("[ConfigMakerCore InitSourceTradingTimeMap]: {0} nightSessionsValue is not array.", itr->name.GetString());
cout << "[ConfigMakerCore InitSourceTradingTimeMap]: " << itr->name.GetString() << " nightSessionsValue is not array." << endl;
return false;
}
vector<vector<string>> nightSessions;
for (SizeType i = 0; i < nightSessionsValue.Size(); i++) {
vector<string> nightSession;
if (nightSessionsValue[i].IsArray()) {
for (SizeType j = 0; j < nightSessionsValue[i].Size(); j++) {
if (nightSessionsValue[i][j].IsString()) {
nightSession.push_back(nightSessionsValue[i][j].GetString());
} else {
this->m_coreLogger->error("[ConfigMakerCore InitSourceTradingTimeMap]: {0} nightSessionsValue [{1},{2}] is not string.", itr->name.GetString(), i, j);
cout << "[ConfigMakerCore InitSourceTradingTimeMap]: " << itr->name.GetString() << " nightSessionsValue [" << i << "]" << "[" << j << "]" << " is not string." << endl;
return false;
}
}
} else {
this->m_coreLogger->error("[ConfigMakerCore InitSourceTradingTimeMap]: {0} nightSessionsValue [{1}] is not array.", itr->name.GetString(), i);
cout << "[ConfigMakerCore InitSourceTradingTimeMap]: " << itr->name.GetString() << " nightSessionsValue [" << i << "]" << " is not array." << endl;
return false;
}
nightSessions.push_back(nightSession);
}
this->m_sourceTradingTimeMap[itr->name.GetString()] = {{"day", daySessions}, {"night", nightSessions}};
}
return true;
}
string ConfigMakerCore::GetExchangeInstru(const string& exchangeInstrument) {
boost::regex pattern("(.+?)(?=\\d|$)");
boost::smatch matches;
if (!boost::regex_search(exchangeInstrument, matches, pattern)) {
this->m_coreLogger->error("[ConfigMakerCore GetExchangeInstru]: regex_search not match found: {0}.", exchangeInstrument);
cout << "[ConfigMakerCore GetExchangeInstru]: regex_search not match found: " << exchangeInstrument << endl;
exit(1); // kill self process.
}
return matches.str(1);
}
bool ConfigMakerCore::IsInDaySession(const std::string& time, const std::vector<std::string>& timeRange) {
return time >= timeRange[0] && time < timeRange[1];
}
bool ConfigMakerCore::IsInNightSession(const std::string& time, const std::vector<std::string>& timeRange) {
return (timeRange[0] < timeRange[1]) ? this->IsInDaySession(time, timeRange) : (time >= timeRange[0] || time < timeRange[1]);
}
bool ConfigMakerCore::IsTradingTime(const string& exchangeInstru, const std::string& time) {
if (!(this->m_sourceTradingTimeMap.count(exchangeInstru) > 0)) {
this->m_coreLogger->error("[ConfigMakerCore IsTradingTime]: sourceTradingTimeMap has no {0} key.", exchangeInstru);
cout << "[ConfigMakerCore IsTradingTime]: sourceTradingTimeMap has no " << exchangeInstru << " key." << endl;
exit(1); // kill self process.
}
vector<vector<string>> daySessions = this->m_sourceTradingTimeMap[exchangeInstru]["day"];
for (const auto& daySession : daySessions) {
if ((2 == daySession.size()) && this->IsInDaySession(time, daySession)) {
return true;
}
}
vector<vector<string>> nightSessions = this->m_sourceTradingTimeMap[exchangeInstru]["night"];
for (const auto& nightSession : nightSessions) {
if (2 == nightSession.size() && this->IsInNightSession(time, nightSession)) {
return true;
}
}
return false;
}
string ConfigMakerCore::GetMainContractsDailyPath() {
size_t last_underscore_pos = (*this->m_csvName).find_last_of("_");
string mainContractsDailyDir = "./main_contracts_daily/";
if (!boost::filesystem::exists(mainContractsDailyDir)) {
mkdir(mainContractsDailyDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
}
string mainContractsDailyPath = "";
if (last_underscore_pos != string::npos) {
mainContractsDailyPath = mainContractsDailyDir + "main_contracts_" + (*this->m_csvName).substr(last_underscore_pos + 1, 8) + ".json";
} else {
this->m_coreLogger->error("[ConfigMakerCore Parser]: no find date {0}.", this->m_csvName->data());
cout << "[ConfigMakerCore Parser]: no find date " << this->m_csvName->data() << "." << endl;
exit(1); // kill self process.
}
return mainContractsDailyPath;
}
void ConfigMakerCore::Parser() {
if (!this->Check())
return;
this->m_coreLogger->info("[ConfigMakerCore Parser]: start parse csv file {0}.", this->m_csvName->data());
cout << "[ConfigMakerCore Parser]: start parse csv file " << this->m_csvName->data() << "." << endl;
ifstream csvFile(this->m_marketDepthDataCSVPath->data());
vector<vector<string>> csvTitles;
if (!csvFile.is_open()) {
this->m_coreLogger->error("[ConfigMakerCore Parser]: open depth data csv {0} file fail.", this->m_marketDepthDataCSVPath->data());
cout << "[ConfigMakerCore Parser]: open depth data csv " << this->m_marketDepthDataCSVPath->data() << " file fail." << endl;
return;
}
string line;
while (getline(csvFile, line)) {
vector<string> row;
string cell;
istringstream line_stream(line);
while (getline(line_stream, cell, ',')) {
row.push_back(cell);
}
if (0 == csvTitles.data()) { // filter first line.
csvTitles.push_back(row);
continue;
}
string exchangeInstru = this->GetExchangeInstru(row[4]);
if (!this->IsTradingTime(exchangeInstru, row[1]))
continue;
if (this->m_mainContractsMap.count(exchangeInstru) > 0) {
if (stol(this->m_mainContractsMap[exchangeInstru]["volume"]) < stol(row[9])) {
this->m_mainContractsMap[exchangeInstru] = {{"exchange_instrument", row[4]}, {"volume", row[9]}};
}
} else {
this->m_mainContractsMap[exchangeInstru] = {{"exchange_instrument", row[4]}, {"volume", row[9]}};
}
}
csvFile.close();
csvTitles.clear();
}
void ConfigMakerCore::DumpMainContractsJson() {
string mainContraactsDailyPath = this->GetMainContractsDailyPath();
Document document;
document.SetObject();
for (const auto& entry : this->m_mainContractsMap) {
Value key(entry.first.c_str(), document.GetAllocator());
Value value(kObjectType);
for (const auto& subentry : entry.second) {
Value subkey(subentry.first.c_str(), document.GetAllocator());
Value subvalue(subentry.second.c_str(), document.GetAllocator());
value.AddMember(subkey, subvalue, document.GetAllocator());
}
document.AddMember(key, value, document.GetAllocator());
}
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
document.Accept(writer);
string json_str = buffer.GetString();
ofstream ofs(this->GetMainContractsDailyPath());
ofs << json_str << endl;
this->m_coreLogger->info("[ConfigMakerCore DumpMainContractsJson]: dump main contracts json is ok.");
cout << "[ConfigMakerCore DumpMainContractsJson]: dump main contracts json is ok." << endl;
}
ConfigMakerCore::~ConfigMakerCore() {
if (this->m_marketDepthDataConfigPath)
this->m_marketDepthDataConfigPath.reset();
if (this->m_marketDepthDataCSVPath)
this->m_marketDepthDataCSVPath.reset();
if (this->m_coreLogger)
this->m_coreLogger.reset();
if (this->m_csvName)
this->m_csvName.reset();
if (this->m_sourceTradingTimeConfigPath)
this->m_sourceTradingTimeConfigPath.reset();
this->m_mainContractsMap.clear();
this->m_sourceTradingTimeMap.clear();
}