参数寻优(continue)

This commit is contained in:
KongDong 2024-09-07 10:30:35 +08:00
parent 6b1bbc2a8b
commit fd2bac268f
9 changed files with 539 additions and 5 deletions

View File

@ -0,0 +1,195 @@
/*
* Copyright (c) 2019~2023, hikyuu.org
*
* History:
* 1. 20240907 added by fasiondog
*/
#include "hikyuu/trade_manage/Performance.h"
#include "optimize.h"
namespace hku {
static std::pair<double, SYSPtr> runSysWithOptimizeParam(
const SYSPtr& sys, const Stock& stk, const KQuery& query, const Datetime& lastDate,
const vector<std::pair<SystemPart, Parameter>>& params, const std::string& out_key) {
for (const auto& combinate_param : params) {
if (SystemPart::PART_ENVIRONMENT == combinate_param.first) {
auto ev = sys->getEV();
if (ev) {
for (auto iter = combinate_param.second.begin();
iter != combinate_param.second.end(); ++iter) {
ev->setParam<boost::any>(iter->first, iter->second);
}
}
} else if (SystemPart::PART_CONDITION == combinate_param.first) {
auto cn = sys->getCN();
if (cn) {
for (auto iter = combinate_param.second.begin();
iter != combinate_param.second.end(); ++iter) {
cn->setParam<boost::any>(iter->first, iter->second);
}
}
} else if (SystemPart::PART_SIGNAL == combinate_param.first) {
auto sg = sys->getSG();
if (sg) {
for (auto iter = combinate_param.second.begin();
iter != combinate_param.second.end(); ++iter) {
sg->setParam<boost::any>(iter->first, iter->second);
}
}
} else if (SystemPart::PART_STOPLOSS == combinate_param.first) {
auto st = sys->getST();
if (st) {
for (auto iter = combinate_param.second.begin();
iter != combinate_param.second.end(); ++iter) {
st->setParam<boost::any>(iter->first, iter->second);
}
}
} else if (SystemPart::PART_TAKEPROFIT == combinate_param.first) {
auto tp = sys->getTP();
if (tp) {
for (auto iter = combinate_param.second.begin();
iter != combinate_param.second.end(); ++iter) {
tp->setParam<boost::any>(iter->first, iter->second);
}
}
} else if (SystemPart::PART_MONEYMANAGER == combinate_param.first) {
auto mm = sys->getMM();
if (mm) {
for (auto iter = combinate_param.second.begin();
iter != combinate_param.second.end(); ++iter) {
mm->setParam<boost::any>(iter->first, iter->second);
}
}
} else if (SystemPart::PART_PROFITGOAL == combinate_param.first) {
auto pg = sys->getPG();
if (pg) {
for (auto iter = combinate_param.second.begin();
iter != combinate_param.second.end(); ++iter) {
pg->setParam<boost::any>(iter->first, iter->second);
}
}
} else {
HKU_WARN("Not support part: {}", int(combinate_param.first));
}
}
sys->run(stk, query);
Performance per;
per.statistics(sys->getTM(), lastDate);
double val = per.get(out_key);
return std::make_pair(val, sys);
}
SYSPtr HKU_API findOptimizeParam(const SYSPtr& sys, const Stock& stk, const KQuery& query,
const OptimizeParamList& optParams, const string& sort_key) {
HKU_ASSERT(sys && sys->getTM());
HKU_ASSERT(!stk.isNull());
HKU_ASSERT(!optParams.empty());
string statistic_key = sort_key.empty() ? "帐户平均年收益率%" : sort_key;
HKU_CHECK(Performance::exist(statistic_key),
"Invalid sort key: {}! A statistical item does not exist!", statistic_key);
auto date_list = StockManager::instance().getTradingCalendar(query);
HKU_CHECK(!date_list.empty(),
"Invalid query: {}! The statistical end date could not be determined!", query);
Datetime last_datetime = date_list.back();
sys->setNotSharedAll();
sys->forceResetAll();
ThreadPool tg;
vector<std::future<std::pair<double, SYSPtr>>> tasks;
vector<std::pair<SystemPart, Parameter>> sys_param;
Parameter param;
while (true) {
size_t finished_count = 0;
for (const auto& opt_param : optParams) {
if (opt_param->type() == OptimizeParam::OPT_PARAM_INT) {
OptimizeParamInt* p = dynamic_cast<OptimizeParamInt*>(opt_param.get());
int value = p->getValue();
if (value != Null<int>()) {
param.set<int>(p->name(), value);
sys_param.emplace_back(std::make_pair(opt_param->part(), std::move(param)));
} else {
finished_count++;
}
} else if (opt_param->type() == OptimizeParam::OPT_PARAM_DOUBLE) {
OptimizeParamDouble* p = dynamic_cast<OptimizeParamDouble*>(opt_param.get());
double value = p->getValue();
if (value != Null<double>()) {
param.set<double>(p->name(), value);
sys_param.emplace_back(std::make_pair(opt_param->part(), std::move(param)));
} else {
finished_count++;
}
} else if (opt_param->type() == OptimizeParam::OPT_PARAM_BOOL) {
OptimizeParamBool* p = dynamic_cast<OptimizeParamBool*>(opt_param.get());
uint8_t value = p->getValue();
if (value >= 0) {
param.set<>(p->name(), static_cast<bool>(value));
sys_param.emplace_back(std::make_pair(opt_param->part(), std::move(param)));
} else {
finished_count++;
}
} else if (opt_param->type() == OptimizeParam::OPT_PARAM_STRING) {
OptimizeParamString* p = dynamic_cast<OptimizeParamString*>(opt_param.get());
string value = p->getValue();
if (!value.empty()) {
param.set<string>(p->name(), value);
sys_param.emplace_back(std::make_pair(opt_param->part(), std::move(param)));
} else {
finished_count++;
}
} else {
finished_count++;
HKU_WARN("Ignore unknown opt param type: {}", int(opt_param->type()));
continue;
}
}
if (!sys_param.empty()) {
tasks.emplace_back(
tg.submit([stk, query, &statistic_key, last_datetime, new_sys = sys->clone(),
new_params = std::move(sys_param)]() {
try {
return runSysWithOptimizeParam(new_sys, stk, query, last_datetime, new_params,
statistic_key);
} catch (const std::exception& e) {
HKU_ERROR(e.what());
return std::make_pair(std::numeric_limits<double>::min(), new_sys);
} catch (...) {
HKU_ERROR_UNKNOWN;
return std::make_pair(std::numeric_limits<double>::min(), new_sys);
}
}));
}
if (finished_count >= optParams.size()) {
break;
}
}
vector<std::pair<double, SYSPtr>> all_result;
for (auto& task : tasks) {
all_result.emplace_back(task.get());
}
SYSPtr ret;
if (!all_result.empty()) {
std::sort(all_result.begin(), all_result.end(),
[](const std::pair<double, SYSPtr>& a, const std::pair<double, SYSPtr>& b) {
return a.first > b.first;
});
ret = all_result.front().second;
}
return ret;
}
} // namespace hku

