Commit 3cbf0a21 authored by wenwen.tang's avatar wenwen.tang 😕

需任意挑选起始日期,设定封闭期参数;

调整配息方法;每个季度后的第一天(正好是调仓日)判断是否更新配息金额(预留)。是,则"标准配息(9%)/前一天的单位净值(rhp_asset_nav)";否,则"延续使用前次的配息金额"
parent 39077d30
...@@ -76,7 +76,9 @@ portfolios: # 投组模块 ...@@ -76,7 +76,9 @@ portfolios: # 投组模块
init-nav: 100 # 初始金额 init-nav: 100 # 初始金额
min-interval-days: 10 # 两次实际调仓最小间隔期,单位交易日 min-interval-days: 10 # 两次实际调仓最小间隔期,单位交易日
dividend-rate: 0.09 #设定年化配息率 dividend-rate: 0.09 #设定年化配息率
dividend-date: 10 #配息日,每月10号 dividend-drift-rate: 0.1 #超过基准配息率上下10%触发配息率重置
dividend-date: 15 #配息日,每月10号
dividend-adjust-day: [1,4,7,10] #每年的首个季度调整配息
solver: # 解算器相关 solver: # 解算器相关
tol: 1E-10 # 误差满足条件 tol: 1E-10 # 误差满足条件
navs: # 净值要求 navs: # 净值要求
...@@ -168,7 +170,8 @@ robo-executor: # 执行器相关 ...@@ -168,7 +170,8 @@ robo-executor: # 执行器相关
backtest: # 回测执行器相关 backtest: # 回测执行器相关
start-date: 2012-10-16 # 回测起始日期 start-date: 2012-10-16 # 回测起始日期
end-date: 2023-03-03 # 回测截止日期 end-date: 2023-03-03 # 回测截止日期
start-step: ${BACKTEST_START_STEP:3} # 回测从哪一步开始执行 1:计算资产池;2:计算最优投组:3:计算再平衡信号以及持仓投组 sealing-period: 10 #调仓封闭期
start-step: ${BACKTEST_START_STEP:1} # 回测从哪一步开始执行 1:计算资产池;2:计算最优投组:3:计算再平衡信号以及持仓投组
end-step: ${BACKTEST_END_STEP:3} # 回测从哪一步执行完成后结束执行 1:计算资产池;2:计算最优投组:3:计算再平衡信号以及持仓投组 end-step: ${BACKTEST_END_STEP:3} # 回测从哪一步执行完成后结束执行 1:计算资产池;2:计算最优投组:3:计算再平衡信号以及持仓投组
clean-up: true clean-up: true
real: # 实盘执行器 real: # 实盘执行器
......
...@@ -23,6 +23,7 @@ class DividendPortfoliosHolder(PortfoliosHolder): ...@@ -23,6 +23,7 @@ class DividendPortfoliosHolder(PortfoliosHolder):
self._executor = executor self._executor = executor
self._builder = builder self._builder = builder
self._config = get_config(__name__) self._config = get_config(__name__)
self._last_div = None
def get_portfolio_type(self, day, risk: PortfoliosRisk) -> PortfoliosType: def get_portfolio_type(self, day, risk: PortfoliosRisk) -> PortfoliosType:
return PortfoliosType.NORMAL return PortfoliosType.NORMAL
...@@ -69,15 +70,34 @@ class DividendPortfoliosHolder(PortfoliosHolder): ...@@ -69,15 +70,34 @@ class DividendPortfoliosHolder(PortfoliosHolder):
navs = fund_div_tuple[0] navs = fund_div_tuple[0]
dividend_acc = last_nav['div_acc'] dividend_acc = last_nav['div_acc']
nav = round(sum([navs[x] * y for x, y in share.items()]), 4) + last_nav['fund_div'] nav = round(sum([navs[x] * y for x, y in share.items()]), 4) + last_nav['fund_div']
# 每年的首个季度调整配息
if day.month in self._config.get('dividend-adjust-day'):
asset_nav = last_nav['asset_nav']
div_rate = self._last_div * 12 / asset_nav
# 超过基准配息率上下10%触发配息率重置
if abs((self._config['dividend-rate'] - div_rate) / self._config['dividend-rate']) > \
self._config['dividend-drift-rate']:
# 以本月前一天的单位净值进行配息计算
dividend = last_nav['asset_nav'] * self.month_dividend
else:
dividend = self._last_div
nav = nav - dividend
dividend_acc = dividend + dividend_acc
self._last_div = dividend
else:
dividend = last_nav['dividend'] + self._last_div
nav = nav - self._last_div
dividend_acc = self._last_div + dividend_acc
else: else:
nav = self.init_nav nav = self.init_nav
fund_div_tuple = self.get_navs_and_div(fund_ids=tuple(weight), day=day) fund_div_tuple = self.get_navs_and_div(fund_ids=tuple(weight), day=day)
navs = fund_div_tuple[0] navs = fund_div_tuple[0]
dividend = nav * self.month_dividend dividend = nav * self.month_dividend
nav = nav - dividend self._last_div = dividend
nav = nav - dividend
dividend_acc = dividend + dividend_acc
share = {x: nav * w / navs[x] for x, w in weight.items()} share = {x: nav * w / navs[x] for x, w in weight.items()}
fund_dividend = 0 fund_dividend = 0
dividend_acc = dividend + dividend_acc
asset_nav = nav + fund_dividend + dividend asset_nav = nav + fund_dividend + dividend
rhp.insert({ rhp.insert({
'date': day, 'date': day,
......
import logging import logging
import os
import sys import sys
from concurrent.futures import wait from concurrent.futures import wait
from datetime import datetime as dt from datetime import datetime as dt
...@@ -9,7 +8,7 @@ from typing import List ...@@ -9,7 +8,7 @@ from typing import List
import pandas as pd import pandas as pd
from py_jftech import ( from py_jftech import (
component, autowired, get_config, filter_weekend, asynchronized, component, autowired, get_config, filter_weekend, asynchronized,
parse_date parse_date, workday_range
) )
from api import ( from api import (
...@@ -58,7 +57,14 @@ class BacktestExecutor(RoboExecutor): ...@@ -58,7 +57,14 @@ class BacktestExecutor(RoboExecutor):
lambda x: pd.date_range(start=x, end=x + pd.offsets.MonthEnd(0), freq='B')[0] lambda x: pd.date_range(start=x, end=x + pd.offsets.MonthEnd(0), freq='B')[0]
) )
# 返回第一个工作日列表 # 返回第一个工作日列表
return list(df['first_business_day']) result = list(df['first_business_day'])
delta = workday_range(start_date, result[0])
period = get_config(__name__)['backtest']['sealing-period']
if len(delta) <= period:
result.pop(0)
result.insert(0, start_date)
return result
@property @property
def start_date(self): def start_date(self):
......
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