diff --git a/config-svrobo5.yml b/config-svrobo5.yml index dd549593466cb63e27ae712d0a49c77ec33d0f49..bd7bf21815b6e9c511ab51b77a4ce43d7a2bb606 100644 --- a/config-svrobo5.yml +++ b/config-svrobo5.yml @@ -86,6 +86,7 @@ portfolios: # æŠ•ç»„æ¨¡å— dividend-date: 15 #é…æ¯æ—¥ï¼Œæ¯æœˆ15å· dividend-adjust-day: [1,4,7,10] #æ¯å¹´çš„首个å£åº¦è°ƒæ•´é…æ¯ warehouse-frequency: 1 #æ¯éš”1个月调一次仓 + warehouse-transfer-date: 1 #调仓日 solver: # 解算器相关 tol: 1E-10 # 误差满足æ¡ä»¶ navs: # å‡€å€¼è¦æ±‚ diff --git a/config-svrobo6.yml b/config-svrobo6.yml index 1fb69b3559b56c4f94e17547242ad18e2ddb1bdb..56d39208d44165dc53464757eaafd82a48434ebe 100644 --- a/config-svrobo6.yml +++ b/config-svrobo6.yml @@ -51,7 +51,7 @@ py-jftech: max-workers: ${MAX_PROCESS:4} basic: # åŸºç¡€ä¿¡æ¯æ¨¡å— sync: - start-date: 1990-01-01 # åŒæ¥æ•°æ®å¼€å§‹æ—¥æœŸ + start-date: 2018-08-26 # åŒæ¥æ•°æ®å¼€å§‹æ—¥æœŸ datum: # èµ„æ–™æ¨¡å— change: date: ${DATUM_CHANGE_DATE} @@ -85,11 +85,12 @@ portfolios: # æŠ•ç»„æ¨¡å— dividend-date: 15 #é…æ¯æ—¥ï¼Œæ¯æœˆ15å· dividend-adjust-day: [1,4,7,10] #æ¯å¹´çš„首个å£åº¦è°ƒæ•´é…æ¯ warehouse-frequency: 1 #æ¯éš”1个月调一次仓 + warehouse-transfer-date: 1 #调仓日 redeem-list: [ 'TEUSAAU LX Equity', 'LIGTRAA ID Equity', 'TEMFHAC LX Equity', 'LUSHUAA ID Equity' ] #从æŒä»“ä¸çš„ä½Žé£Žé™©èµ„äº§â€œç›´æŽ¥â€æŒ‰åºèµŽå›ž solver: # 解算器相关 - model: arc # 结算模型 ARC ,PRR, ~ æ ‡å‡†è§£ç®—å™¨ + model: prr # 结算模型 ARC ,PRR, ~ æ ‡å‡†è§£ç®—å™¨ arc: on #是å¦å¼€å¯ARC - brr: 0.01 #误差补å¿å€¼ + brr: 0.02 #误差补å¿å€¼ trr: 3 tol: 1E-10 # 误差满足æ¡ä»¶ navs: # å‡€å€¼è¦æ±‚ @@ -98,9 +99,9 @@ portfolios: # æŠ•ç»„æ¨¡å— max-nan: # 最大缺失净值æ¡ä»¶ asset: 8 # å•一资产最多缺少多少交易日数æ®ï¼Œåˆ™è¸¢å‡ºèµ„äº§æ± day: 0.5 # å•ä¸€äº¤æ˜“æ—¥æœ€å¤šç¼ºå°‘ç™¾åˆ†ä¹‹å¤šå°‘å‡€å€¼ï¼Œåˆ™åˆ é™¤è¯¥äº¤æ˜“æ—¥ - risk: [] # 资产风险ç‰çº§è¦æ±‚,å¯åˆ†å¼€å†™ä¹Ÿå¯ä»¥åˆå¹¶å†™ï¼Œe.g. risk:[ 2, 3 ] 则表示 所有投组资产风险ç‰çº§éƒ½æ˜¯ 2 或 3 - LARC: [0.5, 0.1, 0.1, 0.1] #低阈值 - UARC: [0.7, 0.25, 0.25, 0.25] #高阈值 + risk: [ ] # 资产风险ç‰çº§è¦æ±‚,å¯åˆ†å¼€å†™ä¹Ÿå¯ä»¥åˆå¹¶å†™ï¼Œe.g. risk:[ 2, 3 ] 则表示 所有投组资产风险ç‰çº§éƒ½æ˜¯ 2 或 3 + LARC: [ 0.30, 0.00, 0.00 ] #低阈值 + UARC: [ 0.70, 0.70, 0.70 ] #高阈值 matrix-rtn-days: 20 # 计算回报率矩阵时,回报率滚动天数 asset-count: [5,5] # 投组资产个数。e.g. count 或 [min, max] 分别表示 最大最å°éƒ½ä¸ºcount 或 最å°ä¸ºmin 最大为max,å¦å¤–这里也å¯ä»¥ç±»ä¼¼ä¸Šé¢ç»™ä¸åŒé£Žé™©ç‰çº§åˆ†åˆ«é…ç½® mpt: # mpt计算相关 @@ -234,12 +235,12 @@ robo-executor: # 执行器相关 use: ${ROBO_EXECUTOR:backtest} # 执行哪个执行器,优先å–系统环境å˜é‡ROBO_EXECUTOR的值,默认backtest sync-data: ${SYNC_DATA:off} # 是å¦å¼€å¯åŒæ¥èµ„æ–™æ•°æ® backtest: # 回测执行器相关 - start-date: 2022-02-16 # 回测起始日期 - end-date: 2023-01-03 # å›žæµ‹æˆªæ¢æ—¥æœŸ + start-date: 2018-11-26 # 回测起始日期 + end-date: 2019-01-13 # å›žæµ‹æˆªæ¢æ—¥æœŸ sealing-period: 10 #调仓å°é—期 - start-step: ${BACKTEST_START_STEP:3} # 回测从哪一æ¥å¼€å§‹æ‰§è¡Œ 1:è®¡ç®—èµ„äº§æ± ï¼›2:计算最优投组:3:计算å†å¹³è¡¡ä¿¡å·ä»¥åŠæŒä»“投组 + start-step: ${BACKTEST_START_STEP:1} # 回测从哪一æ¥å¼€å§‹æ‰§è¡Œ 1:è®¡ç®—èµ„äº§æ± ï¼›2:计算最优投组:3:计算å†å¹³è¡¡ä¿¡å·ä»¥åŠæŒä»“投组 end-step: ${BACKTEST_END_STEP:3} # å›žæµ‹ä»Žå“ªä¸€æ¥æ‰§è¡Œå®ŒæˆåŽç»“æŸæ‰§è¡Œ 1:è®¡ç®—èµ„äº§æ± ï¼›2:计算最优投组:3:计算å†å¹³è¡¡ä¿¡å·ä»¥åŠæŒä»“投组 - clean-up: on + clean-up: off real: # 实盘执行器 export: ${EXPORT_ENABLE:off} # 是å¦å¼€å¯æŠ¥å‘Š start-date: 2023-05-08 # 实盘开始时间 diff --git a/portfolios/holder.py b/portfolios/holder.py index 6141888bb86c4fb1b64e26787169633867179dd1..6375419b6b5917de103b84be7f9600dc93963d91 100644 --- a/portfolios/holder.py +++ b/portfolios/holder.py @@ -266,7 +266,7 @@ class InvTrustPortfoliosHolder(DividendPortfoliosHolder): # è‹¥è°ƒä»“å½“æ—¥ï¼Œæœ‰åŸºé‡‘äº§ç”Ÿé…æ¯ share_nav = {x: fund_nav * w / navs[x] for x, w in weight.items()} share_nodiv_nav = {x: nav * w / nav_cals[x] for x, w in weight.items()} - if self.is_first_workday(day): + if self.is_transfer_workday(day): div_forecast = asset_nav * self.month_dividend else: fund_av = self.init_nav @@ -311,10 +311,11 @@ class InvTrustPortfoliosHolder(DividendPortfoliosHolder): 'asset_nav': asset_nav, }) - def is_first_workday(self, day): - # 获å–当月第一天的日期 - first_day = date(day.year, day.month, 1) - first_work_day = first_day if is_workday(first_day) else next_workday(first_day) + def is_transfer_workday(self, day): + transfer_date = self._config['warehouse-transfer-date'] + # 获å–当月第n天的日期 + transfer_date = date(day.year, day.month, transfer_date) + first_work_day = transfer_date if is_workday(transfer_date) else next_workday(transfer_date) return day.day == first_work_day.day def no_rebalance(self, day, risk: PortfoliosRisk, last_nav): @@ -352,7 +353,7 @@ class InvTrustPortfoliosHolder(DividendPortfoliosHolder): weight_nodiv_nav = format_weight(weight_nodiv_nav) asset_nav = fund_av div_forecast = last_nav['div_forecast'] - if self.is_first_workday(day): + if self.is_transfer_workday(day): div_forecast = asset_nav * self.month_dividend rhp.insert({ 'date': day, diff --git a/rebalance/base_signal.py b/rebalance/base_signal.py index d4e79ef85a67f0b1aa4429dcd2e2e5d44985e224..fbd1346103ae6e43509cf7dd667571435305e2ed 100644 --- a/rebalance/base_signal.py +++ b/rebalance/base_signal.py @@ -6,7 +6,7 @@ from functools import reduce from typing import List import pandas as pd -from py_jftech import component, autowired, get_config, prev_workday +from py_jftech import component, autowired, get_config, prev_workday, workday_range from py_jftech import is_workday from api import PortfoliosBuilder @@ -48,7 +48,13 @@ class BaseRebalanceSignal(RebalanceSignal, ABC): signal = rrs.get_last_one(day, risk, SignalType.NORMAL, effective=None) if signal: frequency = get_config('portfolios')['holder']['warehouse-frequency'] - date = pd.to_datetime(day.replace(day=1)) + pd.DateOffset(months=frequency) + transfer_date = get_config('portfolios')['holder']['warehouse-transfer-date'] + date = pd.to_datetime(signal['date'].replace(day=transfer_date)) + # 说明å‘生了跨月份问题 + if signal['date'].day > transfer_date: + if rrs.get_count(risk=PortfoliosRisk.FT3, effective=True) > 1: + date = date + pd.DateOffset(months=1) + date = date + pd.DateOffset(months=frequency) date = date - timedelta(days=1) # 指定周期末的工作日 date = date if is_workday(date) else prev_workday(date) diff --git a/robo_executor.py b/robo_executor.py index 79160490a63f4f24e3a59fc8e6db1703f071b2ea..a274e9def3d22514fb8e22843a22c1a0cc1119b9 100644 --- a/robo_executor.py +++ b/robo_executor.py @@ -37,12 +37,13 @@ class BacktestExecutor(RoboExecutor): @staticmethod def get_last_business_day(start_date, end_date): - start_date = prev_workday(start_date) + transfer_date = get_config('portfolios')['holder']['warehouse-transfer-date'] # ç”Ÿæˆæ—¥æœŸèŒƒå›´å¹¶è½¬æ¢ä¸ºDataFrame - dates = pd.date_range(start_date, end_date, freq='M') - if dates[0] != start_date: - dates = dates.insert(0, start_date) + dates = pd.date_range(start_date, end_date, freq='MS', closed='right') + dates = [pd.to_datetime(f"{date.year}-{date.month}-{transfer_date}") for date in dates] + dates.insert(0, start_date) df = pd.DataFrame({'dates': dates}) + df['dates'] = df['dates'].apply(lambda x: prev_workday(x)) result = [] for i in range(0, len(df), get_config('portfolios')['holder']['warehouse-frequency']): result.append(df.iloc[i]['dates'])