View File

@ -0,0 +1,165 @@
/*
* Copyright (c) 2019~2023, hikyuu.org
*
* History:
* 1. 20240907 added by fasiondog
*/
#pragma once
#include "hikyuu/trade_sys/system/System.h"
namespace hku {
class HKU_API OptimizeParam {
public:
enum OPTIMIZE_PARAM_TYPE {
OPT_PARAM_INT,
OPT_PARAM_DOUBLE,
OPT_PARAM_BOOL,
OPT_PARAM_STRING,
OPT_PARAM_INVLID,
};
OptimizeParam() = default;
OptimizeParam(SystemPart part, const string& name_, OPTIMIZE_PARAM_TYPE type_)
: m_name(name_), m_part(part), m_type(type_) {}
virtual ~OptimizeParam() = default;
SystemPart part() const noexcept {
return m_part;
}
const string& name() const noexcept {
return m_name;
}
OPTIMIZE_PARAM_TYPE type() const noexcept {
return m_type;
}
virtual string str() const {
return fmt::format("OptimizeParam({}, {})", getSystemPartName(m_part), m_name);
}
protected:
string m_name;
SystemPart m_part;
OPTIMIZE_PARAM_TYPE m_type{OPT_PARAM_INVLID};
};
typedef std::shared_ptr<OptimizeParam> OptimizeParamPtr;
typedef std::vector<OptimizeParamPtr> OptimizeParamList;
class HKU_API OptimizeParamInt : public OptimizeParam {
public:
OptimizeParamInt() = default;
OptimizeParamInt(SystemPart part, const string& name, int start_, int end_, int step_ = 1)
: OptimizeParam(part, name, OPT_PARAM_INT),
m_start(start_),
m_end(end_),
m_step(step_),
m_current(start_) {}
virtual ~OptimizeParamInt() = default;
int getValue() {
HKU_IF_RETURN(m_current >= m_end, Null<int>());
int ret = m_current;
m_current += m_step;
return ret;
}
virtual string str() const override {
return fmt::format("OptimizeParamInt({}, {}, {}, {}, {})", getSystemPartName(m_part),
m_name, m_start, m_end, m_step);
}
private:
int m_start{0};
int m_end{0};
int m_step{0};
int m_current{0};
};
class HKU_API OptimizeParamDouble : public OptimizeParam {
public:
OptimizeParamDouble() = default;
OptimizeParamDouble(SystemPart part, const string& name, double start_, double end_,
double step_)
: OptimizeParam(part, name, OPT_PARAM_DOUBLE),
m_start(start_),
m_end(end_),
m_step(step_),
m_current(start_) {}
virtual ~OptimizeParamDouble() = default;
double getValue() {
HKU_IF_RETURN(m_current >= m_step, Null<double>());
double ret = m_current;
m_current += m_step;
return ret;
}
virtual string str() const override {
return fmt::format("OptimizeParamDouble({}, {}, {}, {}, {})", getSystemPartName(m_part),
m_name, m_start, m_end, m_step);
}
private:
double m_start{0.0};
double m_end{0.0};
double m_step{0.0};
double m_current{0.0};
};
class HKU_API OptimizeParamBool : public OptimizeParam {
public:
OptimizeParamBool() = default;
OptimizeParamBool(SystemPart part, const string& name)
: OptimizeParam(part, name, OPT_PARAM_BOOL) {}
virtual ~OptimizeParamBool() = default;
uint8_t getValue() {
HKU_IF_RETURN(m_current >= 2, -1);
uint8_t ret = m_current;
m_current++;
return ret;
}
virtual string str() const override {
return fmt::format("OptimizeParamBool({}, {})", getSystemPartName(m_part), m_name);
}
private:
uint8_t m_current{0};
};
class HKU_API OptimizeParamString : public OptimizeParam {
public:
OptimizeParamString() = default;
OptimizeParamString(SystemPart part, const string& name, const StringList& values_)
: OptimizeParam(part, name, OPT_PARAM_STRING), m_values(values_) {}
virtual ~OptimizeParamString() = default;
string getValue() {
HKU_IF_RETURN(m_current >= m_values.size(), Null<string>());
string ret = m_values[m_current];
m_current++;
return ret;
}
virtual string str() const override {
return fmt::format("OptimizeParamString({}, {}, values=...)", getSystemPartName(m_part),
m_name);
}
private:
StringList m_values;
size_t m_current;
};
SYSPtr HKU_API findOptimizeParam(const SYSPtr& sys, const Stock& stk, const KQuery& query,
const OptimizeParamList& optParams,
const string& sort_key = string());
} // namespace hku

