Merge pull request #212 from fasiondog/feature/factor

调整 MF get_score 接口; SE/PF/AF 微调; update get_part add *args
This commit is contained in:
fasiondog 2024-03-30 15:34:24 +08:00 committed by GitHub
commit 7d482d90c1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 245 additions and 140 deletions

View File

@ -545,13 +545,14 @@ def remove_hub(name):
HubManager().remove_hub(name)
def get_part(name, **kwargs):
def get_part(name, *args, **kwargs):
"""获取指定策略部件
:param str name:
:param args:
:param kwargs:
"""
return HubManager().get_part(name, **kwargs)
return HubManager().get_part(name, *args, **kwargs)
def get_hub_path(name):

View File

@ -2,7 +2,8 @@
from hikyuu.core import (
System, SystemPart, ConditionBase, EnvironmentBase, MoneyManagerBase,
ProfitGoalBase, SelectorBase, SignalBase, SlippageBase, StoplossBase, AllocateFundsBase
ProfitGoalBase, SelectorBase, SignalBase, SlippageBase, StoplossBase, AllocateFundsBase,
MultiFactorBase
)
@ -180,6 +181,23 @@ def crtAF(allocate_weight_func, params={}, name='crtAF'):
return meta_x(name, params)
# ------------------------------------------------------------------
# multi_factor
# ------------------------------------------------------------------
def crtMF(calculate_func, params={}, name='crtMF'):
"""
:param calculate_func:
:param {} params:
:param str name:
:return:
"""
meta_x = type(name, (MultiFactorBase, ), {'__init__': part_init, '_clone': part_clone})
meta_x._calculate = calculate_func
return meta_x(name, params)
# ------------------------------------------------------------------
# slippage
# ------------------------------------------------------------------

View File

@ -295,7 +295,7 @@ SystemWeightList AllocateFundsBase::_adjust_with_running(
} else {
// 非延迟卖出的系统,立即强制卖出并回收资金
auto tr = sys->sellForceOnClose(date, MAX_DOUBLE, PART_ALLOCATEFUNDS);
HKU_DEBUG_IF(trace && tr.isNull(), "[AF] failed to sell: {}", sys->name());
// HKU_DEBUG_IF(trace && tr.isNull(), "[AF] failed to sell: {}", sys->name());
if (!tr.isNull()) {
auto sub_tm = sys->getTM();
auto sub_cash = sub_tm->currentCash();

View File

@ -181,7 +181,8 @@ const ScoreRecordList& MultiFactorBase::getScore(const Datetime& d) {
return m_stk_factor_by_date[iter->second];
}
ScoreRecordList MultiFactorBase::getScore(const Datetime& date, size_t start, size_t end) {
ScoreRecordList MultiFactorBase::getScores(const Datetime& date, size_t start, size_t end,
std::function<bool(const ScoreRecord&)>&& filter) {
ScoreRecordList ret;
HKU_IF_RETURN(start >= end, ret);
@ -190,23 +191,44 @@ ScoreRecordList MultiFactorBase::getScore(const Datetime& date, size_t start, si
end = cross.size();
}
ret.resize(end - start);
for (size_t i = start; i < end; i++) {
ret[i] = cross[i];
if (filter) {
for (size_t i = start; i < end; i++) {
if (filter(cross[i])) {
ret.emplace_back(cross[i]);
}
}
} else {
for (size_t i = start; i < end; i++) {
ret.emplace_back(cross[i]);
}
}
return ret;
}
ScoreRecordList MultiFactorBase::getScore(const Datetime& date,
std::function<bool(const ScoreRecord&)> filter) {
ScoreRecordList MultiFactorBase::getScores(
const Datetime& date, size_t start, size_t end,
std::function<bool(const Datetime&, const ScoreRecord&)>&& filter) {
ScoreRecordList ret;
const auto& all_scores = getScore(date);
for (const auto& score : all_scores) {
if (filter(score)) {
ret.emplace_back(score);
HKU_IF_RETURN(start >= end, ret);
const auto& cross = getScore(date);
if (end == Null<size_t>() || end > cross.size()) {
end = cross.size();
}
if (filter) {
for (size_t i = start; i < end; i++) {
if (filter(date, cross[i])) {
ret.emplace_back(cross[i]);
}
}
} else {
for (size_t i = start; i < end; i++) {
ret.emplace_back(cross[i]);
}
}
return ret;
}

View File

@ -82,10 +82,20 @@ public:
/** 获取指定日期截面的所有因子值,已经降序排列 */
const ScoreRecordList& getScore(const Datetime&);
ScoreRecordList getScore(const Datetime& date, size_t start, size_t end = Null<size_t>());
/**
* [start, end] , filer进行过滤
* @param date
* @param start
* @param end ()
* @param filter
*/
ScoreRecordList getScores(
const Datetime& date, size_t start, size_t end = Null<size_t>(),
std::function<bool(const ScoreRecord&)>&& filter = std::function<bool(const ScoreRecord&)>());
/** 获取指定日期截面的所有因子值, 并通过指定的filer进行过滤 */
ScoreRecordList getScore(const Datetime& date, std::function<bool(const ScoreRecord&)> filter);
ScoreRecordList getScores(const Datetime& date, size_t start, size_t end = Null<size_t>(),
std::function<bool(const Datetime&, const ScoreRecord&)>&& filter =
std::function<bool(const Datetime&, const ScoreRecord&)>());
/** 获取所有截面数据,已按降序排列 */
const vector<ScoreRecordList>& getAllScores();

View File

@ -244,7 +244,7 @@ void Portfolio::_runMoment(const Datetime& date, bool adjust) {
//----------------------------------------------------------------------
for (auto& sys : m_delay_adjust_sys_list) {
auto tr = sys.sys->sellForceOnOpen(date, sys.weight, PART_PORTFOLIO);
HKU_DEBUG_IF(trace && tr.isNull(), "[PF] Failed to force sell: {}", sys.sys->name());
// HKU_DEBUG_IF(trace && tr.isNull(), "[PF] Failed to force sell: {}", sys.sys->name());
if (!tr.isNull()) {
HKU_INFO_IF(trace, "[PF] Delay adjust sell: {}", tr);
m_tm->addTradeRecord(tr);

View File

@ -25,23 +25,36 @@ HKU_API std::ostream& operator<<(std::ostream& os, const SelectorPtr& st) {
}
SelectorBase::SelectorBase() : m_name("SelectorBase") {
// 是否单独执行原型系统,仅限用于测试目的
setParam<bool>("run_proto_sys", false);
initParam();
}
SelectorBase::SelectorBase(const string& name) : m_name(name) {
// 是否单独执行原型系统
setParam<bool>("run_proto_sys", false);
initParam();
}
SelectorBase::~SelectorBase() {}
void SelectorBase::initParam() {
// 通常原型系统不参与计算,但某些特殊的场景,需要依赖于伴生系统策略,
// 此时可以认为实际执行的系统行为跟随伴生系统的买卖交易如依赖于SG进行选择
// (不过由于仅依赖SG的场景不严谨因为原型和实际系统的SG是一样的)
// 此时需要在自身计算之前执行原型系统然后SE自行时可以使用。
// 而对于实际系统和被跟随的系统完全不一样的情况可以自行设计特殊的SE。
setParam<bool>("depend_on_proto_sys", false); // 此种情况,需要原型系统可独立运行
}
void SelectorBase::baseCheckParam(const string& name) const {}
void SelectorBase::paramChanged() {}
void SelectorBase::paramChanged() {
m_calculated = false;
m_proto_calculated = false;
}
void SelectorBase::removeAll() {
m_pro_sys_list = SystemList();
m_real_sys_list = SystemList();
m_pro_sys_list.clear();
m_real_sys_list.clear();
m_calculated = false;
m_proto_calculated = false;
}
void SelectorBase::reset() {
@ -52,6 +65,9 @@ void SelectorBase::reset() {
m_real_sys_list.clear();
_reset();
m_calculated = false;
m_proto_calculated = false;
}
SelectorPtr SelectorBase::clone() {
@ -70,6 +86,10 @@ SelectorPtr SelectorBase::clone() {
p->m_params = m_params;
p->m_name = m_name;
p->m_query = m_query;
p->m_proto_query = m_proto_query;
p->m_calculated = m_calculated;
p->m_proto_calculated = m_proto_calculated;
p->m_real_sys_list.reserve(m_real_sys_list.size());
for (const auto& sys : m_real_sys_list) {
@ -83,52 +103,57 @@ SelectorPtr SelectorBase::clone() {
return p;
}
void SelectorBase::calculate(const SystemList& sysList, const KQuery& query) {
m_real_sys_list = sysList;
if (getParam<bool>("run_proto_sys")) {
// 用于手工测试
void SelectorBase::calculate(const SystemList& pf_realSysList, const KQuery& query) {
HKU_IF_RETURN(m_calculated && m_query == query, void());
m_query = query;
m_real_sys_list = pf_realSysList;
// 需要依赖于运行系统,在自身运算之前完成计算
if (getParam<bool>("depend_on_proto_sys")) {
calculate_proto(query);
}
_calculate();
m_calculated = true;
}
void SelectorBase::calculate_proto(const KQuery& query) {
if (m_proto_query != query && !m_proto_calculated) {
for (auto& sys : m_pro_sys_list) {
sys->run(query);
}
m_proto_calculated = true;
m_proto_query = query;
}
_calculate();
}
bool SelectorBase::addStock(const Stock& stock, const SystemPtr& protoSys) {
HKU_ERROR_IF_RETURN(stock.isNull(), false, "Try add Null stock, will be discard!");
HKU_ERROR_IF_RETURN(!protoSys, false, "Try add Null protoSys, will be discard!");
HKU_ERROR_IF_RETURN(!protoSys->getMM(), false, "protoSys has not MoneyManager!");
HKU_ERROR_IF_RETURN(!protoSys->getSG(), false, "protoSys has not Siganl!");
SYSPtr sys = protoSys->clone();
// 每个系统独立,不共享 tm
sys->setParam<bool>("shared_tm", false);
void SelectorBase::addStock(const Stock& stock, const SystemPtr& protoSys) {
HKU_CHECK(!stock.isNull(), "The input stock is null!");
HKU_CHECK(protoSys, "The input stock is null!");
HKU_CHECK(protoSys->getMM(), "protoSys missing MoneyManager!");
HKU_CHECK(protoSys->getSG(), "protoSys missing Siganl!");
HKU_CHECK(!protoSys->getParam<bool>("shared_tm"), "Unsupport shared TM for protoSys!");
if (getParam<bool>("depend_on_proto_sys")) {
HKU_CHECK(protoSys->getTM(),
"Scenarios that depend on prototype systems need to specify a TM!");
}
auto proto = protoSys;
proto->forceResetAll();
SYSPtr sys = proto->clone();
sys->reset();
sys->setStock(stock);
m_pro_sys_list.emplace_back(sys);
return true;
m_calculated = false;
m_proto_calculated = false;
}
bool SelectorBase::addStockList(const StockList& stkList, const SystemPtr& protoSys) {
HKU_ERROR_IF_RETURN(!protoSys, false, "Try add Null protoSys, will be discard!");
HKU_ERROR_IF_RETURN(!protoSys->getMM(), false, "protoSys has not MoneyManager!");
HKU_ERROR_IF_RETURN(!protoSys->getSG(), false, "protoSys has not Signal!");
SYSPtr newProtoSys = protoSys->clone();
// 复位清除之前的数据,避免因原有数据过多导致下面循环时速度过慢
// 每个系统独立,不共享 tm
newProtoSys->setParam<bool>("shared_tm", false);
newProtoSys->reset();
StockList::const_iterator iter = stkList.begin();
for (; iter != stkList.end(); ++iter) {
if (iter->isNull()) {
HKU_WARN("Try add Null stock, will be discard!");
continue;
}
SYSPtr sys = newProtoSys->clone();
sys->setStock(*iter);
m_pro_sys_list.emplace_back(sys);
void SelectorBase::addStockList(const StockList& stkList, const SystemPtr& protoSys) {
for (const auto& stk : stkList) {
addStock(stk, protoSys);
}
return true;
}
} /* namespace hku */

View File

@ -50,7 +50,7 @@ public:
* @param protoSys
* @return protoSys stock false true
*/
bool addStock(const Stock& stock, const SystemPtr& protoSys);
void addStock(const Stock& stock, const SystemPtr& protoSys);
/**
*
@ -59,7 +59,7 @@ public:
* @param protoSys
* @return protoSys false true
*/
bool addStockList(const StockList& stkList, const SystemPtr& protoSys);
void addStockList(const StockList& stkList, const SystemPtr& protoSys);
/**
* @brief
@ -102,10 +102,20 @@ public:
virtual bool isMatchAF(const AFPtr& af) = 0;
/* 仅供PF调用由PF通知其实际运行的系统列表并启动计算 */
void calculate(const SystemList& sysList, const KQuery& query);
void calculate(const SystemList& pf_realSysList, const KQuery& query);
void calculate_proto(const KQuery& query);
private:
void initParam();
protected:
string m_name;
bool m_calculated{false}; // 是否已计算过
bool m_proto_calculated{false};
KQuery m_query;
KQuery m_proto_query;
SystemList m_pro_sys_list; // 原型系统列表
SystemList m_real_sys_list; // PF组合中实际运行的系统有PF执行时设定顺序与原型列表一一对应

View File

@ -29,64 +29,55 @@ TEST_CASE("test_SE_Fixed") {
SYSPtr sys = SYS_Simple();
SEPtr se = SE_Fixed();
// /** @arg 试图加入一个不存在的stock */
// se->addStock(Stock(), sys);
// SystemWeightList result = se->getSelectedOnOpen(Datetime(200001010000L));
// CHECK_EQ(result.size(), 0);
/** @arg 试图加入一个不存在的stock */
CHECK_THROWS_AS(se->addStock(Stock(), sys), std::exception);
// /** @arg 试图加入一个空的系统策略原型 */
// se->addStock(sm["sh600000"], SYSPtr());
// result = se->getSelectedOnOpen(Datetime(200001010000L));
// CHECK_EQ(result.size(), 0);
/** @arg 试图加入一个空的系统策略原型 */
CHECK_THROWS_AS(se->addStock(sm["sh600000"], SYSPtr()), std::exception);
// /** @arg 试图加入一个缺少MM的系统策略原型 */
// SGPtr sg = SG_Cross(MA(CLOSE(), 5), MA(CLOSE(), 10));
// MMPtr mm = MM_FixedCount(100);
// CHECK_UNARY(!se->addStock(sm["sh600000"], sys));
// /** @arg 试图加入一个缺少MM | SG的系统策略原型 */
SGPtr sg = SG_Cross(MA(CLOSE(), 5), MA(CLOSE(), 10));
MMPtr mm = MM_FixedCount(100);
sys->setSG(sg);
CHECK_THROWS_AS(se->addStock(sm["sh600000"], sys), std::exception);
// /* @arg 试图加入一个未指定SG的系统原型 */
// sys->setMM(mm);
// CHECK_UNARY(!se->addStock(sm["sh600000"], sys));
sys->setSG(SGPtr());
sys->setMM(mm);
CHECK_THROWS_AS(se->addStock(sm["sh600000"], sys), std::exception);
// 目前必须有PF指定实际执行的子系统下面代码无法执行
// /** @arg getSelectedSystemList */
// sys->setSG(sg);
// se->addStock(sm["sh600000"], sys);
// se->addStock(sm["sz000001"], sys);
// se->addStock(sm["sz000002"], sys);
sys->setSG(sg);
se->addStock(sm["sh600000"], sys);
se->addStock(sm["sz000001"], sys);
se->addStock(sm["sz000002"], sys);
// se->reset();
// result = se->getSelectedSystemList(Datetime(200001010000L));
// CHECK_EQ(result.size(), 3);
// CHECK_EQ(sm["sh600000"], result[0]->getStock());
// CHECK_EQ(sm["sz000001"], result[1]->getStock());
// CHECK_EQ(sm["sz000002"], result[2]->getStock());
auto proto_sys_list = se->getProtoSystemList();
CHECK_EQ(proto_sys_list.size(), 3);
// /** @arg clear */
// se->clear();
// result = se->getSelectedSystemList(Datetime(200001010000L));
// CHECK_EQ(result.size(), 0);
se->calculate(proto_sys_list, KQuery(-20));
auto result = se->getSelected(Datetime(200001010000L));
CHECK_EQ(result.size(), 3);
CHECK_EQ(sm["sh600000"], result[0].sys->getStock());
CHECK_EQ(sm["sz000001"], result[1].sys->getStock());
CHECK_EQ(sm["sz000002"], result[2].sys->getStock());
// /** @arg reset */
// se->addStock(sm["sh600000"], sys);
// se->addStock(sm["sz000001"], sys);
// se->addStock(sm["sz000002"], sys);
// se->reset();
// result = se->getSelectedSystemList(Datetime(200001010000L));
// CHECK_EQ(result.size(), 3);
// CHECK_EQ(sm["sh600000"], result[0]->getStock());
// CHECK_EQ(sm["sz000001"], result[1]->getStock());
// CHECK_EQ(sm["sz000002"], result[2]->getStock());
/** @arg reset */
se->reset();
result = se->getSelected(Datetime(200001010000L));
CHECK_EQ(result.size(), 0);
// /** @arg 克隆操作 */
// SEPtr se2;
// se2 = se->clone();
// CHECK_NE(se2.get(), se.get());
// result = se2->getSelectedSystemList(Datetime(200001010000L));
// CHECK_EQ(result.size(), 3);
// CHECK_EQ(sm["sh600000"], result[0]->getStock());
// CHECK_EQ(sm["sz000001"], result[1]->getStock());
// CHECK_EQ(sm["sz000002"], result[2]->getStock());
/** @arg 克隆操作 */
proto_sys_list = se->getProtoSystemList();
se->calculate(proto_sys_list, KQuery(-20));
SEPtr se2;
se2 = se->clone();
CHECK_NE(se2.get(), se.get());
result = se2->getSelected(Datetime(200001010000L));
CHECK_EQ(result.size(), 3);
CHECK_EQ(sm["sh600000"], result[0].sys->getStock());
CHECK_EQ(sm["sz000001"], result[1].sys->getStock());
CHECK_EQ(sm["sz000002"], result[2].sys->getStock());
}
/** @} */

View File

@ -13,6 +13,11 @@
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <hikyuu/StockManager.h>
#include <hikyuu/trade_manage/crt/crtTM.h>
#include <hikyuu/trade_sys/signal/crt/SG_Cross.h>
#include <hikyuu/trade_sys/moneymanager/crt/MM_FixedCount.h>
#include <hikyuu/indicator/crt/KDATA.h>
#include <hikyuu/indicator/crt/MA.h>
#include <hikyuu/trade_sys/selector/crt/SE_Fixed.h>
#include <hikyuu/trade_sys/system/crt/SYS_Simple.h>
@ -30,7 +35,13 @@ TEST_CASE("test_SE_FIXED_export") {
string filename(sm.tmpdir());
filename += "/SE_FIXED.xml";
TMPtr tm = crtTM(Datetime(20010101), 100000);
SGPtr sg = SG_Cross(MA(CLOSE(), 5), MA(CLOSE(), 10));
MMPtr mm = MM_FixedCount(100);
SYSPtr sys = SYS_Simple();
sys->setTM(tm);
sys->setSG(sg);
sys->setMM(mm);
StockList stkList;
stkList.push_back(sm["sh600000"]);
stkList.push_back(sm["sz000001"]);

View File

@ -38,7 +38,6 @@ void export_MultiFactor(py::module& m) {
.def_readwrite("stock", &ScoreRecord::stock, "时间")
.def_readwrite("value", &ScoreRecord::value, "时间");
size_t null_size = Null<size_t>();
py::class_<MultiFactorBase, MultiFactorPtr, PyMultiFactor>(m, "MultiFactorBase",
R"(市场环境判定策略基类
@ -122,11 +121,31 @@ void export_MultiFactor(py::module& m) {
.def("clone", &MultiFactorBase::clone, "克隆操作")
.def(
"get_score",
[](MultiFactorBase& self, const Datetime& date, size_t start, size_t end) {
return self.getScore(date, start, end);
"get_scores",
[](MultiFactorBase& self, const Datetime& date, size_t start, py::object end,
py::object filter) {
size_t cend = end.is_none() ? Null<size_t>() : end.cast<size_t>();
if (filter.is_none()) {
return self.getScores(date, start, cend, std::function<bool(const ScoreRecord&)>());
}
HKU_CHECK(py::hasattr(filter, "__call__"), "filter not callable!");
py::object filter_func = filter.attr("__call__");
ScoreRecord sc;
try {
filter_func(sc);
return self.getScores(date, start, cend, [&](const ScoreRecord& score_) {
return filter_func(score_).cast<bool>();
});
} catch (...) {
filter_func(date, sc);
return self.getScores(date, start, cend,
[&](const Datetime& date_, const ScoreRecord& score_) {
return filter_func(date_, score_).cast<bool>();
});
}
},
py::arg("datet"), py::arg("start") = 0, py::arg("end") = null_size,
py::arg("datet"), py::arg("start") = 0, py::arg("end") = py::none(),
py::arg("filter") = py::none(),
R"(get_score(self, date[, start=0, end=Null])
@ -134,22 +153,15 @@ void export_MultiFactor(py::module& m) {
:param Datetime date:
:param int start:
:param int end: ()
:param function func: (ScoreRecord)->bool (Datetime, ScoreRecord)->bool
:rtype: ScoreRecordList)")
.def("get_score",
[](MultiFactorBase& self, const Datetime& date, py::object filter) {
HKU_CHECK(py::hasattr(filter, "__call__"), "filter not callable!");
py::object filter_func = filter.attr("__call__");
return self.getScore(
date, [&](const ScoreRecord& score) { return filter_func(score).cast<bool>(); });
})
.def("get_all_scores", &MultiFactorBase::getAllScores, py::return_value_policy::copy,
R"(get_all_scores(self)
:return: ScoreRecordList list)")
:return: ScoreRecordList)")
.def("get_all_src_factors", &MultiFactorBase::getAllSrcFactors)
@ -158,12 +170,15 @@ void export_MultiFactor(py::module& m) {
m.def(
"MF_EqualWeight",
[](const py::sequence& inds, const py::sequence& stks, const KQuery& query,
const Stock& ref_stk, int ic_n) {
const py::object& ref_stk, int ic_n) {
IndicatorList c_inds = python_list_to_vector<Indicator>(inds);
StockList c_stks = python_list_to_vector<Stock>(stks);
return MF_EqualWeight(c_inds, c_stks, query, ref_stk, ic_n);
return MF_EqualWeight(c_inds, c_stks, query,
ref_stk.is_none() ? getStock("sh000300") : ref_stk.cast<Stock>(),
ic_n);
},
py::arg("inds"), py::arg("stks"), py::arg("query"), py::arg("ref_stk"), py::arg("ic_n") = 5,
py::arg("inds"), py::arg("stks"), py::arg("query"), py::arg("ref_stk") = py::none(),
py::arg("ic_n") = 5,
R"(MF_EqualWeight(inds, stks, query, ref_stk[, ic_n=5])
@ -171,21 +186,22 @@ void export_MultiFactor(py::module& m) {
:param sequense(Indicator) inds:
:param sequense(stock) stks:
:param Query query:
:param Stock ref_stk:
:param Stock ref_stk: ( sh000300 300)
:param int ic_n: IC N
:rtype: MultiFactor)");
m.def(
"MF_ICWeight",
[](const py::sequence& inds, const py::sequence& stks, const KQuery& query,
const Stock& ref_stk, int ic_n, int ic_rolling_n) {
// MF_EqualWeight
const py::object& ref_stk, int ic_n, int ic_rolling_n) {
IndicatorList c_inds = python_list_to_vector<Indicator>(inds);
StockList c_stks = python_list_to_vector<Stock>(stks);
return MF_ICWeight(c_inds, c_stks, query, ref_stk, ic_n, ic_rolling_n);
return MF_ICWeight(c_inds, c_stks, query,
ref_stk.is_none() ? getStock("sh000300") : ref_stk.cast<Stock>(), ic_n,
ic_rolling_n);
},
py::arg("inds"), py::arg("stks"), py::arg("query"), py::arg("ref_stk"), py::arg("ic_n") = 5,
py::arg("ic_rolling_n") = 120,
py::arg("inds"), py::arg("stks"), py::arg("query"), py::arg("ref_stk") = py::none(),
py::arg("ic_n") = 5, py::arg("ic_rolling_n") = 120,
R"(MF_EqualWeight(inds, stks, query, ref_stk[, ic_n=5, ic_rolling_n=120])
IC权重合成因子
@ -193,7 +209,7 @@ void export_MultiFactor(py::module& m) {
:param sequense(Indicator) inds:
:param sequense(stock) stks:
:param Query query:
:param Stock ref_stk:
:param Stock ref_stk: ( sh000300 300)
:param int ic_n: IC N
:param int ic_rolling_n: IC
:rtype: MultiFactor)");
@ -201,14 +217,15 @@ void export_MultiFactor(py::module& m) {
m.def(
"MF_ICIRWeight",
[](const py::sequence& inds, const py::sequence& stks, const KQuery& query,
const Stock& ref_stk, int ic_n, int ic_rolling_n) {
// MF_EqualWeight
const py::object& ref_stk, int ic_n, int ic_rolling_n) {
IndicatorList c_inds = python_list_to_vector<Indicator>(inds);
StockList c_stks = python_list_to_vector<Stock>(stks);
return MF_ICIRWeight(c_inds, c_stks, query, ref_stk, ic_n, ic_rolling_n);
return MF_ICIRWeight(c_inds, c_stks, query,
ref_stk.is_none() ? getStock("sh000300") : ref_stk.cast<Stock>(),
ic_n, ic_rolling_n);
},
py::arg("inds"), py::arg("stks"), py::arg("query"), py::arg("ref_stk"), py::arg("ic_n") = 5,
py::arg("ic_rolling_n") = 120,
py::arg("inds"), py::arg("stks"), py::arg("query"), py::arg("ref_stk") = py::none(),
py::arg("ic_n") = 5, py::arg("ic_rolling_n") = 120,
R"(MF_EqualWeight(inds, stks, query, ref_stk[, ic_n=5, ic_rolling_n=120])
ICIR权重合成因子
@ -216,7 +233,7 @@ void export_MultiFactor(py::module& m) {
:param sequense(Indicator) inds:
:param sequense(stock) stks:
:param Query query:
:param Stock ref_stk:
:param Stock ref_stk: ( sh000300 300)
:param int ic_n: IC N
:param int ic_rolling_n: IC
:rtype: MultiFactor)");