Commit 226692af authored by jichao's avatar jichao

依赖注入实现中

parent 41b8f631
from abc import ABCMeta, abstractmethod from abc import ABC, abstractmethod
from enum import Enum, unique from enum import Enum, unique
...@@ -15,7 +15,7 @@ class BusinessException(Exception): ...@@ -15,7 +15,7 @@ class BusinessException(Exception):
return self.__msg return self.__msg
class Datum(metaclass=ABCMeta): class Datum(ABC):
''' '''
基础资料服务,基金资料数据,各种指数,指标资料数据 基础资料服务,基金资料数据,各种指数,指标资料数据
''' '''
...@@ -31,7 +31,7 @@ class Datum(metaclass=ABCMeta): ...@@ -31,7 +31,7 @@ class Datum(metaclass=ABCMeta):
pass pass
class Navs(metaclass=ABCMeta): class Navs(ABC):
''' '''
基础数据相关服务,基金净值,各种指标 高开低收 基础数据相关服务,基金净值,各种指标 高开低收
''' '''
...@@ -47,25 +47,37 @@ class Navs(metaclass=ABCMeta): ...@@ -47,25 +47,37 @@ class Navs(metaclass=ABCMeta):
pass pass
class FundOptimize(metaclass=ABCMeta): class Optimize(ABC):
''' '''
基金优选相关服务 优选相关服务ABC
''' '''
@abstractmethod @abstractmethod
def find_optimize(self, fund_ids, day): def find_optimize(self, ids, day):
''' '''
从多个基金id中,选出指定日期最优的基金id 从多id中,选出指定日期最优的id
:param fund_ids: 待选基金id列表 :param ids: 待选id列表
:param day: 指定日期 :param day: 指定日期
:return: 最优的基金id :return: 最优的id
''' '''
pass pass
@abstractmethod @abstractmethod
def get_optimize_pool(self, day): def get_optimize_pool(self, day):
''' '''
根据基金优选获取指定日期的基金 根据优选规则获取指定日期的优选
:param day: 指定日期 :param day: 指定日期
:return: 基金id列表 :return: 优选id列表
''' '''
pass pass
class EwmaCvar(metaclass=ABCMeta):
'''
ewma相关服务
'''
def build_ewma_cvar(self):
pass
import json import json
import pandas as pd import pandas as pd
from abc import ABC, abstractmethod
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from empyrical import sortino_ratio from empyrical import sortino_ratio
from framework import filter_weekend, dict_remove, get_config, component, autowired from framework import filter_weekend, dict_remove, get_config, component, autowired
from api import FundOptimize, Navs, BusinessException, Datum from api import Optimize, Navs, BusinessException, Datum
from fund_pool.dao import robo_optimize_pool as rop from fund_pool.dao import robo_optimize_pool as rop
@component class SortinoOptimize(Optimize, ABC):
class SortinoFundOptimize(FundOptimize):
_navs: Navs = None
_datum: Datum = None
@autowired def __init__(self):
def __init__(self, navs: Navs = None, datum: Datum = None):
self._navs = navs
self._datum = datum
optimize_config = get_config(__name__) optimize_config = get_config(__name__)
self._config = [{ self._config = [{
**x, **x,
...@@ -27,35 +20,78 @@ class SortinoFundOptimize(FundOptimize): ...@@ -27,35 +20,78 @@ class SortinoFundOptimize(FundOptimize):
def find_optimize(self, fund_ids, day): def find_optimize(self, fund_ids, day):
if not self._config: if not self._config:
raise BusinessException(f"find optimize, but not found sortino config.") raise BusinessException(f"find optimize, but not found sortino config.")
start = filter_weekend(sorted([day - relativedelta(days=1, **dict_remove(x, ('weight', 'name'))) for x in self._config])[0]) pct_change = pd.DataFrame(self.get_pct_change(fund_ids, day))
fund_navs = pd.DataFrame(self._navs.get_fund_navs(fund_ids=tuple(fund_ids), min_date=start, max_date=day)) pct_change.set_index('date', inplace=True)
fund_navs.sort_values('nav_date', inplace=True)
fund_navs = fund_navs.pivot_table(index='nav_date', columns='fund_id', values='nav_cal')
fund_navs.fillna(method='ffill', inplace=True)
day_income = round(fund_navs.pct_change(), 4)
sortino = pd.DataFrame() sortino = pd.DataFrame()
for item in self._config: for item in self._config:
delta_kwargs = item.copy() delta_kwargs = item.copy()
del delta_kwargs['weight'], delta_kwargs['name'] del delta_kwargs['weight'], delta_kwargs['name']
ratio = dict(sortino_ratio(day_income.truncate(before=(day - relativedelta(**delta_kwargs))))) ratio = dict(sortino_ratio(pct_change.truncate(before=(day - relativedelta(**delta_kwargs)))))
sortino = pd.concat([sortino, pd.DataFrame([ratio], index=[item['name']])]) sortino = pd.concat([sortino, pd.DataFrame([ratio], index=[item['name']])])
sortino = sortino.T sortino = sortino.T
sortino['score'] = sortino.apply(lambda r: sum([x['weight'] * r[x['name']] for x in self._config]), axis=1) sortino['score'] = sortino.apply(lambda r: sum([x['weight'] * r[x['name']] for x in self._config]), axis=1)
sortino.sort_values('score', ascending=False, inplace=True) sortino.sort_values('score', ascending=False, inplace=True)
return day_income.columns[sortino.index[0]] return pct_change.columns[sortino.index[0]]
def get_optimize_pool(self, day): def get_optimize_pool(self, day):
last_one = rop.get_last_one(day) last_one = rop.get_last_one(day)
if not last_one: if not last_one:
funds = pd.DataFrame(self._datum.get_fund_datums())
pool = [] pool = []
for (category, asset_type), fund_group in funds.groupby(by=['category', 'assetType']): for fund_group in self.get_groups():
if len(fund_group) > 1: if len(fund_group) > 1:
pool.append(self.find_optimize(tuple(fund_group['id']), day)) pool.append(self.find_optimize(fund_group, day))
else: else:
pool.append(fund_group.iloc[0].id) pool.append(fund_group[0])
rop.insert(day, sorted(pool)) rop.insert(day, sorted(pool))
last_one = rop.get_last_one(day) last_one = rop.get_last_one(day)
return json.loads(last_one['fund_ids']) return json.loads(last_one['fund_ids'])
@abstractmethod
def get_groups(self):
'''
:return: 返回待处理的id数组
'''
pass
@abstractmethod
def get_pct_change(self, fund_ids, day):
'''
根据id数组,返回指定日期的收益率
:param fund_ids: id数组
:param day: 指定的日期
:return: 收益率
'''
pass
@component
class FundSortinoOptimize(SortinoOptimize):
'''
根据索提诺比率计算基金优选的优选实现
'''
@autowired
def __init__(self, navs: Navs = None, datum: Datum = None):
super().__init__()
self._navs = navs
self._datum = datum
def get_groups(self):
funds = pd.DataFrame(self._datum.get_fund_datums())
result = []
for (category, asset_type), fund_group in funds.groupby(by=['category', 'assetType']):
result.append(tuple(fund_group['id']))
return result
def get_pct_change(self, fund_ids, day):
if not self._config:
raise BusinessException(f"find optimize, but not found sortino config.")
start = filter_weekend(sorted([day - relativedelta(days=1, **dict_remove(x, ('weight', 'name'))) for x in self._config])[0])
fund_navs = pd.DataFrame(self._navs.get_fund_navs(fund_ids=tuple(fund_ids), min_date=start, max_date=day))
fund_navs.sort_values('nav_date', inplace=True)
fund_navs = fund_navs.pivot_table(index='nav_date', columns='fund_id', values='nav_cal')
fund_navs.fillna(method='ffill', inplace=True)
result = round(fund_navs.pct_change().dropna(), 4)
result.reset_index(inplace=True)
result.rename(columns={'nav_date': 'date'}, inplace=True)
return result.to_dict('records')
from framework import autowired, parse_date, logger from framework import autowired, parse_date, logger
from api import FundOptimize from api import Optimize
@autowired @autowired
def start(optimize: FundOptimize = None): def start(optimize: Optimize = None):
pool = optimize.get_optimize_pool(parse_date('2022-11-07')) pool = optimize.get_optimize_pool(parse_date('2022-11-07'))
logger.info(pool) logger.info(pool)
......
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