Commit 1213b877 authored by wenwen.tang's avatar wenwen.tang 😕

回测平台调整:持有基金自身配息不再下次调仓后拿来再投资

parent 0f0faaa9
...@@ -645,3 +645,12 @@ class RebalanceSignal(ABC): ...@@ -645,3 +645,12 @@ class RebalanceSignal(ABC):
:param risk: 指定的风险等级 :param risk: 指定的风险等级
:return: 如果有信号,则返回信号数据,否则返回None :return: 如果有信号,则返回信号数据,否则返回None
''' '''
@abstractmethod
def clear(self, min_date=None, risk: PortfoliosRisk = None):
'''
清理指定的数据
:param min_date: 指定的起始时间
:param risk: 指定的风险等级
'''
pass
\ No newline at end of file
...@@ -231,15 +231,15 @@ reports: # 报告模块相关 ...@@ -231,15 +231,15 @@ reports: # 报告模块相关
subject: "SVROBO6-实盘版-每日监测_{today}" subject: "SVROBO6-实盘版-每日监测_{today}"
content: "Dear All: 附件是今天生成的监测数据,請驗收,謝謝! 注>:該郵件為自動發送,如有問題請聯繫矽谷團隊 telan_qian@chifufund.com" content: "Dear All: 附件是今天生成的监测数据,請驗收,謝謝! 注>:該郵件為自動發送,如有問題請聯繫矽谷團隊 telan_qian@chifufund.com"
robo-executor: # 执行器相关 robo-executor: # 执行器相关
use: ${ROBO_EXECUTOR:real} # 执行哪个执行器,优先取系统环境变量ROBO_EXECUTOR的值,默认backtest use: ${ROBO_EXECUTOR:backtest} # 执行哪个执行器,优先取系统环境变量ROBO_EXECUTOR的值,默认backtest
sync-data: ${SYNC_DATA:on} # 是否开启同步资料数据 sync-data: ${SYNC_DATA:off} # 是否开启同步资料数据
backtest: # 回测执行器相关 backtest: # 回测执行器相关
start-date: 2022-09-30 # 回测起始日期 start-date: 2022-09-22 # 回测起始日期
end-date: 2023-07-03 # 回测截止日期 end-date: 2023-07-03 # 回测截止日期
sealing-period: 10 #调仓封闭期 sealing-period: 10 #调仓封闭期
start-step: ${BACKTEST_START_STEP:3} # 回测从哪一步开始执行 1:计算资产池;2:计算最优投组:3:计算再平衡信号以及持仓投组 start-step: ${BACKTEST_START_STEP:3} # 回测从哪一步开始执行 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: off
real: # 实盘执行器 real: # 实盘执行器
export: ${EXPORT_ENABLE:off} # 是否开启报告 export: ${EXPORT_ENABLE:off} # 是否开启报告
start-date: 2023-05-08 # 实盘开始时间 start-date: 2023-05-08 # 实盘开始时间
......
...@@ -237,11 +237,11 @@ class InvTrustPortfoliosHolder(DividendPortfoliosHolder): ...@@ -237,11 +237,11 @@ class InvTrustPortfoliosHolder(DividendPortfoliosHolder):
fund_div_tuple = self.get_navs_and_div(fund_ids=tuple(set(weight) | set(share)), day=day) fund_div_tuple = self.get_navs_and_div(fund_ids=tuple(set(weight) | set(share)), day=day)
navs = fund_div_tuple[0] navs = fund_div_tuple[0]
fund_dividend = fund_div_tuple[1] fund_dividend = fund_div_tuple[1]
fund_dividend = sum( fund_dividend = last_nav['fund_div'] + sum(
map(lambda k: share[k] * fund_dividend[k], filter(lambda k: k in fund_dividend, share.keys()))) map(lambda k: share[k] * fund_dividend[k], filter(lambda k: k in fund_dividend, share.keys())))
dividend_acc = last_nav['div_acc'] dividend_acc = last_nav['div_acc']
fund_av = round(sum([navs[x] * y for x, y in share.items()]), 4) + last_nav['fund_div'] fund_av = round(sum([navs[x] * y for x, y in share.items()]), 4) + last_nav['fund_div']
asset_nav = fund_av + fund_dividend asset_nav = fund_av
nav = last_nav['nav'] * asset_nav / last_nav['asset_nav'] nav = last_nav['nav'] * asset_nav / last_nav['asset_nav']
share = {x: fund_av * w / navs[x] for x, w in weight.items()} share = {x: fund_av * w / navs[x] for x, w in weight.items()}
if self.is_first_workday(day): if self.is_first_workday(day):
...@@ -313,7 +313,7 @@ class InvTrustPortfoliosHolder(DividendPortfoliosHolder): ...@@ -313,7 +313,7 @@ class InvTrustPortfoliosHolder(DividendPortfoliosHolder):
weight = format_weight(weight) weight = format_weight(weight)
fund_dividend = last_nav['fund_div'] + sum( fund_dividend = last_nav['fund_div'] + sum(
map(lambda k: share[k] * fund_dividend[k], filter(lambda k: k in fund_dividend, share.keys()))) map(lambda k: share[k] * fund_dividend[k], filter(lambda k: k in fund_dividend, share.keys())))
asset_nav = fund_av + fund_dividend asset_nav = fund_av
nav = last_nav['nav'] * asset_nav / last_nav['asset_nav'] nav = last_nav['nav'] * asset_nav / last_nav['asset_nav']
div_forecast = last_nav['div_forecast'] div_forecast = last_nav['div_forecast']
if self.is_first_workday(day): if self.is_first_workday(day):
......
...@@ -73,6 +73,9 @@ class BaseRebalanceSignal(RebalanceSignal, ABC): ...@@ -73,6 +73,9 @@ class BaseRebalanceSignal(RebalanceSignal, ABC):
last_re = rrs.get_last_one(max_date=day, risk=risk, effective=True) last_re = rrs.get_last_one(max_date=day, risk=risk, effective=True)
return last_re return last_re
def clear(self, min_date=None, risk: PortfoliosRisk = None):
rrs.delete(min_date=min_date, risk=risk)
@component(bean_name='signal-report') @component(bean_name='signal-report')
class SignalReportor(RoboReportor): class SignalReportor(RoboReportor):
......
...@@ -24,27 +24,27 @@ class BacktestExecutor(RoboExecutor): ...@@ -24,27 +24,27 @@ class BacktestExecutor(RoboExecutor):
@autowired(names={'datum': 'hk-datum'}) @autowired(names={'datum': 'hk-datum'})
def __init__(self, datum: Datum = None, pool: AssetPool = None, def __init__(self, datum: Datum = None, pool: AssetPool = None,
syncs: List[DataSync] = None, export: RoboExportor = None, syncs: List[DataSync] = None, export: RoboExportor = None,
builder: PortfoliosBuilder = None, hold: PortfoliosHolder = None): builder: PortfoliosBuilder = None, hold: PortfoliosHolder = None,
signal: RebalanceSignal = None):
self._datum = datum self._datum = datum
self._pool = pool self._pool = pool
self._builder = builder self._builder = builder
self._hold = hold self._hold = hold
self._syncs = syncs self._syncs = syncs
self._export = export self._export = export
self._signal = signal
self._config = get_config(__name__)['backtest'] self._config = get_config(__name__)['backtest']
@staticmethod @staticmethod
def get_last_business_day(start_date, end_date): def get_last_business_day(start_date, end_date):
# 生成日期范围并转换为DataFrame # 生成日期范围并转换为DataFrame
dates = pd.date_range(start_date, end_date, freq='MS') dates = pd.date_range(start_date, end_date, freq='M')
if dates[0] != start_date:
dates = dates.insert(0, start_date)
df = pd.DataFrame({'dates': dates}) df = pd.DataFrame({'dates': dates})
df['last_business_day'] = df['dates'].map(
lambda date: pd.date_range(start=date, periods=1, freq='BM')[-1]
)
# 每隔n个月提取第一个工作日
result = [] result = []
for i in range(0, len(df), get_config('portfolios')['holder']['warehouse-frequency']): for i in range(0, len(df), get_config('portfolios')['holder']['warehouse-frequency']):
result.append(df.iloc[i]['last_business_day']) result.append(df.iloc[i]['dates'])
delta = workday_range(result[0], result[1]) delta = workday_range(result[0], result[1])
period = get_config(__name__)['backtest']['sealing-period'] period = get_config(__name__)['backtest']['sealing-period']
if len(delta) <= period: if len(delta) <= period:
...@@ -83,6 +83,7 @@ class BacktestExecutor(RoboExecutor): ...@@ -83,6 +83,7 @@ class BacktestExecutor(RoboExecutor):
BacktestStep.NORMAL_PORTFOLIO): BacktestStep.NORMAL_PORTFOLIO):
logger.info('start to clear normal portfolios'.center(50, '-')) logger.info('start to clear normal portfolios'.center(50, '-'))
self._builder.clear() self._builder.clear()
self._signal.clear()
if self.start_step.within(BacktestStep.HOLD_PORTFOLIO) and self.end_step.without(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, '-')) logger.info('start to clear hold portfolios'.center(50, '-'))
self._hold.clear() self._hold.clear()
...@@ -199,5 +200,3 @@ class RealExecutor(RoboExecutor): ...@@ -199,5 +200,3 @@ class RealExecutor(RoboExecutor):
f'export email for date[{format_date(date)}] send success, use[{(dt.now() - now).seconds}s]') f'export email for date[{format_date(date)}] send success, use[{(dt.now() - now).seconds}s]')
else: else:
logger.info(f'today[{format_date(date)}] is a rest day, do not execute the daily real robo.') logger.info(f'today[{format_date(date)}] is a rest day, do not execute the daily real robo.')
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