diff --git a/hikyuu/hub.py b/hikyuu/hub.py index c29879de..4fc7f02d 100644 --- a/hikyuu/hub.py +++ b/hikyuu/hub.py @@ -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): diff --git a/hikyuu/trade_sys/trade_sys.py b/hikyuu/trade_sys/trade_sys.py index e43d5604..62f78154 100644 --- a/hikyuu/trade_sys/trade_sys.py +++ b/hikyuu/trade_sys/trade_sys.py @@ -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 # ------------------------------------------------------------------ diff --git a/hikyuu_cpp/hikyuu/trade_sys/allocatefunds/AllocateFundsBase.cpp b/hikyuu_cpp/hikyuu/trade_sys/allocatefunds/AllocateFundsBase.cpp index ad789ac1..2b715bb1 100644 --- a/hikyuu_cpp/hikyuu/trade_sys/allocatefunds/AllocateFundsBase.cpp +++ b/hikyuu_cpp/hikyuu/trade_sys/allocatefunds/AllocateFundsBase.cpp @@ -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(); diff --git a/hikyuu_cpp/hikyuu/trade_sys/factor/MultiFactorBase.cpp b/hikyuu_cpp/hikyuu/trade_sys/factor/MultiFactorBase.cpp index 78921f6f..7c7bf1db 100644 --- a/hikyuu_cpp/hikyuu/trade_sys/factor/MultiFactorBase.cpp +++ b/hikyuu_cpp/hikyuu/trade_sys/factor/MultiFactorBase.cpp @@ -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&& 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 filter) { +ScoreRecordList MultiFactorBase::getScores( + const Datetime& date, size_t start, size_t end, + std::function&& 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() || 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; } diff --git a/hikyuu_cpp/hikyuu/trade_sys/factor/MultiFactorBase.h b/hikyuu_cpp/hikyuu/trade_sys/factor/MultiFactorBase.h index b7cae809..3dcf7fca 100644 --- a/hikyuu_cpp/hikyuu/trade_sys/factor/MultiFactorBase.h +++ b/hikyuu_cpp/hikyuu/trade_sys/factor/MultiFactorBase.h @@ -82,10 +82,20 @@ public: /** 获取指定日期截面的所有因子值,已经降序排列 */ const ScoreRecordList& getScore(const Datetime&); - ScoreRecordList getScore(const Datetime& date, size_t start, size_t end = Null()); + /** + * 获取指定日期截面 [start, end] 范围内的因子值(评分), 并通过filer进行过滤 + * @param date 指定日期 + * @param start 排序起始点 + * @param end 排序起始点(不含该点) + * @param filter 过滤函数 + */ + ScoreRecordList getScores( + const Datetime& date, size_t start, size_t end = Null(), + std::function&& filter = std::function()); - /** 获取指定日期截面的所有因子值, 并通过指定的filer进行过滤 */ - ScoreRecordList getScore(const Datetime& date, std::function filter); + ScoreRecordList getScores(const Datetime& date, size_t start, size_t end = Null(), + std::function&& filter = + std::function()); /** 获取所有截面数据,已按降序排列 */ const vector& getAllScores(); diff --git a/hikyuu_cpp/hikyuu/trade_sys/portfolio/Portfolio.cpp b/hikyuu_cpp/hikyuu/trade_sys/portfolio/Portfolio.cpp index ebd7d37b..3ca54f0f 100644 --- a/hikyuu_cpp/hikyuu/trade_sys/portfolio/Portfolio.cpp +++ b/hikyuu_cpp/hikyuu/trade_sys/portfolio/Portfolio.cpp @@ -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); diff --git a/hikyuu_cpp/hikyuu/trade_sys/selector/SelectorBase.cpp b/hikyuu_cpp/hikyuu/trade_sys/selector/SelectorBase.cpp index 08f64c7a..58b99da0 100644 --- a/hikyuu_cpp/hikyuu/trade_sys/selector/SelectorBase.cpp +++ b/hikyuu_cpp/hikyuu/trade_sys/selector/SelectorBase.cpp @@ -25,23 +25,36 @@ HKU_API std::ostream& operator<<(std::ostream& os, const SelectorPtr& st) { } SelectorBase::SelectorBase() : m_name("SelectorBase") { - // 是否单独执行原型系统,仅限用于测试目的 - setParam("run_proto_sys", false); + initParam(); } SelectorBase::SelectorBase(const string& name) : m_name(name) { - // 是否单独执行原型系统 - setParam("run_proto_sys", false); + initParam(); } SelectorBase::~SelectorBase() {} +void SelectorBase::initParam() { + // 通常原型系统不参与计算,但某些特殊的场景,需要依赖于伴生系统策略, + // 此时可以认为实际执行的系统行为跟随伴生系统的买卖交易,如依赖于SG进行选择 + // (不过由于仅依赖SG的场景不严谨,因为原型和实际系统的SG是一样的) + // 此时,需要在自身计算之前执行原型系统,然后SE自行时可以使用。 + // 而对于实际系统和被跟随的系统完全不一样的情况,可以自行设计特殊的SE。 + setParam("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("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("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("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("shared_tm"), "Unsupport shared TM for protoSys!"); + if (getParam("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("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 */ diff --git a/hikyuu_cpp/hikyuu/trade_sys/selector/SelectorBase.h b/hikyuu_cpp/hikyuu/trade_sys/selector/SelectorBase.h index 267a7992..1531359c 100644 --- a/hikyuu_cpp/hikyuu/trade_sys/selector/SelectorBase.h +++ b/hikyuu_cpp/hikyuu/trade_sys/selector/SelectorBase.h @@ -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执行时设定,顺序与原型列表一一对应 diff --git a/hikyuu_cpp/unit_test/hikyuu/trade_sys/selector/test_SE_Fixed.cpp b/hikyuu_cpp/unit_test/hikyuu/trade_sys/selector/test_SE_Fixed.cpp index e4d1b230..a29a478a 100644 --- a/hikyuu_cpp/unit_test/hikyuu/trade_sys/selector/test_SE_Fixed.cpp +++ b/hikyuu_cpp/unit_test/hikyuu/trade_sys/selector/test_SE_Fixed.cpp @@ -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()); } /** @} */ diff --git a/hikyuu_cpp/unit_test/hikyuu/trade_sys/selector/test_export.cpp b/hikyuu_cpp/unit_test/hikyuu/trade_sys/selector/test_export.cpp index 10d3f2b4..f2287fc4 100644 --- a/hikyuu_cpp/unit_test/hikyuu/trade_sys/selector/test_export.cpp +++ b/hikyuu_cpp/unit_test/hikyuu/trade_sys/selector/test_export.cpp @@ -13,6 +13,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include @@ -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"]); diff --git a/hikyuu_pywrap/trade_sys/_MultiFactor.cpp b/hikyuu_pywrap/trade_sys/_MultiFactor.cpp index 718d8f23..5051d506 100644 --- a/hikyuu_pywrap/trade_sys/_MultiFactor.cpp +++ b/hikyuu_pywrap/trade_sys/_MultiFactor.cpp @@ -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(); py::class_(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() : end.cast(); + if (filter.is_none()) { + return self.getScores(date, start, cend, std::function()); + } + 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(); + }); + } catch (...) { + filter_func(date, sc); + return self.getScores(date, start, cend, + [&](const Datetime& date_, const ScoreRecord& score_) { + return filter_func(date_, score_).cast(); + }); + } }, - 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(); }); - }) - .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(inds); StockList c_stks = python_list_to_vector(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(), + 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(inds); StockList c_stks = python_list_to_vector(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(), 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(inds); StockList c_stks = python_list_to_vector(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(), + 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)");