Commit 938ef10c authored by jichao's avatar jichao

回测报告增加基金池

parent 22435898
......@@ -89,11 +89,11 @@ class CvarEwmaAssetRisk(AssetRisk):
start_date = last_start['date'] if last_start else self.risk_start_date
rtns = pd.DataFrame(self.get_income_return(asset_id, min_date=start_date, max_date=day))
risk_rtns = rtns[rtns.date <= last['date']]
cvar_start_date = risk_rtns.loc[risk_rtns.rtn.idxmin()].date
cvar_start_date = risk_rtns.loc[risk_rtns.nav.idxmin()].date
for index, row in rtns[rtns.date >= cvar_start_date].iterrows():
tigger = False
cvar_rtns = rtns[(rtns.date >= cvar_start_date) & (rtns.date <= row['date'])]
if row['rtn'] < rtns[rtns.date == cvar_start_date].iloc[0].rtn:
if row.nav < rtns[rtns.date == cvar_start_date].iloc[0].nav:
# 当日回报率跌破最低点, 则直接触发
tigger = True
elif row['rtn'] <= self._config['cvar']['threshold'] and len(cvar_rtns) >= self._config['cvar']['min-volume']:
......@@ -136,7 +136,7 @@ class CvarEwmaAssetRisk(AssetRisk):
fund_navs.dropna(inplace=True)
if min_date:
fund_navs = fund_navs[fund_navs.nav_date >= pd.to_datetime(min_date)]
fund_navs.rename(columns={'nav_date': 'date'}, inplace=True)
fund_navs = fund_navs[['date', 'rtn']]
fund_navs.rename(columns={'nav_date': 'date', 'nav_cal': 'nav'}, inplace=True)
fund_navs = fund_navs[['date', 'nav', 'rtn']]
return fund_navs.to_dict('records')
return []
......@@ -3,7 +3,7 @@ import unittest
from py_jftech import autowired, parse_date, to_str
from api import AssetPool, RoboReportor
from api import AssetPool, RoboReportor, AssetRisk
logger = logging.getLogger(__name__)
......@@ -19,6 +19,10 @@ class AssetPoolTest(unittest.TestCase):
result = report.load_report(max_date=parse_date('2009-12-31'))
logger.info(to_str(result))
@autowired
def test_next_risk_date(self, risk: AssetRisk = None):
risk.build_risk_date(asset_id=46)
if __name__ == '__main__':
unittest.main()
......@@ -208,23 +208,24 @@ reports: # 报告模块相关
backtest: # 回测导出曹策略
exist-build: on # 如果报告文件存在,是否重新构建文件
save-path: ${EXPORT_PATH:excels} # 导出报告文件存放路径,如果以./或者../开头,则会以执行python文件为根目录,如果以/开头,则为系统绝对路径,否则,以项目目录为根目录
file-name: ${EXPORT_FILENAME:navs}
file-name: ${EXPORT_FILENAME:asset-pool}
include-report: # 需要导出的报告类型列表,下面的顺序,也代表了excel中sheet的顺序
# - navs-report # 净值报告
- hold-report # 持仓报告
- signal-report # 信号报告
# - hold-report # 持仓报告
# - signal-report # 信号报告
- asset-pool-report # 基金池报告
- benckmark-report # benckmark报告
- indicators-report # 各种特殊指标报告
- fixed-range-report # 固定区间收益报告
- relative-range-report # 相对区间收益报告
# - benckmark-report # benckmark报告
# - indicators-report # 各种特殊指标报告
# - fixed-range-report # 固定区间收益报告
# - relative-range-report # 相对区间收益报告
robo-executor: # 执行器相关
use: ${ROBO_EXECUTOR:backtest} #执行哪个执行器,优先取系统环境变量ROBO_EXECUTOR的值,默认backtest
sync-data: ${SYNC_DATA:on}
sync-data: ${SYNC_DATA:off}
backtest: # 回测执行器相关
start-date: 2008-01-02 # 回测起始日期
end-date: 2022-11-01 # 回测截止日期
start-step: 4 # 回测从哪一步开始执行 1:计算资产ewma;2:计算资产池;3:计算最优投组:4:计算再平衡信号以及持仓投组
start-step: 1 # 回测从哪一步开始执行 1:计算资产ewma;2:计算资产池;3:计算最优投组:4:计算再平衡信号以及持仓投组
end-step: 2 # 回测从哪一步执行完成后结束执行 1:计算资产ewma;2:计算资产池;3:计算最优投组:4:计算再平衡信号以及持仓投组
clean-up: on
real: # 实盘执行器
start-date: 2022-11-01 # 实盘开始时间
......
......@@ -30,6 +30,9 @@ class BacktestStep(Enum):
def within(self, step: Enum):
return self.value <= step.value
def without(self, step: Enum):
return self.value >= step.value
@component(bean_name='backtest')
class BacktestExecutor(RoboExecutor):
......@@ -55,6 +58,10 @@ class BacktestExecutor(RoboExecutor):
def start_step(self) -> BacktestStep:
return BacktestStep(self._config['start-step'])
@property
def end_step(self) -> BacktestStep:
return BacktestStep(self._config['end-step']) if 'end-step' in self._config else BacktestStep.HOLD_PORTFOLIO
@property
def is_sync_data(self):
return get_config(__name__)['sync-data']
......@@ -68,16 +75,16 @@ class BacktestExecutor(RoboExecutor):
return self._config['clean-up'] if 'clean-up' in self._config else True
def clear_datas(self):
if self.start_step.within(BacktestStep.EWMA_VALUE):
if self.start_step.within(BacktestStep.EWMA_VALUE) and self.end_step.without(BacktestStep.EWMA_VALUE):
logger.info('start to clear fund ewma value'.center(50, '-'))
self._risk.clear()
if self.start_step.within(BacktestStep.ASSET_POOL):
if self.start_step.within(BacktestStep.ASSET_POOL) and self.end_step.without(BacktestStep.ASSET_POOL):
logger.info('start to clear asset pool'.center(50, '-'))
self._pool.clear()
if self.start_step.within(BacktestStep.NORMAL_PORTFOLIO):
if self.start_step.within(BacktestStep.NORMAL_PORTFOLIO) and self.end_step.without(BacktestStep.NORMAL_PORTFOLIO):
logger.info('start to clear normal portfolios'.center(50, '-'))
self._builder.clear()
if self.start_step.within(BacktestStep.HOLD_PORTFOLIO):
if self.start_step.within(BacktestStep.HOLD_PORTFOLIO) and self.end_step.without(BacktestStep.HOLD_PORTFOLIO):
logger.info('start to clear hold portfolios'.center(50, '-'))
self._hold.clear()
self._rule.clear_signal()
......@@ -88,12 +95,12 @@ class BacktestExecutor(RoboExecutor):
sync.do_sync()
if self.is_clean_up:
self.clear_datas()
if self.start_step.within(BacktestStep.EWMA_VALUE):
if self.start_step.within(BacktestStep.EWMA_VALUE) and self.end_step.without(BacktestStep.EWMA_VALUE):
logger.info("start to build fund ewma value.".center(50, '-'))
now = dt.now()
wait([self.async_build_risk_date(x['id']) for x in self._datum.get_datums(type=DatumType.FUND, risk=(3, 4, 5))])
logger.info(f"build fund ewma value success, use[{(dt.now() - now).seconds}s]")
if self.start_step.within(BacktestStep.ASSET_POOL):
if self.start_step.within(BacktestStep.ASSET_POOL) and self.end_step.without(BacktestStep.ASSET_POOL):
logger.info("start to build asset pool".center(50, '-'))
now = dt.now()
workdays = workday_range(self.start_date, self.end_date)
......@@ -102,12 +109,12 @@ class BacktestExecutor(RoboExecutor):
for date in workdays:
self._pool.get_pool(date)
logger.info(f"build asset pool success, use[{(dt.now() - now).seconds}s]")
if self.start_step.within(BacktestStep.NORMAL_PORTFOLIO):
if self.start_step.within(BacktestStep.NORMAL_PORTFOLIO) and self.end_step.without(BacktestStep.NORMAL_PORTFOLIO):
logger.info("start to build normal portfolios".center(50, '-'))
now = dt.now()
wait([self.async_build_portfolios(day, risk) for risk in PortfoliosRisk for day in workday_range(self.start_date, self.end_date)])
logger.info(f"build normal portfolios success, use[{(dt.now() - now).seconds}s]")
if self.start_step.within(BacktestStep.HOLD_PORTFOLIO):
if self.start_step.within(BacktestStep.HOLD_PORTFOLIO) and self.end_step.without(BacktestStep.HOLD_PORTFOLIO):
logger.info("start to build hold portfolios".center(50, '-'))
now = dt.now()
wait([self.async_build_hold(x) for x in PortfoliosRisk])
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment