2015-01-07 01:26:14 +08:00
|
|
|
|
/*
|
|
|
|
|
* StockManager.cpp
|
|
|
|
|
*
|
|
|
|
|
* Created on: 2011-11-9
|
|
|
|
|
* Author: fasiondog
|
|
|
|
|
*/
|
|
|
|
|
|
2020-05-01 18:49:36 +08:00
|
|
|
|
#ifndef NOMINMAX
|
|
|
|
|
#define NOMINMAX
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-04-03 02:05:27 +08:00
|
|
|
|
#include "GlobalInitializer.h"
|
2018-09-10 01:14:42 +08:00
|
|
|
|
#include <chrono>
|
2020-04-20 23:59:47 +08:00
|
|
|
|
#include <fmt/format.h>
|
2015-01-07 01:26:14 +08:00
|
|
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
|
|
2019-12-31 23:18:30 +08:00
|
|
|
|
#include "utilities/IniParser.h"
|
2015-01-07 01:26:14 +08:00
|
|
|
|
#include "utilities/util.h"
|
2021-01-17 00:27:09 +08:00
|
|
|
|
#include "utilities/thread/ThreadPool.h"
|
2015-01-07 01:26:14 +08:00
|
|
|
|
#include "StockManager.h"
|
2021-02-21 22:52:05 +08:00
|
|
|
|
#include "global/GlobalTaskGroup.h"
|
|
|
|
|
#include "global/schedule/inner_tasks.h"
|
2020-10-01 00:06:58 +08:00
|
|
|
|
#include "data_driver/kdata/cvs/KDataTempCsvDriver.h"
|
2019-08-16 01:17:24 +08:00
|
|
|
|
#include "data_driver/base_info/sqlite/SQLiteBaseInfoDriver.h"
|
2018-04-16 03:46:43 +08:00
|
|
|
|
#include "data_driver/base_info/mysql/MySQLBaseInfoDriver.h"
|
2017-10-13 01:50:11 +08:00
|
|
|
|
#include "data_driver/block_info/qianlong/QLBlockInfoDriver.h"
|
2017-10-12 01:58:08 +08:00
|
|
|
|
#include "data_driver/kdata/hdf5/H5KDataDriver.h"
|
2017-10-13 01:50:11 +08:00
|
|
|
|
#include "data_driver/kdata/tdx/TdxKDataDriver.h"
|
2018-04-16 03:46:43 +08:00
|
|
|
|
#include "data_driver/kdata/mysql/MySQLKDataDriver.h"
|
2015-01-07 01:26:14 +08:00
|
|
|
|
|
|
|
|
|
namespace hku {
|
|
|
|
|
|
2020-04-03 02:05:27 +08:00
|
|
|
|
StockManager* StockManager::m_sm = nullptr;
|
2015-01-07 01:26:14 +08:00
|
|
|
|
|
2020-03-01 01:24:55 +08:00
|
|
|
|
void StockManager::quit() {
|
2020-03-01 03:00:48 +08:00
|
|
|
|
if (m_sm) {
|
2020-04-03 02:05:27 +08:00
|
|
|
|
delete m_sm;
|
|
|
|
|
m_sm = nullptr;
|
2020-03-01 01:24:55 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-05 23:57:15 +08:00
|
|
|
|
StockManager::StockManager() : m_initializing(false) {
|
2021-01-26 22:58:19 +08:00
|
|
|
|
m_stockDict_mutex = new std::mutex;
|
2021-01-25 00:31:47 +08:00
|
|
|
|
m_marketInfoDict_mutex = new std::mutex;
|
|
|
|
|
m_stockTypeInfo_mutex = new std::mutex;
|
2021-02-07 00:56:04 +08:00
|
|
|
|
m_holidays_mutex = new std::mutex;
|
2021-01-25 00:31:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-20 23:59:47 +08:00
|
|
|
|
StockManager::~StockManager() {
|
2021-01-26 22:58:19 +08:00
|
|
|
|
delete m_stockDict_mutex;
|
2021-01-25 00:31:47 +08:00
|
|
|
|
delete m_marketInfoDict_mutex;
|
|
|
|
|
delete m_stockTypeInfo_mutex;
|
2021-02-07 00:56:04 +08:00
|
|
|
|
delete m_holidays_mutex;
|
2020-04-20 23:59:47 +08:00
|
|
|
|
fmt::print("Quit Hikyuu system!\n\n");
|
|
|
|
|
}
|
2015-01-07 01:26:14 +08:00
|
|
|
|
|
|
|
|
|
StockManager& StockManager::instance() {
|
2019-11-10 19:45:57 +08:00
|
|
|
|
if (!m_sm) {
|
2020-04-03 02:05:27 +08:00
|
|
|
|
m_sm = new StockManager();
|
2015-01-07 01:26:14 +08:00
|
|
|
|
}
|
|
|
|
|
return (*m_sm);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-13 01:50:11 +08:00
|
|
|
|
Parameter default_preload_param() {
|
|
|
|
|
Parameter param;
|
|
|
|
|
param.set<bool>("day", true);
|
|
|
|
|
param.set<bool>("week", false);
|
|
|
|
|
param.set<bool>("month", false);
|
|
|
|
|
param.set<bool>("quarter", false);
|
|
|
|
|
param.set<bool>("halfyear", false);
|
|
|
|
|
param.set<bool>("year", false);
|
|
|
|
|
param.set<bool>("min", false);
|
|
|
|
|
param.set<bool>("min5", false);
|
|
|
|
|
param.set<bool>("min15", false);
|
|
|
|
|
param.set<bool>("min30", false);
|
|
|
|
|
param.set<bool>("min60", false);
|
2020-12-26 18:33:57 +08:00
|
|
|
|
param.set<bool>("ticks", false);
|
|
|
|
|
param.set<int>("day_max", 100000);
|
|
|
|
|
param.set<int>("week_max", 100000);
|
|
|
|
|
param.set<int>("month_max", 100000);
|
|
|
|
|
param.set<int>("quarter_max", 100000);
|
|
|
|
|
param.set<int>("halfyear_max", 100000);
|
|
|
|
|
param.set<int>("year_max", 100000);
|
|
|
|
|
param.set<int>("min_max", 5120);
|
|
|
|
|
param.set<int>("min5_max", 5120);
|
|
|
|
|
param.set<int>("min15_max", 5120);
|
|
|
|
|
param.set<int>("min30_max", 5120);
|
|
|
|
|
param.set<int>("min60_max", 5120);
|
|
|
|
|
param.set<int>("ticks_max", 5120);
|
2017-10-13 01:50:11 +08:00
|
|
|
|
return param;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-14 03:08:49 +08:00
|
|
|
|
Parameter default_other_param() {
|
|
|
|
|
Parameter param;
|
|
|
|
|
param.set<string>("tmpdir", ".");
|
2019-11-10 19:45:57 +08:00
|
|
|
|
param.set<string>("logger", "");
|
2017-10-14 03:08:49 +08:00
|
|
|
|
return param;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-20 23:59:47 +08:00
|
|
|
|
void StockManager::init(const Parameter& baseInfoParam, const Parameter& blockParam,
|
|
|
|
|
const Parameter& kdataParam, const Parameter& preloadParam,
|
2021-02-11 18:06:18 +08:00
|
|
|
|
const Parameter& hikyuuParam, const StrategyContext& context) {
|
2021-02-06 14:45:52 +08:00
|
|
|
|
HKU_WARN_IF_RETURN(m_initializing, void(),
|
|
|
|
|
"The last initialization has not finished. Please try again later!");
|
2021-02-05 23:57:15 +08:00
|
|
|
|
m_initializing = true;
|
2021-03-25 00:55:39 +08:00
|
|
|
|
m_thread_id = std::this_thread::get_id();
|
2017-10-26 02:02:32 +08:00
|
|
|
|
m_baseInfoDriverParam = baseInfoParam;
|
|
|
|
|
m_blockDriverParam = blockParam;
|
|
|
|
|
m_kdataDriverParam = kdataParam;
|
|
|
|
|
m_preloadParam = preloadParam;
|
|
|
|
|
m_hikyuuParam = hikyuuParam;
|
2021-02-11 18:06:18 +08:00
|
|
|
|
m_context = context;
|
2017-10-26 02:02:32 +08:00
|
|
|
|
|
2020-11-22 00:12:09 +08:00
|
|
|
|
// 获取路径信息
|
|
|
|
|
m_tmpdir = hikyuuParam.tryGet<string>("tmpdir", ".");
|
|
|
|
|
m_datadir = hikyuuParam.tryGet<string>("datadir", ".");
|
2019-04-03 22:31:55 +08:00
|
|
|
|
|
2018-08-19 16:51:10 +08:00
|
|
|
|
m_stockDict.clear();
|
|
|
|
|
m_marketInfoDict.clear();
|
|
|
|
|
m_stockTypeInfo.clear();
|
|
|
|
|
|
|
|
|
|
string funcname(" [StockManager::init]");
|
|
|
|
|
|
2017-10-14 03:08:49 +08:00
|
|
|
|
//加载证券基本信息
|
2020-10-29 00:03:25 +08:00
|
|
|
|
m_baseInfoDriver = DataDriverFactory::getBaseInfoDriver(baseInfoParam);
|
|
|
|
|
HKU_CHECK(m_baseInfoDriver, "Failed get base info driver!");
|
2021-02-07 00:56:04 +08:00
|
|
|
|
|
|
|
|
|
loadAllHolidays();
|
|
|
|
|
loadAllMarketInfos();
|
|
|
|
|
loadAllStockTypeInfo();
|
|
|
|
|
loadAllStocks();
|
|
|
|
|
loadAllStockWeights();
|
2017-10-13 01:50:11 +08:00
|
|
|
|
|
2017-10-14 03:08:49 +08:00
|
|
|
|
//获取板块驱动
|
|
|
|
|
m_blockDriver = DataDriverFactory::getBlockDriver(blockParam);
|
2017-10-13 01:50:11 +08:00
|
|
|
|
|
2017-10-14 03:08:49 +08:00
|
|
|
|
//获取K线数据驱动并预加载指定的数据
|
2018-08-30 02:38:13 +08:00
|
|
|
|
HKU_INFO("Loading KData...");
|
2018-09-10 01:14:42 +08:00
|
|
|
|
std::chrono::system_clock::time_point start_time = std::chrono::system_clock::now();
|
2017-10-13 01:50:11 +08:00
|
|
|
|
|
2021-01-22 00:39:37 +08:00
|
|
|
|
setKDataDriver(DataDriverFactory::getKDataDriverPool(m_kdataDriverParam));
|
2017-10-14 03:08:49 +08:00
|
|
|
|
|
2019-11-10 19:45:57 +08:00
|
|
|
|
// add special Market, for temp csv file
|
2020-04-20 23:59:47 +08:00
|
|
|
|
m_marketInfoDict["TMP"] =
|
2020-10-31 00:07:18 +08:00
|
|
|
|
MarketInfo("TMP", "Temp Csv file", "temp load from csv file", "000001", Null<Datetime>(),
|
|
|
|
|
TimeDelta(0), TimeDelta(0), TimeDelta(0), TimeDelta(0));
|
2017-10-13 01:50:11 +08:00
|
|
|
|
|
2018-09-10 01:14:42 +08:00
|
|
|
|
std::chrono::duration<double> sec = std::chrono::system_clock::now() - start_time;
|
2019-06-16 17:56:34 +08:00
|
|
|
|
HKU_INFO("{:<.2f}s Loaded Data.", sec.count());
|
2021-02-05 23:57:15 +08:00
|
|
|
|
m_initializing = false;
|
2017-10-26 02:02:32 +08:00
|
|
|
|
}
|
2015-01-07 01:26:14 +08:00
|
|
|
|
|
2021-01-24 20:47:38 +08:00
|
|
|
|
void StockManager::setKDataDriver(const KDataDriverConnectPoolPtr& driver) {
|
2020-11-22 00:12:09 +08:00
|
|
|
|
HKU_ERROR_IF_RETURN(!driver, void(), "kdata driver is null!");
|
2015-01-07 01:26:14 +08:00
|
|
|
|
|
2021-01-22 00:39:37 +08:00
|
|
|
|
if (m_kdataDriverParam != driver->getPrototype()->getParameter()) {
|
|
|
|
|
m_kdataDriverParam = driver->getPrototype()->getParameter();
|
2017-10-26 02:02:32 +08:00
|
|
|
|
}
|
2015-01-07 01:26:14 +08:00
|
|
|
|
|
2020-11-22 00:12:09 +08:00
|
|
|
|
bool preload_day = m_preloadParam.tryGet<bool>("day", false);
|
|
|
|
|
HKU_INFO_IF(preload_day, "Preloading all day kdata to buffer!");
|
2015-01-07 01:26:14 +08:00
|
|
|
|
|
2020-11-22 00:12:09 +08:00
|
|
|
|
bool preload_week = m_preloadParam.tryGet<bool>("week", false);
|
|
|
|
|
HKU_INFO_IF(preload_week, "Preloading all week kdata to buffer!");
|
2015-01-07 01:26:14 +08:00
|
|
|
|
|
2020-11-22 00:12:09 +08:00
|
|
|
|
bool preload_month = m_preloadParam.tryGet<bool>("month", false);
|
2021-01-04 00:16:19 +08:00
|
|
|
|
HKU_INFO_IF(preload_month, "Preloading all month kdata to buffer!");
|
2015-01-07 01:26:14 +08:00
|
|
|
|
|
2020-11-22 00:12:09 +08:00
|
|
|
|
bool preload_quarter = m_preloadParam.tryGet<bool>("quarter", false);
|
|
|
|
|
HKU_INFO_IF(preload_quarter, "Preloading all quarter kdata to buffer!");
|
2015-01-07 01:26:14 +08:00
|
|
|
|
|
2020-11-22 00:12:09 +08:00
|
|
|
|
bool preload_halfyear = m_preloadParam.tryGet<bool>("halfyear", false);
|
|
|
|
|
HKU_INFO_IF(preload_halfyear, "Preloading all halfyear kdata to buffer!");
|
2015-01-07 01:26:14 +08:00
|
|
|
|
|
2020-11-22 00:12:09 +08:00
|
|
|
|
bool preload_year = m_preloadParam.tryGet<bool>("year", false);
|
|
|
|
|
HKU_INFO_IF(preload_year, "Preloading all year kdata to buffer!");
|
2017-10-12 01:58:08 +08:00
|
|
|
|
|
2020-11-22 00:12:09 +08:00
|
|
|
|
bool preload_min = m_preloadParam.tryGet<bool>("min", false);
|
|
|
|
|
HKU_INFO_IF(preload_min, "Preloading all 1 min kdata to buffer!");
|
2017-10-26 02:02:32 +08:00
|
|
|
|
|
2020-11-22 00:12:09 +08:00
|
|
|
|
bool preload_min5 = m_preloadParam.tryGet<bool>("min5", false);
|
|
|
|
|
HKU_INFO_IF(preload_min5, "Preloading all 5 min kdata to buffer!");
|
2017-10-26 02:02:32 +08:00
|
|
|
|
|
2020-11-22 00:12:09 +08:00
|
|
|
|
bool preload_min15 = m_preloadParam.tryGet<bool>("min15", false);
|
|
|
|
|
HKU_INFO_IF(preload_min15, "Preloading all 15 min kdata to buffer!");
|
2017-10-26 02:02:32 +08:00
|
|
|
|
|
2020-11-22 00:12:09 +08:00
|
|
|
|
bool preload_min30 = m_preloadParam.tryGet<bool>("min30", false);
|
|
|
|
|
HKU_INFO_IF(preload_min30, "Preloading all 30 min kdata to buffer!");
|
2015-01-07 01:26:14 +08:00
|
|
|
|
|
2020-11-22 00:12:09 +08:00
|
|
|
|
bool preload_min60 = m_preloadParam.tryGet<bool>("min60", false);
|
|
|
|
|
HKU_INFO_IF(preload_min60, "Preloading all 60 min kdata to buffer!");
|
2015-01-07 01:26:14 +08:00
|
|
|
|
|
2021-01-22 00:39:37 +08:00
|
|
|
|
if (!driver->getPrototype()->canParallelLoad()) {
|
2020-12-27 19:11:18 +08:00
|
|
|
|
for (auto iter = m_stockDict.begin(); iter != m_stockDict.end(); ++iter) {
|
|
|
|
|
if (iter->second.market() == "TMP")
|
|
|
|
|
continue;
|
|
|
|
|
iter->second.setKDataDriver(driver);
|
|
|
|
|
if (preload_day)
|
|
|
|
|
iter->second.loadKDataToBuffer(KQuery::DAY);
|
|
|
|
|
if (preload_week)
|
|
|
|
|
iter->second.loadKDataToBuffer(KQuery::WEEK);
|
|
|
|
|
if (preload_month)
|
|
|
|
|
iter->second.loadKDataToBuffer(KQuery::MONTH);
|
|
|
|
|
if (preload_quarter)
|
|
|
|
|
iter->second.loadKDataToBuffer(KQuery::QUARTER);
|
|
|
|
|
if (preload_halfyear)
|
|
|
|
|
iter->second.loadKDataToBuffer(KQuery::HALFYEAR);
|
|
|
|
|
if (preload_year)
|
|
|
|
|
iter->second.loadKDataToBuffer(KQuery::YEAR);
|
|
|
|
|
if (preload_min)
|
|
|
|
|
iter->second.loadKDataToBuffer(KQuery::MIN);
|
|
|
|
|
if (preload_min5)
|
|
|
|
|
iter->second.loadKDataToBuffer(KQuery::MIN5);
|
|
|
|
|
if (preload_min15)
|
|
|
|
|
iter->second.loadKDataToBuffer(KQuery::MIN15);
|
|
|
|
|
if (preload_min30)
|
|
|
|
|
iter->second.loadKDataToBuffer(KQuery::MIN30);
|
|
|
|
|
if (preload_min60)
|
|
|
|
|
iter->second.loadKDataToBuffer(KQuery::MIN60);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// 异步并行加载
|
2021-01-17 00:27:09 +08:00
|
|
|
|
auto& tg = *getGlobalTaskGroup();
|
2020-12-27 19:11:18 +08:00
|
|
|
|
for (auto iter = m_stockDict.begin(); iter != m_stockDict.end(); ++iter) {
|
|
|
|
|
if (iter->second.market() == "TMP")
|
|
|
|
|
continue;
|
2020-12-29 00:18:57 +08:00
|
|
|
|
iter->second.setKDataDriver(driver);
|
2020-12-27 19:11:18 +08:00
|
|
|
|
if (preload_day)
|
2021-01-17 00:27:09 +08:00
|
|
|
|
tg.submit([=]() mutable { iter->second.loadKDataToBuffer(KQuery::DAY); });
|
2020-12-27 19:11:18 +08:00
|
|
|
|
if (preload_week)
|
2021-01-17 00:27:09 +08:00
|
|
|
|
tg.submit([=]() mutable { iter->second.loadKDataToBuffer(KQuery::WEEK); });
|
2020-12-27 19:11:18 +08:00
|
|
|
|
if (preload_month)
|
2021-01-17 00:27:09 +08:00
|
|
|
|
tg.submit([=]() mutable { iter->second.loadKDataToBuffer(KQuery::MONTH); });
|
2020-12-27 19:11:18 +08:00
|
|
|
|
if (preload_quarter)
|
2021-01-17 00:27:09 +08:00
|
|
|
|
tg.submit([=]() mutable { iter->second.loadKDataToBuffer(KQuery::QUARTER); });
|
2020-12-27 19:11:18 +08:00
|
|
|
|
if (preload_halfyear)
|
2021-01-17 00:27:09 +08:00
|
|
|
|
tg.submit([=]() mutable { iter->second.loadKDataToBuffer(KQuery::HALFYEAR); });
|
2020-12-27 19:11:18 +08:00
|
|
|
|
if (preload_year)
|
2021-01-17 00:27:09 +08:00
|
|
|
|
tg.submit([=]() mutable { iter->second.loadKDataToBuffer(KQuery::YEAR); });
|
2020-12-27 19:11:18 +08:00
|
|
|
|
if (preload_min)
|
2021-01-17 00:27:09 +08:00
|
|
|
|
tg.submit([=]() mutable { iter->second.loadKDataToBuffer(KQuery::MIN); });
|
2020-12-27 19:11:18 +08:00
|
|
|
|
if (preload_min5)
|
2021-01-17 00:27:09 +08:00
|
|
|
|
tg.submit([=]() mutable { iter->second.loadKDataToBuffer(KQuery::MIN5); });
|
2020-12-27 19:11:18 +08:00
|
|
|
|
if (preload_min15)
|
2021-01-17 00:27:09 +08:00
|
|
|
|
tg.submit([=]() mutable { iter->second.loadKDataToBuffer(KQuery::MIN15); });
|
2020-12-27 19:11:18 +08:00
|
|
|
|
if (preload_min30)
|
2021-01-17 00:27:09 +08:00
|
|
|
|
tg.submit([=]() mutable { iter->second.loadKDataToBuffer(KQuery::MIN30); });
|
2020-12-27 19:11:18 +08:00
|
|
|
|
if (preload_min60)
|
2021-01-17 00:27:09 +08:00
|
|
|
|
tg.submit([=]() mutable { iter->second.loadKDataToBuffer(KQuery::MIN60); });
|
2020-12-27 19:11:18 +08:00
|
|
|
|
}
|
2017-10-26 02:02:32 +08:00
|
|
|
|
}
|
2021-01-15 00:19:38 +08:00
|
|
|
|
|
2021-01-31 23:45:53 +08:00
|
|
|
|
initInnerTasek();
|
2021-01-29 00:18:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void StockManager::reload() {
|
2021-02-07 00:56:04 +08:00
|
|
|
|
loadAllHolidays();
|
2021-01-29 00:18:01 +08:00
|
|
|
|
|
2021-02-07 00:56:04 +08:00
|
|
|
|
loadAllMarketInfos();
|
|
|
|
|
loadAllStockTypeInfo();
|
|
|
|
|
loadAllStocks();
|
|
|
|
|
loadAllStockWeights();
|
2021-01-29 00:18:01 +08:00
|
|
|
|
|
2021-02-07 00:56:04 +08:00
|
|
|
|
HKU_INFO("start reload kdata to buffer");
|
|
|
|
|
std::vector<Stock> can_not_parallel_stk_list; // 记录不支持并行加载的Stock
|
2021-01-29 00:18:01 +08:00
|
|
|
|
{
|
|
|
|
|
auto* tg = getGlobalTaskGroup();
|
|
|
|
|
std::lock_guard<std::mutex> lock(*m_stockDict_mutex);
|
|
|
|
|
for (auto iter = m_stockDict.begin(); iter != m_stockDict.end(); ++iter) {
|
2021-02-07 00:56:04 +08:00
|
|
|
|
auto driver = iter->second.getKDataDirver();
|
|
|
|
|
if (!driver->getPrototype()->canParallelLoad()) {
|
|
|
|
|
can_not_parallel_stk_list.push_back(iter->second);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-29 00:18:01 +08:00
|
|
|
|
auto& ktype_list = KQuery::getAllKType();
|
|
|
|
|
for (auto& ktype : ktype_list) {
|
|
|
|
|
if (iter->second.isBuffer(ktype)) {
|
|
|
|
|
tg->submit([=]() mutable {
|
|
|
|
|
Stock& stk = iter->second;
|
|
|
|
|
stk.loadKDataToBuffer(ktype);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-02-07 00:56:04 +08:00
|
|
|
|
|
|
|
|
|
for (auto& stk : can_not_parallel_stk_list) {
|
|
|
|
|
auto& ktype_list = KQuery::getAllKType();
|
|
|
|
|
for (auto& ktype : ktype_list) {
|
|
|
|
|
if (stk.isBuffer(ktype)) {
|
|
|
|
|
stk.loadKDataToBuffer(ktype);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-01-29 00:18:01 +08:00
|
|
|
|
}
|
2015-01-07 01:26:14 +08:00
|
|
|
|
|
|
|
|
|
string StockManager::tmpdir() const {
|
2017-10-13 01:50:11 +08:00
|
|
|
|
return m_tmpdir;
|
2015-01-07 01:26:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-03 22:31:55 +08:00
|
|
|
|
string StockManager::datadir() const {
|
|
|
|
|
return m_datadir;
|
|
|
|
|
}
|
2015-01-07 01:26:14 +08:00
|
|
|
|
|
|
|
|
|
Stock StockManager::getStock(const string& querystr) const {
|
|
|
|
|
Stock result;
|
|
|
|
|
string query_str = querystr;
|
2019-08-03 01:44:57 +08:00
|
|
|
|
to_upper(query_str);
|
2021-01-26 22:58:19 +08:00
|
|
|
|
std::lock_guard<std::mutex> lock(*m_stockDict_mutex);
|
2016-04-03 00:08:31 +08:00
|
|
|
|
auto iter = m_stockDict.find(query_str);
|
2020-11-22 00:12:09 +08:00
|
|
|
|
return (iter != m_stockDict.end()) ? iter->second : result;
|
2015-01-07 01:26:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MarketInfo StockManager::getMarketInfo(const string& market) const {
|
2021-01-25 00:31:47 +08:00
|
|
|
|
MarketInfo result;
|
2015-01-07 01:26:14 +08:00
|
|
|
|
string market_tmp = market;
|
2019-08-03 01:44:57 +08:00
|
|
|
|
to_upper(market_tmp);
|
2021-01-25 00:31:47 +08:00
|
|
|
|
|
|
|
|
|
std::lock_guard<std::mutex> lock(*m_marketInfoDict_mutex);
|
2016-04-03 00:08:31 +08:00
|
|
|
|
auto iter = m_marketInfoDict.find(market_tmp);
|
2021-01-25 00:31:47 +08:00
|
|
|
|
if (iter != m_marketInfoDict.end()) {
|
|
|
|
|
result = iter->second;
|
|
|
|
|
} else {
|
|
|
|
|
result = m_baseInfoDriver->getMarketInfo(market_tmp);
|
|
|
|
|
if (result != Null<MarketInfo>()) {
|
|
|
|
|
m_marketInfoDict[market_tmp] = result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
2015-01-07 01:26:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-01 22:52:50 +08:00
|
|
|
|
StockTypeInfo StockManager::getStockTypeInfo(uint32_t type) const {
|
2021-01-25 00:31:47 +08:00
|
|
|
|
StockTypeInfo result;
|
|
|
|
|
std::lock_guard<std::mutex> lock(*m_stockTypeInfo_mutex);
|
2016-04-03 00:08:31 +08:00
|
|
|
|
auto iter = m_stockTypeInfo.find(type);
|
2021-01-25 00:31:47 +08:00
|
|
|
|
if (iter != m_stockTypeInfo.end()) {
|
|
|
|
|
result = iter->second;
|
|
|
|
|
} else {
|
|
|
|
|
result = m_baseInfoDriver->getStockTypeInfo(type);
|
|
|
|
|
if (result != Null<StockTypeInfo>()) {
|
|
|
|
|
m_stockTypeInfo[type] = result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
2015-01-07 01:26:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MarketList StockManager::getAllMarket() const {
|
|
|
|
|
MarketList result;
|
2021-02-11 18:06:18 +08:00
|
|
|
|
std::lock_guard<std::mutex> lock(*m_marketInfoDict_mutex);
|
2016-04-03 00:08:31 +08:00
|
|
|
|
auto iter = m_marketInfoDict.begin();
|
2019-11-10 19:45:57 +08:00
|
|
|
|
for (; iter != m_marketInfoDict.end(); ++iter) {
|
2015-01-07 01:26:14 +08:00
|
|
|
|
result.push_back(iter->first);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-03 00:08:31 +08:00
|
|
|
|
Block StockManager::getBlock(const string& category, const string& name) {
|
2019-11-10 19:45:57 +08:00
|
|
|
|
return m_blockDriver ? m_blockDriver->getBlock(category, name) : Block();
|
2016-04-03 00:08:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BlockList StockManager::getBlockList(const string& category) {
|
2017-10-14 03:08:49 +08:00
|
|
|
|
return m_blockDriver ? m_blockDriver->getBlockList(category) : BlockList();
|
2016-04-03 00:08:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BlockList StockManager::getBlockList() {
|
2017-10-14 03:08:49 +08:00
|
|
|
|
return m_blockDriver ? m_blockDriver->getBlockList() : BlockList();
|
2016-04-03 00:08:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-11-10 19:45:57 +08:00
|
|
|
|
DatetimeList StockManager::getTradingCalendar(const KQuery& query, const string& market) {
|
2020-11-22 00:12:09 +08:00
|
|
|
|
auto marketinfo = getMarketInfo(market);
|
|
|
|
|
return getStock(fmt::format("{}{}", marketinfo.market(), marketinfo.code()))
|
|
|
|
|
.getDatetimeList(query);
|
2016-04-03 00:08:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-20 23:59:47 +08:00
|
|
|
|
Stock StockManager::addTempCsvStock(const string& code, const string& day_filename,
|
|
|
|
|
const string& min_filename, price_t tick, price_t tickValue,
|
|
|
|
|
int precision, size_t minTradeNumber, size_t maxTradeNumber) {
|
2017-08-01 02:16:51 +08:00
|
|
|
|
string new_code(code);
|
2019-08-03 01:44:57 +08:00
|
|
|
|
to_upper(new_code);
|
2020-04-20 23:59:47 +08:00
|
|
|
|
Stock result("TMP", new_code, day_filename, STOCKTYPE_TMP, true, Datetime(199901010000),
|
|
|
|
|
Null<Datetime>(), tick, tickValue, precision, minTradeNumber, maxTradeNumber);
|
2017-09-20 02:29:53 +08:00
|
|
|
|
|
2021-01-20 00:32:01 +08:00
|
|
|
|
Parameter param;
|
|
|
|
|
param.set<string>("type", "TMPCSV");
|
2021-01-22 23:50:46 +08:00
|
|
|
|
auto driver_pool = DataDriverFactory::getKDataDriverPool(param);
|
|
|
|
|
auto driver = driver_pool->getPrototype();
|
2021-01-20 00:32:01 +08:00
|
|
|
|
KDataTempCsvDriver* p = dynamic_cast<KDataTempCsvDriver*>(driver.get());
|
|
|
|
|
p->setDayFileName(day_filename);
|
|
|
|
|
p->setMinFileName(min_filename);
|
2021-01-22 23:50:46 +08:00
|
|
|
|
result.setKDataDriver(driver_pool);
|
2020-12-27 00:23:58 +08:00
|
|
|
|
const auto& preload_param = getPreloadParameter();
|
|
|
|
|
if (preload_param.tryGet<bool>("day", true)) {
|
|
|
|
|
result.loadKDataToBuffer(KQuery::DAY);
|
|
|
|
|
}
|
|
|
|
|
if (preload_param.tryGet<bool>("min", false)) {
|
|
|
|
|
result.loadKDataToBuffer(KQuery::MIN);
|
|
|
|
|
}
|
2021-02-07 00:56:04 +08:00
|
|
|
|
return addStock(result) ? result : Null<Stock>();
|
2017-07-31 02:26:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void StockManager::removeTempCsvStock(const string& code) {
|
|
|
|
|
string query_str = "TMP" + code;
|
2019-08-03 01:44:57 +08:00
|
|
|
|
to_upper(query_str);
|
2017-07-31 02:26:10 +08:00
|
|
|
|
auto iter = m_stockDict.find(query_str);
|
2019-11-10 19:45:57 +08:00
|
|
|
|
if (iter != m_stockDict.end()) {
|
2017-07-31 02:26:10 +08:00
|
|
|
|
m_stockDict.erase(iter);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-07 00:56:04 +08:00
|
|
|
|
bool StockManager::addStock(const Stock& stock) {
|
2017-10-09 02:25:02 +08:00
|
|
|
|
string market_code(stock.market_code());
|
2019-08-03 01:44:57 +08:00
|
|
|
|
to_upper(market_code);
|
2021-01-26 22:58:19 +08:00
|
|
|
|
std::lock_guard<std::mutex> lock(*m_stockDict_mutex);
|
2020-11-22 00:12:09 +08:00
|
|
|
|
HKU_ERROR_IF_RETURN(m_stockDict.find(market_code) != m_stockDict.end(), false,
|
|
|
|
|
"The stock had exist! {}", market_code);
|
2017-10-09 02:25:02 +08:00
|
|
|
|
m_stockDict[market_code] = stock;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-07 00:56:04 +08:00
|
|
|
|
void StockManager::loadAllStocks() {
|
|
|
|
|
HKU_INFO("Loading stock information...");
|
2021-02-11 18:06:18 +08:00
|
|
|
|
vector<StockInfo> stockInfos;
|
2021-02-17 16:08:24 +08:00
|
|
|
|
if (m_context.isAll()) {
|
2021-02-11 18:06:18 +08:00
|
|
|
|
stockInfos = m_baseInfoDriver->getAllStockInfo();
|
|
|
|
|
} else {
|
2021-02-17 16:08:24 +08:00
|
|
|
|
const vector<string>& context_stock_code_list = m_context.getStockCodeList();
|
2021-02-11 18:06:18 +08:00
|
|
|
|
auto all_market = getAllMarket();
|
|
|
|
|
for (auto stkcode : context_stock_code_list) {
|
|
|
|
|
to_upper(stkcode);
|
|
|
|
|
bool find = false;
|
|
|
|
|
for (auto& market : all_market) {
|
|
|
|
|
auto pos = stkcode.find(market);
|
|
|
|
|
if (pos != string::npos && market.size() <= stkcode.size()) {
|
|
|
|
|
string stk_market = stkcode.substr(pos, market.size());
|
|
|
|
|
string stk_code = stkcode.substr(market.size(), stkcode.size());
|
|
|
|
|
stockInfos.push_back(m_baseInfoDriver->getStockInfo(stk_market, stk_code));
|
|
|
|
|
find = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
HKU_WARN_IF(!find, "Invalid stock code: {}", stkcode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-07 00:56:04 +08:00
|
|
|
|
std::lock_guard<std::mutex> lock(*m_stockDict_mutex);
|
|
|
|
|
for (auto& info : stockInfos) {
|
|
|
|
|
Datetime startDate, endDate;
|
|
|
|
|
try {
|
|
|
|
|
startDate = Datetime(info.startDate * 10000LL);
|
|
|
|
|
} catch (...) {
|
|
|
|
|
startDate = Null<Datetime>();
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
endDate = Datetime(info.endDate * 10000LL);
|
|
|
|
|
} catch (...) {
|
|
|
|
|
endDate = Null<Datetime>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string market_code = format("{}{}", info.market, info.code);
|
|
|
|
|
to_upper(market_code);
|
|
|
|
|
auto iter = m_stockDict.find(market_code);
|
|
|
|
|
if (iter == m_stockDict.end()) {
|
|
|
|
|
Stock stock(info.market, info.code, info.name, info.type, info.valid, startDate,
|
|
|
|
|
endDate, info.tick, info.tickValue, info.precision, info.minTradeNumber,
|
|
|
|
|
info.maxTradeNumber);
|
|
|
|
|
m_stockDict[market_code] = stock;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
Stock& stock = iter->second;
|
|
|
|
|
if (!stock.m_data) {
|
|
|
|
|
stock.m_data = shared_ptr<Stock::Data>(
|
|
|
|
|
new Stock::Data(info.market, info.code, info.name, info.type, info.valid,
|
|
|
|
|
startDate, endDate, info.tick, info.tickValue, info.precision,
|
|
|
|
|
info.minTradeNumber, info.maxTradeNumber));
|
|
|
|
|
} else {
|
|
|
|
|
stock.m_data->m_market = info.market;
|
|
|
|
|
stock.m_data->m_code = info.code;
|
|
|
|
|
stock.m_data->m_name = info.name;
|
|
|
|
|
stock.m_data->m_type = info.type;
|
|
|
|
|
stock.m_data->m_valid = info.valid;
|
|
|
|
|
stock.m_data->m_startDate = startDate;
|
|
|
|
|
stock.m_data->m_lastDate = endDate;
|
|
|
|
|
stock.m_data->m_tick = info.tick;
|
|
|
|
|
stock.m_data->m_tickValue = info.tickValue;
|
|
|
|
|
stock.m_data->m_precision = info.precision;
|
|
|
|
|
stock.m_data->m_minTradeNumber = info.minTradeNumber;
|
|
|
|
|
stock.m_data->m_maxTradeNumber = info.maxTradeNumber;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void StockManager::loadAllMarketInfos() {
|
|
|
|
|
HKU_INFO("Loading market information...");
|
|
|
|
|
auto marketInfos = m_baseInfoDriver->getAllMarketInfo();
|
2021-01-26 22:58:19 +08:00
|
|
|
|
std::lock_guard<std::mutex> lock(*m_marketInfoDict_mutex);
|
2021-02-07 00:56:04 +08:00
|
|
|
|
m_marketInfoDict.clear();
|
|
|
|
|
m_marketInfoDict.reserve(marketInfos.size());
|
|
|
|
|
for (auto& marketInfo : marketInfos) {
|
|
|
|
|
string market = marketInfo.market();
|
|
|
|
|
to_upper(market);
|
|
|
|
|
m_marketInfoDict[market] = marketInfo;
|
|
|
|
|
}
|
2017-10-09 02:25:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-07 00:56:04 +08:00
|
|
|
|
void StockManager::loadAllStockTypeInfo() {
|
|
|
|
|
HKU_INFO("Loading stock type information...");
|
|
|
|
|
auto stkTypeInfos = m_baseInfoDriver->getAllStockTypeInfo();
|
2021-01-26 22:58:19 +08:00
|
|
|
|
std::lock_guard<std::mutex> lock(*m_stockTypeInfo_mutex);
|
2021-02-07 00:56:04 +08:00
|
|
|
|
m_stockTypeInfo.clear();
|
|
|
|
|
m_stockTypeInfo.reserve(stkTypeInfos.size());
|
|
|
|
|
for (auto& stkTypeInfo : stkTypeInfos) {
|
|
|
|
|
m_stockTypeInfo[stkTypeInfo.type()] = stkTypeInfo;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void StockManager::loadAllHolidays() {
|
|
|
|
|
auto holidays = m_baseInfoDriver->getAllHolidays();
|
|
|
|
|
std::lock_guard<std::mutex> lock(*m_holidays_mutex);
|
|
|
|
|
m_holidays = std::move(holidays);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void StockManager::loadAllStockWeights() {
|
|
|
|
|
HKU_INFO("Loading stock weight...");
|
|
|
|
|
ThreadPool tg; // 这里不用全局的线程池,可以避免在初始化后立即reload导致过长的等待
|
|
|
|
|
std::vector<std::future<void>> task_list;
|
|
|
|
|
std::lock_guard<std::mutex> lock(*m_stockDict_mutex);
|
|
|
|
|
for (auto iter = m_stockDict.begin(); iter != m_stockDict.end(); ++iter) {
|
|
|
|
|
task_list.push_back(tg.submit([=]() mutable {
|
|
|
|
|
Stock& stock = iter->second;
|
|
|
|
|
StockWeightList weightList = m_baseInfoDriver->getStockWeightList(
|
|
|
|
|
stock.market(), stock.code(), Datetime::min(), Null<Datetime>());
|
|
|
|
|
if (stock.m_data) {
|
|
|
|
|
std::lock_guard<std::mutex> lock(stock.m_data->m_weight_mutex);
|
|
|
|
|
stock.m_data->m_weightList.swap(weightList);
|
|
|
|
|
}
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
// 权息信息如果不等待加载完毕,在数据加载期间进行计算可能导致复权错误,所以这里需要等待
|
|
|
|
|
for (auto& task : task_list) {
|
|
|
|
|
task.get();
|
|
|
|
|
}
|
2017-10-09 02:25:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-11-10 19:45:57 +08:00
|
|
|
|
} // namespace hku
|