Skip to content

Commit

Permalink
Merge pull request #214 from fasiondog/feature/factor
Browse files Browse the repository at this point in the history
MF 多线程优化; Selector, Portfolio 增加数据缺失保护
  • Loading branch information
fasiondog committed Mar 30, 2024
2 parents 81b7c43 + 3eb4881 commit d4e70f8
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 4 deletions.
11 changes: 10 additions & 1 deletion hikyuu_cpp/hikyuu/trade_sys/multifactor/MultiFactorBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

#include <cmath>
#include "hikyuu/utilities/thread/algorithm.h"
#include "hikyuu/indicator/crt/ALIGN.h"
#include "hikyuu/indicator/crt/ROCP.h"
#include "hikyuu/indicator/crt/REF.h"
Expand Down Expand Up @@ -342,13 +343,21 @@ Indicator MultiFactorBase::getICIR(int ir_n, int ic_n) {

IndicatorList MultiFactorBase::_getAllReturns(int ndays) const {
bool fill_null = getParam<bool>("fill_null");
#if 0
vector<Indicator> all_returns;
all_returns.reserve(m_stks.size());
for (const auto& stk : m_stks) {
auto k = stk.getKData(m_query);
all_returns.push_back(ALIGN(REF(ROCP(k.close(), ndays), ndays), m_ref_dates, fill_null));
all_returns.emplace_back(ALIGN(REF(ROCP(k.close(), ndays), ndays), m_ref_dates,
fill_null));
}
return all_returns;
#else
return parallel_for_index(0, m_stks.size(), [this, ndays, fill_null](size_t i) {
auto k = m_stks[i].getKData(m_query);
return ALIGN(REF(ROCP(k.close(), ndays), ndays), m_ref_dates, fill_null);
});
#endif
}

vector<IndicatorList> MultiFactorBase::getAllSrcFactors() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Author: fasiondog
*/

#include "hikyuu/utilities/thread/algorithm.h"
#include "hikyuu/indicator/crt/PRICELIST.h"
#include "hikyuu/indicator/crt/IC.h"
#include "hikyuu/indicator/crt/ICIR.h"
Expand All @@ -29,6 +30,7 @@ vector<Indicator> EqualWeightMultiFactor::_calculate(
size_t stk_count = m_stks.size();
size_t ind_count = m_inds.size();

#if 0
value_t null_value = Null<value_t>();
vector<price_t> sumByDate(days_total);
vector<size_t> countByDate(days_total);
Expand Down Expand Up @@ -69,6 +71,44 @@ vector<Indicator> EqualWeightMultiFactor::_calculate(
}

return all_factors;
#endif

return parallel_for_index(0, stk_count, [&, this](size_t si) {
vector<price_t> sumByDate(days_total);
vector<size_t> countByDate(days_total);

const auto& curStkInds = all_stk_inds[si];
for (size_t di = 0; di < days_total; di++) {
for (size_t ii = 0; ii < ind_count; ii++) {
const auto& value = curStkInds[ii][di];
if (!std::isnan(value)) {
sumByDate[di] += value;
countByDate[di] += 1;
}
}
}

// 均值权重
for (size_t di = 0; di < days_total; di++) {
sumByDate[di] =
(countByDate[di] == 0) ? Null<value_t>() : sumByDate[di] / countByDate[di];
}

Indicator ret = PRICELIST(sumByDate);
ret.name("IC");

// 更新 discard
for (size_t di = 0; di < days_total; di++) {
if (!std::isnan(ret[di])) {
ret.setDiscard(di);
break;
}
if (di == days_total - 1 && std::isnan(ret[di])) {
ret.setDiscard(di);
}
}
return ret;
});
}

MultiFactorPtr HKU_API MF_EqualWeight(const IndicatorList& inds, const StockList& stks,
Expand Down
50 changes: 50 additions & 0 deletions hikyuu_cpp/hikyuu/trade_sys/multifactor/imp/ICIRMultiFactor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Author: fasiondog
*/

#include "hikyuu/utilities/thread/algorithm.h"
#include "hikyuu/indicator/crt/PRICELIST.h"
#include "hikyuu/indicator/crt/IC.h"
#include "hikyuu/indicator/crt/ICIR.h"
Expand Down Expand Up @@ -43,6 +44,7 @@ IndicatorList ICIRMultiFactor::_calculate(const vector<IndicatorList>& all_stk_i
int ic_n = getParam<int>("ic_n");
int ir_n = getParam<int>("ic_rolling_n");

#if 0
size_t discard = 0;
vector<Indicator> icir(ind_count);
for (size_t ii = 0; ii < ind_count; ii++) {
Expand All @@ -51,8 +53,21 @@ IndicatorList ICIRMultiFactor::_calculate(const vector<IndicatorList>& all_stk_i
discard = icir[ii].discard();
}
}
#else
vector<Indicator> icir = parallel_for_index(0, ind_count, [this, ic_n, ir_n](size_t ii) {
return ICIR(m_inds[ii], m_stks, m_query, m_ref_stk, ic_n, ir_n);
});

size_t discard = 0;
for (size_t ii = 0; ii < ind_count; ii++) {
if (icir[ii].discard() > discard) {
discard = icir[ii].discard();
}
}
#endif

// 以 ICIR 为权重,计算加权后的合成因子
#if 0
IndicatorList all_factors(stk_count);
PriceList new_values(days_total, 0.0);
PriceList sum_weight(days_total, 0.0);
Expand Down Expand Up @@ -89,6 +104,41 @@ IndicatorList ICIRMultiFactor::_calculate(const vector<IndicatorList>& all_stk_i
}

return all_factors;
#else
return parallel_for_index(0, stk_count, [&, this, discard, ind_count, days_total](size_t si) {
PriceList new_values(days_total, 0.0);
PriceList sum_weight(days_total, 0.0);
for (size_t di = 0; di < discard; di++) {
new_values[di] = Null<price_t>();
}
for (size_t ii = 0; ii < ind_count; ii++) {
const auto* ind_data = all_stk_inds[si][ii].data();
const auto* icir_data = icir[ii].data();
for (size_t di = discard; di < days_total; di++) {
new_values[di] += ind_data[di] * icir_data[di];
sum_weight[di] += std::abs(icir_data[di]);
}
}

for (size_t di = discard; di < days_total; di++) {
if (!std::isnan(new_values[di]) && sum_weight[di] != 0.0) {
new_values[di] = new_values[di] / sum_weight[di];
}
}

Indicator ret = PRICELIST(new_values);
ret.name("ICIR");

const auto* data = ret.data();
for (size_t di = discard; di < days_total; di++) {
if (!std::isnan(data[di])) {
ret.setDiscard(discard);
}
}

return ret;
});
#endif
}

MultiFactorPtr HKU_API MF_ICIRWeight(const IndicatorList& inds, const StockList& stks,
Expand Down
51 changes: 51 additions & 0 deletions hikyuu_cpp/hikyuu/trade_sys/multifactor/imp/ICMultiFactor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Author: fasiondog
*/

#include "hikyuu/utilities/thread/algorithm.h"
#include "hikyuu/indicator/crt/PRICELIST.h"
#include "hikyuu/indicator/crt/IC.h"
#include "hikyuu/indicator/crt/MA.h"
Expand Down Expand Up @@ -43,6 +44,7 @@ IndicatorList ICMultiFactor::_calculate(const vector<IndicatorList>& all_stk_ind
int ic_rolling_n = getParam<int>("ic_rolling_n");

// 计算每个原始因子的滚动IC值
#if 0
size_t discard = 0;
IndicatorList ic(ind_count);
for (size_t ii = 0; ii < ind_count; ii++) {
Expand All @@ -51,8 +53,20 @@ IndicatorList ICMultiFactor::_calculate(const vector<IndicatorList>& all_stk_ind
discard = ic[ii].discard();
}
}
#else
IndicatorList ic = parallel_for_index(0, ind_count, [this, ic_n, ic_rolling_n](size_t ii) {
return MA(IC(m_inds[ii], m_stks, m_query, m_ref_stk, ic_n), ic_rolling_n);
});
size_t discard = 0;
for (size_t ii = 0; ii < ind_count; ii++) {
if (ic[ii].discard() > discard) {
discard = ic[ii].discard();
}
}
#endif

// 以滚动 IC 为权重,计算加权后的合成因子
#if 0
IndicatorList all_factors(stk_count);
PriceList new_values(days_total, 0.0);
PriceList sum_weight(days_total, 0.0);
Expand Down Expand Up @@ -89,6 +103,43 @@ IndicatorList ICMultiFactor::_calculate(const vector<IndicatorList>& all_stk_ind
}

return all_factors;

#else
return parallel_for_index(0, stk_count, [&, this, ind_count, days_total, discard](size_t si) {
PriceList new_values(days_total, 0.0);
PriceList sum_weight(days_total, 0.0);
for (size_t di = 0; di < discard; di++) {
new_values[di] = Null<price_t>();
}

for (size_t ii = 0; ii < ind_count; ii++) {
const auto* ind_data = all_stk_inds[si][ii].data();
const auto* ic_data = ic[ii].data();
for (size_t di = discard; di < days_total; di++) {
new_values[di] += ind_data[di] * ic_data[di];
sum_weight[di] += std::abs(ic_data[di]);
}
}

for (size_t di = discard; di < days_total; di++) {
if (!std::isnan(new_values[di]) && sum_weight[di] != 0.0) {
new_values[di] = new_values[di] / sum_weight[di];
}
}

Indicator ret = PRICELIST(new_values);
ret.name("IC");

const auto* data = ret.data();
for (size_t di = discard; di < days_total; di++) {
if (!std::isnan(data[di])) {
ret.setDiscard(discard);
}
}

return ret;
});
#endif
}

MultiFactorPtr HKU_API MF_ICWeight(const IndicatorList& inds, const StockList& stks,
Expand Down
7 changes: 4 additions & 3 deletions hikyuu_cpp/hikyuu/trade_sys/portfolio/Portfolio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ void Portfolio::_readyForRun() {
FundsRecord funds = m_tm->getFunds();
HKU_CHECK(funds.total_assets() > 0.0, "The current tm is zero assets!");

// 从 se 获取原型系统列表
auto pro_sys_list = m_se->getProtoSystemList();
HKU_CHECK(!pro_sys_list.empty(), "Can't fetch proto_sys_lsit from Selector!");

reset();

// 生成资金账户
Expand All @@ -127,9 +131,6 @@ void Portfolio::_readyForRun() {
m_af->setCashTM(m_cash_tm);
m_af->setQuery(m_query);

// 从 se 获取原型系统列表
auto pro_sys_list = m_se->getProtoSystemList();

// 获取所有备选子系统,为无关联账户的子系统分配子账号,对所有子系统做好启动准备
TMPtr pro_tm = crtTM(m_tm->initDatetime(), 0.0, m_tm->costFunc(), "TM_SUB");
size_t total = pro_sys_list.size();
Expand Down
1 change: 1 addition & 0 deletions hikyuu_cpp/hikyuu/trade_sys/selector/SelectorBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ void SelectorBase::calculate(const SystemList& pf_realSysList, const KQuery& que

void SelectorBase::calculate_proto(const KQuery& query) {
if (m_proto_query != query && !m_proto_calculated) {
HKU_WARN_IF_RETURN(m_pro_sys_list.empty(), void(), "m_pro_sys_list is empty!");
for (auto& sys : m_pro_sys_list) {
sys->run(query);
}
Expand Down

0 comments on commit d4e70f8

Please sign in to comment.