Commit 466c7595 authored by stephen.wang's avatar stephen.wang

Merge remote-tracking branch 'origin/dev-dividend' into dev-dividend

parents f6fff7b4 69854f30
import logging
import sys import sys
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from datetime import datetime as dt from datetime import datetime as dt
...@@ -6,6 +7,8 @@ from typing import List ...@@ -6,6 +7,8 @@ from typing import List
from py_jftech import get_config, parse_date from py_jftech import get_config, parse_date
logger = logging.getLogger(__name__)
@unique @unique
class BacktestStep(Enum): class BacktestStep(Enum):
......
...@@ -42,7 +42,7 @@ class SortinoAssetOptimize(AssetOptimize, ABC): ...@@ -42,7 +42,7 @@ class SortinoAssetOptimize(AssetOptimize, ABC):
pass pass
@abstractmethod @abstractmethod
def get_groups(self): def get_groups(self, day=None):
''' '''
:return: 返回待处理的id数组 :return: 返回待处理的id数组
''' '''
...@@ -122,7 +122,7 @@ class FundDividendSortinoAssetOptimize(SortinoAssetOptimize): ...@@ -122,7 +122,7 @@ class FundDividendSortinoAssetOptimize(SortinoAssetOptimize):
min_dates = self.nav_min_dates min_dates = self.nav_min_dates
max_incept_date = sorted([(day - relativedelta(**x)) for x in self.delta_kwargs])[0] max_incept_date = sorted([(day - relativedelta(**x)) for x in self.delta_kwargs])[0]
max_incept_date = max_incept_date if is_workday(max_incept_date) else next_workday(max_incept_date) max_incept_date = max_incept_date if is_workday(max_incept_date) else next_workday(max_incept_date)
for fund_group in self.get_groups(): for fund_group in self.get_groups(day):
fund_group = [x for x in fund_group if min_dates[x] <= max_incept_date] fund_group = [x for x in fund_group if min_dates[x] <= max_incept_date]
if len(fund_group) > self.optimize_count: if len(fund_group) > self.optimize_count:
pool.extend(self.find_optimize(tuple(fund_group), day)[0]) pool.extend(self.find_optimize(tuple(fund_group), day)[0])
...@@ -132,8 +132,16 @@ class FundDividendSortinoAssetOptimize(SortinoAssetOptimize): ...@@ -132,8 +132,16 @@ class FundDividendSortinoAssetOptimize(SortinoAssetOptimize):
last_one = rop.get_last_one(day=day, type=AssetPoolType.OPTIMIZE) last_one = rop.get_last_one(day=day, type=AssetPoolType.OPTIMIZE)
return json.loads(last_one['asset_ids']) return json.loads(last_one['asset_ids'])
def get_filtered_funds(self): def get_filtered_funds(self, day):
funds = self._datum.get_datums(type=DatumType.FUND) funds = self._datum.get_datums(type=DatumType.FUND)
if get_config('portfolios.checker.month-fund-filter'):
# 如果有按月剔除
filters = get_config('portfolios.checker.month-fund-filter')
excludes = filters.get(day.month)
if excludes:
for f in funds[:]:
if f['bloombergTicker'] in excludes:
funds.remove(f)
if self.asset_filter: if self.asset_filter:
filters = list(self.asset_filter.keys())[0] filters = list(self.asset_filter.keys())[0]
funds_in = [] funds_in = []
...@@ -143,8 +151,8 @@ class FundDividendSortinoAssetOptimize(SortinoAssetOptimize): ...@@ -143,8 +151,8 @@ class FundDividendSortinoAssetOptimize(SortinoAssetOptimize):
return funds_in return funds_in
return funds return funds
def get_groups(self): def get_groups(self, day=None):
funds = pd.DataFrame(self.get_filtered_funds()) funds = pd.DataFrame(self.get_filtered_funds(day))
result = [] result = []
if self.asset_include: if self.asset_include:
include = list(self.asset_include.keys())[0] include = list(self.asset_include.keys())[0]
......
...@@ -34,7 +34,7 @@ py-jftech: ...@@ -34,7 +34,7 @@ py-jftech:
port: ${MYSQL_PORT:3306} port: ${MYSQL_PORT:3306}
user: ${MYSQL_USER:root} user: ${MYSQL_USER:root}
password: ${MYSQL_PWD:changeit} password: ${MYSQL_PWD:changeit}
dbname: ${MYSQL_DBNAME:mdiv_prr3} # mdiv_prr3 dbname: ${MYSQL_DBNAME:j_robo} # mdiv_prr3
injectable: injectable:
names: names:
backtest: robo_executor.BacktestExecutor backtest: robo_executor.BacktestExecutor
...@@ -115,7 +115,7 @@ portfolios: # 投组模块 ...@@ -115,7 +115,7 @@ portfolios: # 投组模块
checker: #投组检测模块 checker: #投组检测模块
switch: on #是否开启检查 switch: on #是否开启检查
custom-type-priority: [3,2,1,4] # 检测优先级 custom-type-priority: [3,2,1,4] # 检测优先级
month-fund-filter: {2:['TEMSCFA LX Equity'],12:['TEMHYAD LX Equity','TEMFIAI LX Equity']} # 根据月份删除某几档基金
reports: # 报告模块相关 reports: # 报告模块相关
navs: navs:
type: FUND type: FUND
...@@ -245,7 +245,7 @@ robo-executor: # 执行器相关 ...@@ -245,7 +245,7 @@ robo-executor: # 执行器相关
sealing-period: 10 #调仓封闭期 sealing-period: 10 #调仓封闭期
start-step: ${BACKTEST_START_STEP:1} # 回测从哪一步开始执行 1:计算资产池;2:计算最优投组:3:计算再平衡信号以及持仓投组 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: off clean-up: on
real: # 实盘执行器 real: # 实盘执行器
export: ${EXPORT_ENABLE:off} # 是否开启报告 export: ${EXPORT_ENABLE:off} # 是否开启报告
start-date: 2023-05-08 # 实盘开始时间 start-date: 2023-05-08 # 实盘开始时间
......
...@@ -29,10 +29,16 @@ class DefaultPortfoliosChecker(PortfoliosChecker): ...@@ -29,10 +29,16 @@ class DefaultPortfoliosChecker(PortfoliosChecker):
# step1: 检查原始投组的customType。检查顺序用列表呈现,依序进行 # step1: 检查原始投组的customType。检查顺序用列表呈现,依序进行
priority = self._config.get('custom-type-priority') priority = self._config.get('custom-type-priority')
for p in priority: for p in priority:
# 找出对应优先级序列的基金列表
keys = [key for key in portfolios.keys() if customType[key] == p] keys = [key for key in portfolios.keys() if customType[key] == p]
# 若存在匹配值则执行后跳出循环 # 若存在匹配值则执行后跳出循环
if len(keys) > 0: if len(keys) > 0:
ids = [fund['id'] for fund in funds if fund['companyType'] != list(companies)[0]] # 选取非同公司的、风险等级小于等于原基金的 基金
min_risk = min(fund['risk'] for fund in funds if str(fund['id']) in keys)
ids = [fund['id'] for fund in funds if fund['companyType'] != list(companies)[0] and
fund['risk'] <= min_risk]
if len(ids) == 0:
continue
best = self.find_highest_score(ids, day) best = self.find_highest_score(ids, day)
# 若刚好有一个匹配,直接替换 # 若刚好有一个匹配,直接替换
if len(keys) == 1: if len(keys) == 1:
...@@ -42,7 +48,7 @@ class DefaultPortfoliosChecker(PortfoliosChecker): ...@@ -42,7 +48,7 @@ class DefaultPortfoliosChecker(PortfoliosChecker):
else: else:
# 算分,把分低的替换掉 # 算分,把分低的替换掉
scores = self.do_score(keys, day) scores = self.do_score(keys, day)
weight_scores = {key: scores[key]*portfolios[key] for key in keys} weight_scores = {key: scores[key] * portfolios[key] for key in keys}
lowest = min(scores, key=lambda k: weight_scores[k]) lowest = min(scores, key=lambda k: weight_scores[k])
portfolios[best] = portfolios[lowest] portfolios[best] = portfolios[lowest]
# 删除原始键 # 删除原始键
......
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