View File

@ -17,7 +17,8 @@
* \n
*
* @section test_rule
* 1使 \n
* 1使
* \n
* 2test_suitetest_模块名)_suite
* IniParsertest_iniparser_suite使 \n
* 3使test_模块名.cpp \n
@ -37,6 +38,7 @@
* @defgroup test_hikyuu_indicator_suite test_hikyuu_indicator_suite
* @defgroup test_hikyuu_trade_manage_suite test_hikyuu_trade_manage_suite
* @defgroup test_hikyuu_trade_sys_suite test_hikyuu_trade_sys_suite
* @defgroup test_hikyuu_analysis_suite test_hikyuu_analysis_suite
*
*
*/

View File

@ -13,7 +13,7 @@ using namespace hku;
/**
* @defgroup test_hikyuu_combinate test_hikyuu_combinate
* @ingroup test_hikyuu_combinate_suite
* @ingroup test_hikyuu_analysis_suite
* @{
*/

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2019~2023, hikyuu.org
*
* History:
* 1. 20240907 added by fasiondog
*/
#include "../test_config.h"
#include <hikyuu/analysis/optimize.h>
using namespace hku;
/**
* @defgroup test_hikyuu_optimize test_hikyuu_optimize
* @ingroup test_hikyuu_analysis_suite
* @{
*/
/** @par 检测点 */
TEST_CASE("test_findOptimizeParam") {}
/** @} */

View File

@ -7,7 +7,7 @@
#include <hikyuu/analysis/combinate.h>
#include <hikyuu/analysis/analysis_sys.h>
#include "pybind_utils.h"
#include "../pybind_utils.h"
using namespace hku;
namespace py = pybind11;

View File

