Skip to content

Commit

Permalink
Merge pull request #218 from fasiondog/feature/factor
Browse files Browse the repository at this point in the history
优化 TradeManager 获取资金曲线相关方法及其他 python 引入调整
  • Loading branch information
fasiondog committed Apr 2, 2024
2 parents 26da56f + 5064e7e commit c01ce5a
Show file tree
Hide file tree
Showing 25 changed files with 889 additions and 436 deletions.
8 changes: 8 additions & 0 deletions docs/source/trade_manage/TradeManager.rst
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,15 @@
:param Datetime datetime: 指定时刻
:param Query.KType ktype: K线类型
:rtype: FundsRecord

.. py:method:: get_funds_list(self, datetime, [ktype = Query.DAY])
获取指定日期列表每日资产记录

:param Datetime datetime: 指定时刻
:param Query.KType ktype: K线类型
:rtype: FundsList

.. py:method:: get_funds_curve(self, dates[, ktype = Query.DAY])
获取资产净值曲线
Expand Down
11 changes: 10 additions & 1 deletion docs/source/trade_manage/record_struct.rst
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,13 @@
.. py:attribute:: base_cash 当前投入本金(float
.. py:attribute:: base_asset 当前投入的资产价值(float
.. py:attribute:: borrow_cash 当前借入的资金(float),即负债
.. py:attribute:: borrow_asset 当前借入证券资产价值(float
.. py:attribute:: borrow_asset 当前借入证券资产价值(float
只读属性,自动根据上面的属性计算得到的结果:

.. py:attribute:: total_assets 总资产
.. py:attribute:: net_assets 净资产
.. py:attribute:: total_borrow 总负债
.. py:attribute:: total_base 投入本值资产(本钱)
.. py:attribute:: profit 收益
2 changes: 1 addition & 1 deletion docs/source/trade_sys/signal.rst
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@
克隆操作

.. py:method:: _calculate(self)
.. py:method:: _calculate(self, kdata)
【重载接口】子类计算接口

Expand Down
10 changes: 4 additions & 6 deletions hikyuu/draw/drawplot/matplotlib_draw.py
Original file line number Diff line number Diff line change
Expand Up @@ -752,14 +752,12 @@ def sys_performance(sys, ref_stk=None):
ref_dates = ref_k.get_datetime_list()
profit = sys.tm.get_profit_curve(ref_dates)
profit = VALUE(profit)
funds = sys.tm.get_funds_curve(ref_dates)
funds_list = sys.tm.get_funds_list(ref_dates)
funds = [f.total_assets for f in funds_list]
funds = VALUE(funds)
funds_return = profit / REF(funds, 1) + 1
# funds_return = cum_return(funds)
funds_return = [f.total_assets / f.total_base for f in funds_list]
funds_return = VALUE(funds_return)
funds_return.name = "系统累积收益率"
# cum_return = get_part("default.ind.累积收益率")
ref_return = ROCR(ref_k.close, 0)
ref_return.name = ref_stk.name
Expand Down
122 changes: 65 additions & 57 deletions hikyuu/examples/notebook/001-overview.ipynb

Large diffs are not rendered by default.

163 changes: 130 additions & 33 deletions hikyuu/examples/notebook/007-SystemDetails.ipynb

Large diffs are not rendered by default.

235 changes: 204 additions & 31 deletions hikyuu/examples/notebook/010-Portfolio.ipynb

Large diffs are not rendered by default.

225 changes: 114 additions & 111 deletions hikyuu/examples/notebook/Demo/Demo1.ipynb

Large diffs are not rendered by default.

271 changes: 203 additions & 68 deletions hikyuu/examples/notebook/Demo/Demo2.ipynb

Large diffs are not rendered by default.

24 changes: 0 additions & 24 deletions hikyuu_cpp/hikyuu/strategy/AccountTradeManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -387,30 +387,6 @@ class HKU_API AccountTradeManager : public TradeManagerBase {
return FundsRecord();
}

/**
* 获取资产净值曲线,含借入的资产
* @param dates 日期列表,根据该日期列表获取其对应的资产净值曲线
* @param ktype K线类型,必须与日期列表匹配,默认KQuery::DAY
* @return 资产净值列表
*/
virtual PriceList getFundsCurve(const DatetimeList& dates,
KQuery::KType ktype = KQuery::DAY) override {
HKU_WARN("The subclass does not implement this method");
return PriceList();
}

/**
* 获取收益曲线,即扣除历次存入资金后的资产净值曲线
* @param dates 日期列表,根据该日期列表获取其对应的收益曲线,应为递增顺序
* @param ktype K线类型,必须与日期列表匹配,默认为KQuery::DAY
* @return 收益曲线
*/
virtual PriceList getProfitCurve(const DatetimeList& dates,
KQuery::KType ktype = KQuery::DAY) override {
HKU_WARN("The subclass does not implement this method");
return PriceList();
}

/**
* 直接加入交易记录
* @note 如果加入初始化账户记录,将清除全部已有交易及持仓记录
Expand Down
3 changes: 3 additions & 0 deletions hikyuu_cpp/hikyuu/trade_manage/FundsRecord.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ class HKU_API FundsRecord {
#endif
};

typedef vector<FundsRecord> FundsList;
typedef vector<FundsRecord> FundsRecordList;

/**
* 输出TradeRecord信息
* @ingroup TradeManagerClass
Expand Down
34 changes: 0 additions & 34 deletions hikyuu_cpp/hikyuu/trade_manage/TradeManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1471,40 +1471,6 @@ FundsRecord TradeManager::getFunds(const Datetime& indatetime, KQuery::KType kty
return funds;
}

PriceList TradeManager::getFundsCurve(const DatetimeList& dates, KQuery::KType ktype) {
size_t total = dates.size();
PriceList result(total);
int precision = getParam<int>("precision");
for (size_t i = 0; i < total; ++i) {
FundsRecord funds = getFunds(dates[i], ktype);
result[i] = roundEx(
funds.cash + funds.market_value - funds.borrow_cash - funds.borrow_asset, precision);
}
return result;
}

PriceList TradeManager::getProfitCurve(const DatetimeList& dates, KQuery::KType ktype) {
size_t total = dates.size();
PriceList result(total);
if (total == 0)
return result;

size_t i = 0;
while (i < total && dates[i] < m_init_datetime) {
result[i] = 0;
i++;
}
int precision = getParam<int>("precision");
for (; i < total; ++i) {
FundsRecord funds = getFunds(dates[i], ktype);
result[i] = roundEx(funds.cash + funds.market_value - funds.borrow_cash -
funds.borrow_asset - funds.base_cash - funds.base_asset,
precision);
}

return result;
}

/******************************************************************************
* 每次执行交易操作时,先根据权息信息调整持有仓位及现金记录
* 采用滞后更新的策略,即只在需要获取当前持仓情况及卖出时更新当前的持仓及资产情况
Expand Down
18 changes: 0 additions & 18 deletions hikyuu_cpp/hikyuu/trade_manage/TradeManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,24 +336,6 @@ class HKU_API TradeManager : public TradeManagerBase {
virtual FundsRecord getFunds(const Datetime& datetime,
KQuery::KType ktype = KQuery::DAY) override;

/**
* 获取资产净值曲线,含借入的资产
* @param dates 日期列表,根据该日期列表获取其对应的资产净值曲线
* @param ktype K线类型,必须与日期列表匹配,默认KQuery::DAY
* @return 资产净值列表
*/
virtual PriceList getFundsCurve(const DatetimeList& dates,
KQuery::KType ktype = KQuery::DAY) override;

/**
* 获取收益曲线,即扣除历次存入资金后的资产净值曲线
* @param dates 日期列表,根据该日期列表获取其对应的收益曲线,应为递增顺序
* @param ktype K线类型,必须与日期列表匹配,默认为KQuery::DAY
* @return 收益曲线
*/
virtual PriceList getProfitCurve(const DatetimeList& dates,
KQuery::KType ktype = KQuery::DAY) override;

/**
* 直接加入交易记录
* @note 如果加入初始化账户记录,将清除全部已有交易及持仓记录
Expand Down
101 changes: 79 additions & 22 deletions hikyuu_cpp/hikyuu/trade_manage/TradeManagerBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,85 @@ class HKU_API TradeManagerBase {
m_broker_list.clear();
}

/**
* 获取指定日期列表中的所有日资产记录
* @param dates 日期列表
* @param ktype K线类型,必须与日期列表匹配,默认KQuery::DAY
* @return 日资产记录列表
*/
FundsList getFundsList(const DatetimeList& dates, KQuery::KType ktype = KQuery::DAY) {
size_t total = dates.size();
FundsList result(total);
HKU_IF_RETURN(total == 0, result);
for (size_t i = 0; i < total; ++i) {
result[i] = getFunds(dates[i], ktype);
}
return result;
}

/**
* 获取资产净值曲线,含借入的资产
* @param dates 日期列表,根据该日期列表获取其对应的资产净值曲线
* @param ktype K线类型,必须与日期列表匹配,默认KQuery::DAY
* @return 资产净值列表
*/
PriceList getFundsCurve(const DatetimeList& dates, KQuery::KType ktype = KQuery::DAY) {
FundsList funds_list = getFundsList(dates, ktype);
PriceList ret(funds_list.size());
int precision = getParam<int>("precision");
for (size_t i = 0, total = funds_list.size(); i < total; i++) {
ret[i] = roundEx(funds_list[i].total_assets(), precision);
}
return ret;
}

/**
* 获取收益曲线,即扣除历次存入资金后的资产净值曲线
* @param dates 日期列表,根据该日期列表获取其对应的收益曲线,应为递增顺序
* @param ktype K线类型,必须与日期列表匹配,默认为KQuery::DAY
* @return 收益曲线
*/
PriceList getProfitCurve(const DatetimeList& dates, KQuery::KType ktype = KQuery::DAY) {
FundsList funds_list = getFundsList(dates, ktype);
PriceList ret(funds_list.size());
int precision = getParam<int>("precision");
for (size_t i = 0, total = funds_list.size(); i < total; i++) {
ret[i] = roundEx(funds_list[i].profit(), precision);
}
return ret;
}

/**
* 获取累积收益率曲线
* @param dates 日期列表
* @param ktype K线类型,必须与日期列表匹配,默认为KQuery::DAY
* @return 收益率曲线
*/
PriceList getProfitCumChangeCurve(const DatetimeList& dates,
KQuery::KType ktype = KQuery::DAY) {
FundsList funds_list = getFundsList(dates, ktype);
PriceList ret(funds_list.size());
for (size_t i = 0, total = funds_list.size(); i < total; i++) {
ret[i] = funds_list[i].total_assets() / funds_list[i].total_base();
}
return ret;
}

/**
* 获取投入本值资产曲线
* @param dates 日期列表,根据该日期列表获取其对应的收益曲线,应为递增顺序
* @param ktype K线类型,必须与日期列表匹配,默认为KQuery::DAY
* @return 价格曲线
*/
PriceList getBaseAssetsCurve(const DatetimeList& dates, KQuery::KType ktype = KQuery::DAY) {
FundsList funds_list = getFundsList(dates, ktype);
PriceList ret(funds_list.size());
for (size_t i = 0, total = funds_list.size(); i < total; i++) {
ret[i] = funds_list[i].total_base();
}
return ret;
}

/**
* 根据权息信息更新当前持仓与交易情况
* @note 必须按时间顺序调用
Expand Down Expand Up @@ -578,28 +657,6 @@ class HKU_API TradeManagerBase {
return FundsRecord();
}

/**
* 获取资产净值曲线,含借入的资产
* @param dates 日期列表,根据该日期列表获取其对应的资产净值曲线
* @param ktype K线类型,必须与日期列表匹配,默认KQuery::DAY
* @return 资产净值列表
*/
virtual PriceList getFundsCurve(const DatetimeList& dates, KQuery::KType ktype = KQuery::DAY) {
HKU_WARN("The subclass does not implement this method");
return PriceList();
}

/**
* 获取收益曲线,即扣除历次存入资金后的资产净值曲线
* @param dates 日期列表,根据该日期列表获取其对应的收益曲线,应为递增顺序
* @param ktype K线类型,必须与日期列表匹配,默认为KQuery::DAY
* @return 收益曲线
*/
virtual PriceList getProfitCurve(const DatetimeList& dates, KQuery::KType ktype = KQuery::DAY) {
HKU_WARN("The subclass does not implement this method");
return PriceList();
}

/**
* 直接加入交易记录
* @note 如果加入初始化账户记录,将清除全部已有交易及持仓记录
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ void AllocateFundsBase::initParam() {
// 仅针对剩余现金比例调整没有意义,即使分配由于交易成本原因可能也无法完成实际交易
// adjust_running_sys: True - 主动根据资产分配对已持仓策略进行增减仓
// adjust_running_sys: False - 不会根据当前分配权重对已持仓策略进行强制加减仓
setParam<bool>("adjust_running_sys", false);
setParam<bool>("adjust_running_sys", true);

// 自动调整权重,此时认为传入的权重为各证券的相互比例(详见ignore_zero_weight说明)
// 否则,以传入的权重为指定权重不做调整(此时传入的各个权重需要小于1)
Expand Down
2 changes: 1 addition & 1 deletion hikyuu_cpp/hikyuu/trade_sys/portfolio/Portfolio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ void Portfolio::_runMoment(const Datetime& date, const Datetime& nextCycle, bool
count++;
int trace_max_num = getParam<int>("trace_max_num");
if (count >= trace_max_num) {
if (count > trace_max_num) {
if (m_running_sys_set.size() > trace_max_num) {
HKU_INFO("+ ... ... more +");
HKU_INFO("+------------+------------+------------+--------------+--------------+-------------+-------------+");
}
Expand Down
3 changes: 2 additions & 1 deletion hikyuu_cpp/hikyuu/trade_sys/signal/SignalBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ void SignalBase::reset() {
void SignalBase::startCycle(const Datetime& start, const Datetime& close) {
HKU_IF_RETURN(!getParam<bool>("cycle"), void());
HKU_ASSERT(start != Null<Datetime>() && close != Null<Datetime>() && start < close);
HKU_CHECK(start >= m_cycle_end, "curretn start: {}, pre cycle end: {}", start, m_cycle_end);
HKU_CHECK(start >= m_cycle_end || m_cycle_end == Null<Datetime>(),
"curretn start: {}, pre cycle end: {}", start, m_cycle_end);
m_cycle_start = start;
m_cycle_end = close;
KData kdata = m_kdata.getKData(start, close);
Expand Down
16 changes: 10 additions & 6 deletions hikyuu_pywrap/bind_stl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,25 @@
using namespace hku;
namespace py = pybind11;

// pybind 默认会将 vector 和 list 互转,数据量过大的情况下会影响性能
// 只考虑引出影响可能性能的类型

void export_bind_stl(py::module& m) {
// py::bind_vector<PriceList>(m, "PriceList");
// py::bind_vector<StringList>(m, "StringList");
py::bind_vector<DatetimeList>(m, "DatetimeList");
py::bind_vector<KRecordList>(m, "KRecordList");
py::bind_vector<StockList>(m, "StockList");
// py::bind_vector<StockList>(m, "StockList");
py::bind_vector<StockWeightList>(m, "StockWeightList");
// py::bind_vector<IndicatorList>(m, "Indicatorist");
py::bind_vector<TimeLineList>(m, "TimeLineList");
py::bind_vector<TransList>(m, "TransList");
py::bind_vector<BorrowRecordList>(m, "BorrowRecordList");
py::bind_vector<LoanRecordList>(m, "LoanRecordList");
py::bind_vector<PositionRecordList>(m, "PositionRecordList");
py::bind_vector<TradeRecordList>(m, "TradeRecordList");
// py::bind_vector<BorrowRecordList>(m, "BorrowRecordList");
// py::bind_vector<LoanRecordList>(m, "LoanRecordList");
// py::bind_vector<PositionRecordList>(m, "PositionRecordList");
// py::bind_vector<FundsList>(m, "FundsList");
// py::bind_vector<TradeRecordList>(m, "TradeRecordList");
py::bind_vector<SystemWeightList>(m, "SystemWeightList");
py::bind_vector<SystemList>(m, "SystemList");
// py::bind_vector<SystemList>(m, "SystemList");
py::bind_vector<ScoreRecordList>(m, "ScoreRecordList");
}
14 changes: 8 additions & 6 deletions hikyuu_pywrap/bind_stl.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#pragma once

#include <pybind11/pybind11.h>
#include <pybind11/stl_bind.h>
#include <hikyuu/hikyuu.h>

using namespace hku;
Expand All @@ -20,15 +21,16 @@ using namespace hku;
// PYBIND11_MAKE_OPAQUE(PriceList);
PYBIND11_MAKE_OPAQUE(DatetimeList);
PYBIND11_MAKE_OPAQUE(KRecordList);
PYBIND11_MAKE_OPAQUE(StockList);
// PYBIND11_MAKE_OPAQUE(StockList); // StockList 数据量不大,让 pybind 自动从 list 互转比较方便
PYBIND11_MAKE_OPAQUE(StockWeightList);
// PYBIND11_MAKE_OPAQUE(IndicatorList); // 无法编译
PYBIND11_MAKE_OPAQUE(TimeLineList);
PYBIND11_MAKE_OPAQUE(TransList);
PYBIND11_MAKE_OPAQUE(BorrowRecordList);
PYBIND11_MAKE_OPAQUE(LoanRecordList);
PYBIND11_MAKE_OPAQUE(PositionRecordList);
PYBIND11_MAKE_OPAQUE(TradeRecordList);
// PYBIND11_MAKE_OPAQUE(BorrowRecordList);
// PYBIND11_MAKE_OPAQUE(LoanRecordList);
// PYBIND11_MAKE_OPAQUE(PositionRecordList);
// PYBIND11_MAKE_OPAQUE(FundsList);
// PYBIND11_MAKE_OPAQUE(TradeRecordList);
PYBIND11_MAKE_OPAQUE(SystemWeightList);
PYBIND11_MAKE_OPAQUE(SystemList);
// PYBIND11_MAKE_OPAQUE(SystemList);
PYBIND11_MAKE_OPAQUE(ScoreRecordList);
2 changes: 1 addition & 1 deletion hikyuu_pywrap/pybind_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#define HIKYUU_PYTHON_BIND_UTILS_H

#include <pybind11/pybind11.h>
#include <pybind11/stl_bind.h>

#include <pybind11/operators.h>
#include <pybind11/stl.h>
#include <pybind11/numpy.h>
Expand Down
6 changes: 6 additions & 0 deletions hikyuu_pywrap/trade_manage/_FundsRecord.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ void export_FundsRecord(py::module& m) {
.def_readwrite("borrow_cash", &FundsRecord::borrow_cash, "当前借入的资金(float),即负债")
.def_readwrite("borrow_asset", &FundsRecord::borrow_asset, "当前借入证券资产价值(float)")

.def_property_readonly("total_assets", &FundsRecord::total_assets, "总资产")
.def_property_readonly("net_assets", &FundsRecord::net_assets, "净资产")
.def_property_readonly("total_borrow", &FundsRecord::total_borrow, "总负债")
.def_property_readonly("total_base", &FundsRecord::total_base, "投入本值资产")
.def_property_readonly("profit", &FundsRecord::profit, "当前收益")

.def(py::self + py::self)
.def(py::self += py::self)

Expand Down

0 comments on commit c01ce5a

Please sign in to comment.