Skip to content

Commit

Permalink
Merge branch 'develop' into RQSDK-737
Browse files Browse the repository at this point in the history
  • Loading branch information
Lin-Dongzhao committed Apr 10, 2024
2 parents 2ad8af0 + ece76cd commit 51eef63
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 11 deletions.
8 changes: 5 additions & 3 deletions rqalpha/mod/rqalpha_mod_sys_analyser/report/excel_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,10 @@ def fill_worksheet(self, ws: Worksheet, data: Dict[str, List]):
if not data:
for key, (row, column, style) in self._cell_map.items():
self._write_cell(ws, row, column, None, style)
for key, (row, column, style) in self._cell_map.items():
for i, item in enumerate(data.get(key, [])):
self._write_cell(ws, row + i, column, item, style)
else:
for key, (row, column, style) in self._cell_map.items():
for i, item in enumerate(data.get(key, [])):
self._write_cell(ws, row + i, column, item, style)


class SummaryTemplate(ExcelTemplate):
Expand All @@ -83,6 +84,7 @@ class SummaryTemplate(ExcelTemplate):
"月度收益": VerticalSeriesSchema,
"月度超额收益(几何)": VerticalSeriesSchema,
"个股权重": VerticalSeriesSchema,
"压力测试": VerticalSeriesSchema,
}


Expand Down
59 changes: 51 additions & 8 deletions rqalpha/mod/rqalpha_mod_sys_analyser/report/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,37 @@

import os
from typing import Dict, Optional
import datetime

import numpy
import pandas
from collections import ChainMap
from collections import ChainMap, defaultdict
from pandas import Series, DataFrame

from rqrisk import Risk
from rqrisk import WEEKLY, MONTHLY
from rqalpha.environment import Environment

from rqalpha.mod.rqalpha_mod_sys_analyser.plot.utils import max_dd as _max_dd
from rqalpha.mod.rqalpha_mod_sys_analyser.report.excel_template import generate_xlsx_reports


PRESSURE_TEST_PERIOD = {
"打击壳价值": (datetime.date(2016, 11, 1), datetime.date(2018, 2, 1)),
"公募基金抱团": (datetime.date(2020, 10, 9), datetime.date(2021, 3, 1)),
"行业风格切换": (datetime.date(2021, 9, 1), datetime.date(2021, 12, 31)),
"小盘踩踏危机": (datetime.date(2024, 1, 5), datetime.date(2024, 2, 8)),
}


def _returns(unit_net_value: Series):
return (unit_net_value / unit_net_value.shift(1).fillna(1)).fillna(0) - 1


def _yearly_indicators(
p_nav: Series, p_returns: Series, b_nav: Optional[Series], b_returns: Optional[Series], risk_free_rates: Dict
):
data = {field: [] for field in [
"year", "returns", "benchmark_returns", "geometric_excess_return", "geometric_excess_drawdown",
"geometric_excess_drawdown_days", "excess_annual_volatility", "annual_volatility", "sharpe_ratio",
"excess_sharpe",
"information_ratio", "annual_tracking_error", "weekly_excess_win_rate", "monthly_excess_win_rate",
"max_drawdown", "max_drawdown_days"
]}
data = defaultdict(list)

for year, p_year_returns in p_returns.groupby(p_returns.index.year): # noqa
year_slice = p_returns.index.year == year # noqa
Expand Down Expand Up @@ -114,6 +118,44 @@ def _gen_positions_weight(df):
return df.reset_index().rename(columns=rename).to_dict(orient="list")


def _pressure_test(
p_nav: Series, p_returns: Series, b_nav: Optional[Series], b_returns: Optional[Series]
):
env = Environment.get_instance()
# data = {field: [] for field in [
# "title", "start_date", "end_date", "returns", "annual_return", "geometric_excess_return", "max_drawdown",
# "geometric_excess_drawdown", "sharpe", "excess_sharpe"
# ]}
data = defaultdict(list)

for title, (start, end) in PRESSURE_TEST_PERIOD.items():
p_period_returns = p_returns.loc[start: end]
if (p_period_returns is None or p_period_returns.empty):
continue
# 当且仅当回测周期完整包含压力测试的一个区间时才展示该区间的表现
if len(p_period_returns) != len(env.data_proxy.get_trading_dates(start, end)):
continue
if b_nav is not None:
b_period_returns = b_returns.loc[start: end]
else:
b_period_returns = Series(index=p_period_returns.index)
risk_free_rate = env.data_proxy.get_risk_free_rate(start, end)
risk = Risk(p_period_returns, b_period_returns, risk_free_rate)
data["title"].append(title)
data["start_date"].append(str(start))
data["end_date"].append(str(end))
data["returns"].append(risk.return_rate)
data["annual_return"].append(risk.annual_return)
data["geometric_excess_return"].append(risk.geometric_excess_return)
data["max_drawdown"].append(risk.max_drawdown)
data["geometric_excess_drawdown"].append(risk.geometric_excess_drawdown)
data["sharpe"].append(risk.sharpe)
data["excess_sharpe"].append(risk.excess_sharpe)
if not data["title"]:
return None
return data


def generate_report(result_dict, output_path):
from six import StringIO

Expand All @@ -138,6 +180,7 @@ def generate_report(result_dict, output_path):
"月度收益": _monthly_returns(p_returns),
"月度超额收益(几何)": _monthly_geometric_excess_returns(p_returns, b_returns),
"个股权重": _gen_positions_weight(result_dict["positions_weight"]),
"压力测试": _pressure_test(p_nav, p_returns, b_nav, b_returns),
}, output_path)

for name in ["portfolio", "stock_account", "future_account",
Expand Down
Binary file not shown.

0 comments on commit 51eef63

Please sign in to comment.