@ -0,0 +1,131 @@
/*
* Copyright (c) 2019~2023, hikyuu.org
*
* History:
* 1. 20240907 added by fasiondog
*/
#include <hikyuu/analysis/optimize.h>
#include "../pybind_utils.h"
using namespace hku;
namespace py = pybind11;
class PyOptimizeParamInt {
public:
PyOptimizeParamInt(SystemPart part, const string& name, int start, int end, int step) {
m_param = std::make_shared<OptimizeParamInt>(part, name, start, end, step);
}
OptimizeParamPtr get() {
return m_param;
}
string str() const {
return m_param->str();
}
private:
OptimizeParamPtr m_param;
};
class PyOptimizeParamDouble {
public:
PyOptimizeParamDouble(SystemPart part, const string& name, double start, double end,
double step) {
m_param = std::make_shared<OptimizeParamDouble>(part, name, start, end, step);
}
OptimizeParamPtr get() {
return m_param;
}
string str() const {
return m_param->str();
}
private:
OptimizeParamPtr m_param;
};
class PyOptimizeParamBool {
public:
PyOptimizeParamBool(SystemPart part, const string& name) {
m_param = std::make_shared<OptimizeParamBool>(part, name);
}
OptimizeParamPtr get() {
return m_param;
}
string str() const {
return m_param->str();
}
private:
OptimizeParamPtr m_param;
};
class PyOptimizeParamString {
public:
PyOptimizeParamString(SystemPart part, const string& name, const StringList& values) {
m_param = std::make_shared<OptimizeParamString>(part, name, values);
}
OptimizeParamPtr get() {
return m_param;
}
string str() const {
return m_param->str();
}
private:
OptimizeParamPtr m_param;
};
void export_optimize(py::module& m) {
py::class_<PyOptimizeParamInt>(m, "OptimizeParamInt")
.def(py::init<SystemPart, const string&, int, int, int>(), py::arg("part"), py::arg("name"),
py::arg("start"), py::arg("end"), py::arg("step") = 1)
.def("__str__", &PyOptimizeParamInt::str)
.def("__call__", &PyOptimizeParamInt::get);
py::class_<PyOptimizeParamDouble>(m, "OptimizeParamDouble")
.def(py::init<SystemPart, const string&, double, double, double>(), py::arg("part"),
py::arg("name"), py::arg("start"), py::arg("end"), py::arg("step"))
.def("__str__", &PyOptimizeParamDouble::str)
.def("__call__", &PyOptimizeParamDouble::get);
py::class_<PyOptimizeParamBool>(m, "OptimizeParamBool")
.def(py::init<SystemPart, const string&>(), py::arg("part"), py::arg("name"))
.def("__str__", &PyOptimizeParamBool::str)
.def("__call__", &PyOptimizeParamBool::get);
py::class_<PyOptimizeParamString>(m, "OptimizeParamString")
.def(py::init<SystemPart, const string&, const StringList&>(), py::arg("part"),
py::arg("name"), py::arg("values"))
.def("__str__", &PyOptimizeParamString::str)
.def("__call__", &PyOptimizeParamString::get);
m.def("find_optimize_param", [](const SYSPtr& sys, const Stock& stk, const KQuery& query,
const py::sequence& opt_params, const string& sort_key) {
OptimizeParamList c_opt_params;
auto total = len(opt_params);
for (auto i = 0; i < total; ++i) {
const auto& obj = opt_params[i];
if (py::isinstance<PyOptimizeParamInt>(obj)) {
c_opt_params.push_back(obj.cast<PyOptimizeParamInt>().get());
} else if (py::isinstance<PyOptimizeParamDouble>(obj)) {
c_opt_params.push_back(obj.cast<PyOptimizeParamDouble>().get());
} else if (py::isinstance<PyOptimizeParamBool>(obj)) {
c_opt_params.push_back(obj.cast<PyOptimizeParamBool>().get());
} else if (py::isinstance<PyOptimizeParamDouble>(obj)) {
c_opt_params.push_back(obj.cast<PyOptimizeParamString>().get());
} else {
HKU_THROW("Not OptimizeParam, index: {}", i);
}
}
return findOptimizeParam(sys, stk, query, c_opt_params, sort_key);
});
}

View File

@ -0,0 +1,18 @@
/*
* Copyright (c) 2019~2023, hikyuu.org
*
* History:
* 1. 20240907 added by fasiondog
*/
#include <pybind11/pybind11.h>
namespace py = pybind11;
void export_analysis(py::module& m);
void export_optimize(py::module& m);
void export_analysis_main(py::module& m) {
export_analysis(m);
export_optimize(m);
}

View File

@ -42,7 +42,7 @@ void export_SystemPart(py::module& m);
void export_trade_manage_main(py::module& m);
void export_trade_sys_main(py::module& m);
void export_global_main(py::module& m);
void export_analysis(py::module& m);
void export_analysis_main(py::module& m);
void export_StrategeContext(py::module& m);
void export_strategy_main(py::module& m);
@ -99,7 +99,7 @@ PYBIND11_MODULE(core, m) {
export_trade_manage_main(m);
export_trade_sys_main(m); // must after export_trade_manage_main
export_analysis(m);
export_analysis_main(m);
export_strategy_main(m);
export_global_main(m);