Merge pull request #248 from fasiondog/feature/strategey

fixed setKRecordList 使用 move(ks) 时错误; 接收spot时,分钟级别的成交量为股数
This commit is contained in:
fasiondog 2024-05-08 01:30:43 +08:00 committed by GitHub
commit 9d5a62e672
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 58 additions and 32 deletions

View File

@ -25,7 +25,7 @@ public:
price_t lowPrice; ///< 最低价
price_t closePrice; ///< 最低价
price_t transAmount; ///< 成交金额(千元)
price_t transCount; ///< 成交量(手)
price_t transCount; ///< 成交量(手),日线以下为股数
KRecord()
: datetime(Null<Datetime>()),

View File

@ -936,8 +936,8 @@ void Stock::setKRecordList(KRecordList&& ks, const KQuery::KType& ktype) {
m_kdataDriver = DataDriverFactory::getKDataDriverPool(param);
m_data->m_valid = true;
m_data->m_startDate = ks.front().datetime;
m_data->m_lastDate = ks.back().datetime;
m_data->m_startDate = (*m_data->pKData[nktype]).front().datetime;
m_data->m_lastDate = (*m_data->pKData[nktype]).back().datetime;
}
const vector<HistoryFinanceInfo>& Stock::getHistoryFinance() const {

View File

@ -31,6 +31,7 @@ public:
}
void startDatetime(const Datetime& d) {
HKU_CHECK(!d.isNull(), "Don't use null datetime!");
m_startDatetime = d;
}

View File

@ -156,7 +156,8 @@ static void updateStockMinData(const SpotRecord& spot, KQuery::KType ktype) {
}
price_t amount = spot.amount > sum_amount ? spot.amount - sum_amount : spot.amount;
price_t volume = spot.volume > sum_volume ? spot.volume - sum_volume : spot.volume;
price_t spot_volume = spot.volume * 100; // spot 传过来的是手数
price_t volume = spot_volume > sum_volume ? spot_volume - sum_volume : spot_volume;
KRecord krecord(minute, spot.open, spot.high, spot.low, spot.close, amount, volume);
stk.realtimeUpdate(krecord, ktype);
}

View File

@ -58,7 +58,7 @@ void StrategyBase::_initDefaultParam() {
setParam<bool>("enable_2hour_clock", false);
}
void StrategyBase::run() {
void StrategyBase::_run(bool forTest) {
// 调用 strategy 自身的初始化方法
init();
@ -127,15 +127,10 @@ void StrategyBase::run() {
ktype_list.push_back(KQuery::DAY);
}
// 不使用默认的预加载模式
for (auto ktype : ktype_list) {
to_lower(ktype);
preloadParam.set<bool>(ktype, true);
string key(format("{}_max", ktype));
try {
preloadParam.set<int>(key, config.getInt("preload", key));
} catch (...) {
preloadParam.set<int>(key, 4096);
}
preloadParam.set<bool>(ktype, false);
}
sm.init(baseParam, blockParam, kdataParam, preloadParam, hkuParam, m_context);
@ -152,29 +147,54 @@ void StrategyBase::run() {
}
HKU_WARN_IF(m_stock_list.empty(), "[Strategy {}] stock list is empty!", m_name);
if (m_stock_list.size() > 0) {
const Stock& ref_stk = m_stock_list[0];
for (const auto& ktype : ktype_list) {
// 由于异步初始化此处不用通过先getCount再getKRecord的方式获取最后的KRecord
KRecordList klist = ref_stk.getKRecordList(KQueryByIndex(0, Null<int64_t>(), ktype));
size_t count = klist.size();
if (count > 0) {
m_ref_last_time[ktype] = klist[count - 1].datetime;
} else {
m_ref_last_time[ktype] = Null<Datetime>();
}
// 借助 Stock.setKRecordList 方法进行预加载(同步方式,不需要异步加载)
// 只从 context 指定起始日期开始加载
size_t ktype_count = ktype_list.size();
vector<KRecordList> k_buffer(ktype_count);
for (auto& stk : m_stock_list) {
// 保留原始 KDataDriver因为使用 stock.setKRecordList 将会把 stock 的 KDataDriver 设置为
// DoNothing
auto old_driver = stk.getKDataDirver();
for (size_t i = 0; i < ktype_count; i++) {
k_buffer[i] = std::move(stk.getKRecordList(
KQueryByDate(m_context.startDatetime(), Null<Datetime>(), ktype_list[i])));
}
for (size_t i = 0; i < ktype_count; i++) {
stk.setKRecordList(std::move(k_buffer[i]), ktype_list[i]);
}
// 恢复 KDataDriver
stk.setKDataDriver(old_driver);
}
// 启动行情接收代理
auto& agent = *getGlobalSpotAgent();
agent.addProcess([this](const SpotRecord& spot) { this->receivedSpot(spot); });
agent.addPostProcess([this](Datetime revTime) { this->finishReceivedSpot(revTime); });
startSpotAgent(false);
// 计算每个类型当前最后的日期
for (const auto& ktype : ktype_list) {
Datetime last_date = Datetime::min();
for (auto& stk : m_stock_list) {
size_t count = stk.getCount(ktype);
if (count > 1) {
auto kr = stk.getKRecord(count - 1, ktype);
if (kr.datetime > last_date) {
last_date = kr.datetime;
}
}
}
m_ref_last_time[ktype] = last_date == Datetime::min() ? Null<Datetime>() : last_date;
}
_addTimer();
if (!forTest) {
// 启动行情接收代理
auto& agent = *getGlobalSpotAgent();
agent.addProcess([this](const SpotRecord& spot) { this->receivedSpot(spot); });
agent.addPostProcess([this](Datetime revTime) { this->finishReceivedSpot(revTime); });
startSpotAgent(false);
_startEventLoop();
_addTimer();
HKU_INFO("start even loop ...");
_startEventLoop();
}
}
void StrategyBase::receivedSpot(const SpotRecord& spot) {

View File

@ -84,7 +84,9 @@ public:
return m_context.getKTypeList();
}
void run();
void run() {
_run(false);
}
void receivedSpot(const SpotRecord& spot);
void finishReceivedSpot(Datetime revTime);
@ -114,6 +116,8 @@ private:
void _addClockEvent(const string& enable, TimeDelta delta, TimeDelta openTime,
TimeDelta closeTime);
void _run(bool forTest);
private:
static std::atomic_bool ms_keep_running;
static void sig_handler(int sig);

View File

@ -42,7 +42,7 @@ public:
};
void export_Strategy(py::module& m) {
py::class_<StrategyBase, PyStrategyBase>(m, "StrategyBase")
py::class_<StrategyBase, StrategyPtr, PyStrategyBase>(m, "StrategyBase")
.def(py::init<>())
.def_property("name", py::overload_cast<>(&StrategyBase::name, py::const_),
py::overload_cast<const string&>(&StrategyBase::name),