Commit 2c653030 authored by wenwen.tang's avatar wenwen.tang 😕

update

parent 4c46b934
...@@ -423,6 +423,15 @@ class PortfoliosHolder(ABC): ...@@ -423,6 +423,15 @@ class PortfoliosHolder(ABC):
''' '''
pass pass
@abstractmethod
def is_dividend_date(self, day):
"""
是否为配息日
:param day: 日期
:return: 是否为配息日
"""
pass
@abstractmethod @abstractmethod
def clear(self, day=None, risk: PortfoliosRisk = None): def clear(self, day=None, risk: PortfoliosRisk = None):
''' '''
......
...@@ -76,6 +76,7 @@ portfolios: # 投组模块 ...@@ -76,6 +76,7 @@ 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号
solver: # 解算器相关 solver: # 解算器相关
tol: 1E-10 # 误差满足条件 tol: 1E-10 # 误差满足条件
navs: # 净值要求 navs: # 净值要求
...@@ -105,7 +106,7 @@ robo-executor: # 执行器相关 ...@@ -105,7 +106,7 @@ robo-executor: # 执行器相关
use: ${ROBO_EXECUTOR:backtest} # 执行哪个执行器,优先取系统环境变量ROBO_EXECUTOR的值,默认backtest use: ${ROBO_EXECUTOR:backtest} # 执行哪个执行器,优先取系统环境变量ROBO_EXECUTOR的值,默认backtest
sync-data: ${SYNC_DATA:off} # 是否开启同步资料数据 sync-data: ${SYNC_DATA:off} # 是否开启同步资料数据
backtest: # 回测执行器相关 backtest: # 回测执行器相关
start-date: 2022-09-01 # 回测起始日期 start-date: 2012-10-16 # 回测起始日期
end-date: 2023-03-03 # 回测截止日期 end-date: 2023-03-03 # 回测截止日期
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:计算再平衡信号以及持仓投组
......
...@@ -12,6 +12,8 @@ __COLUMNS__ = { ...@@ -12,6 +12,8 @@ __COLUMNS__ = {
'rhp_rebalance': 'rebalance', 'rhp_rebalance': 'rebalance',
'rhp_portfolios': 'portfolios', 'rhp_portfolios': 'portfolios',
'rhp_nav': 'nav', 'rhp_nav': 'nav',
'rhp_fund_div': 'fund_div',
'rhp_asset_nav': 'asset_nav',
} }
......
import datetime
import json import json
import logging import logging
import pandas as pd import pandas as pd
from py_jftech import ( from py_jftech import (
component, autowired, get_config, next_workday, format_date component, autowired, get_config, next_workday, format_date, is_workday
) )
from api import PortfoliosHolder, PortfoliosRisk, Navs, RoboExecutor, PortfoliosType, PortfoliosBuilder from api import PortfoliosHolder, PortfoliosRisk, Navs, RoboExecutor, PortfoliosType, PortfoliosBuilder
...@@ -66,23 +67,29 @@ class DividendPortfoliosHolder(PortfoliosHolder): ...@@ -66,23 +67,29 @@ class DividendPortfoliosHolder(PortfoliosHolder):
share = {int(x): y for x, y in json.loads(last_nav['portfolios'])['share'].items()} share = {int(x): y for x, y in json.loads(last_nav['portfolios'])['share'].items()}
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]
# todo 如果建仓是遇到基金配息,则忽略
fund_dividend = fund_div_tuple[1] fund_dividend = fund_div_tuple[1]
nav = round(sum([navs[x] * y for x, y in share.items()]), 4)
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']
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]
# todo 如果建仓是遇到基金配息,则忽略
fund_dividend = fund_div_tuple[1] fund_dividend = fund_div_tuple[1]
dividend = nav * self.month_dividend dividend = nav * self.month_dividend
nav = nav - dividend nav = nav - dividend
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 = sum(map(lambda k: share[k] * fund_dividend[k], filter(lambda k: k in fund_dividend, share.keys()))) # todo 如果建仓是遇到基金配息,则忽略
dividend_acc = dividend + dividend_acc + fund_dividend fund_dividend = sum(
map(lambda k: share[k] * fund_dividend[k], filter(lambda k: k in fund_dividend, share.keys())))
dividend_acc = dividend + dividend_acc
asset_nav = nav + fund_dividend + dividend
rhp.insert({ rhp.insert({
'date': day, 'date': day,
'risk': risk, 'risk': risk,
'dividend': dividend, 'dividend': dividend,
'fund_div': fund_dividend,
'div_acc': dividend_acc, 'div_acc': dividend_acc,
'rebalance': True, 'rebalance': True,
'portfolios': { 'portfolios': {
...@@ -90,6 +97,7 @@ class DividendPortfoliosHolder(PortfoliosHolder): ...@@ -90,6 +97,7 @@ class DividendPortfoliosHolder(PortfoliosHolder):
'share': share, 'share': share,
}, },
'nav': nav, 'nav': nav,
'asset_nav': asset_nav,
}) })
def no_rebalance(self, day, risk: PortfoliosRisk, last_nav): def no_rebalance(self, day, risk: PortfoliosRisk, last_nav):
...@@ -100,12 +108,18 @@ class DividendPortfoliosHolder(PortfoliosHolder): ...@@ -100,12 +108,18 @@ class DividendPortfoliosHolder(PortfoliosHolder):
nav = round(sum([navs[x] * y for x, y in share.items()]), 4) nav = round(sum([navs[x] * y for x, y in share.items()]), 4)
weight = {x: round(y * navs[x] / nav, 2) for x, y in share.items()} weight = {x: round(y * navs[x] / nav, 2) for x, y in share.items()}
weight = format_weight(weight) weight = format_weight(weight)
fund_dividend = sum(map(lambda k: share[k] * fund_dividend[k], filter(lambda k: k in fund_dividend, share.keys()))) dividend = last_nav['dividend']
dividend_acc = last_nav['div_acc'] + fund_dividend fund_dividend = last_nav['fund_div'] + sum(
map(lambda k: share[k] * fund_dividend[k], filter(lambda k: k in fund_dividend, share.keys())))
dividend_acc = last_nav['div_acc']
if self.is_dividend_date(day):
dividend = 0
asset_nav = nav + fund_dividend + dividend
rhp.insert({ rhp.insert({
'date': day, 'date': day,
'risk': risk, 'risk': risk,
'dividend': 0, 'dividend': dividend,
'fund_div': fund_dividend,
'div_acc': dividend_acc, 'div_acc': dividend_acc,
'signal_id': last_nav['signal_id'], 'signal_id': last_nav['signal_id'],
'rebalance': False, 'rebalance': False,
...@@ -114,6 +128,7 @@ class DividendPortfoliosHolder(PortfoliosHolder): ...@@ -114,6 +128,7 @@ class DividendPortfoliosHolder(PortfoliosHolder):
'share': share, 'share': share,
}, },
'nav': nav, 'nav': nav,
'asset_nav': asset_nav,
}) })
def get_navs_and_div(self, day, fund_ids): def get_navs_and_div(self, day, fund_ids):
...@@ -127,6 +142,14 @@ class DividendPortfoliosHolder(PortfoliosHolder): ...@@ -127,6 +142,14 @@ class DividendPortfoliosHolder(PortfoliosHolder):
def clear(self, day=None, risk: PortfoliosRisk = None): def clear(self, day=None, risk: PortfoliosRisk = None):
rhp.delete(min_date=day, risk=risk) rhp.delete(min_date=day, risk=risk)
def is_dividend_date(self, day):
div_date = self._config['dividend-date']
div_date = datetime.date(day.year, day.month, div_date)
if is_workday(div_date):
return div_date.day == day.day
else:
return next_workday(div_date).day == day.day
@property @property
def month_dividend(self): def month_dividend(self):
return self._config['dividend-rate'] / 12 return self._config['dividend-rate'] / 12
......
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