Commit 89adaa4a authored by 李宗熹's avatar 李宗熹

产品净值获取方式修改2

parent b2420a78
# -*- coding: UTF-8 -*-
"""
@author: Zongxi.Li
@file:portfolio_diagnose.py
@time:2020/12/07
"""
from app.utils.fund_rank import * from app.utils.fund_rank import *
from app.utils.risk_parity import * from app.utils.risk_parity import *
from app.pypfopt import risk_models from app.pypfopt import risk_models
...@@ -58,6 +52,23 @@ def replace_fund(manager, substrategy, fund_rank): ...@@ -58,6 +52,23 @@ def replace_fund(manager, substrategy, fund_rank):
return df['fund_id'].values[0] return df['fund_id'].values[0]
def get_tamp_fund():
"""获取探普产品池净值表
Returns:
"""
with TAMP_SQL(tamp_fund_engine) as tamp_fund:
tamp_fund_session = tamp_fund.session
sql = "SELECT id FROM tamp_fund_info WHERE id LIKE 'HF%'"
cur = tamp_fund_session.execute(sql)
data = cur.fetchall()
# df = pd.read_sql(sql, con)
df = pd.DataFrame(list(data), columns=['fund_id'])
# df.rename({'id': 'fund_id'}, axis=1, inplace=True)
return df
def search_rank(fund_rank, fund, metric): def search_rank(fund_rank, fund, metric):
"""查找基金在基金排名表中的指标 """查找基金在基金排名表中的指标
...@@ -113,7 +124,8 @@ def choose_good_evaluation(evaluation): ...@@ -113,7 +124,8 @@ def choose_good_evaluation(evaluation):
if v1[0] > 1: if v1[0] > 1:
del evaluation[1] del evaluation[1]
if v2[0] > 1: # if v2[0] > 1:
if v2:
del evaluation[2] del evaluation[2]
if v3[0] > 1: if v3[0] > 1:
del evaluation[3] del evaluation[3]
...@@ -133,7 +145,8 @@ def choose_bad_evaluation(evaluation): ...@@ -133,7 +145,8 @@ def choose_bad_evaluation(evaluation):
if v1[0] < 2: if v1[0] < 2:
del evaluation[1] del evaluation[1]
if v2[0] < 2: # if v2[0] < 2:
if v2:
del evaluation[2] del evaluation[2]
if v3[0] < 2: if v3[0] < 2:
del evaluation[3] del evaluation[3]
...@@ -144,17 +157,13 @@ def choose_bad_evaluation(evaluation): ...@@ -144,17 +157,13 @@ def choose_bad_evaluation(evaluation):
def get_fund_rank(): def get_fund_rank():
"""获取基金指标排名 with TAMP_SQL(tamp_fund_engine) as tamp_product:
tamp_product_session = tamp_product.session
:return: 基金指标排名表
"""
with TAMP_SQL(tamp_fund_engine) as tamp_fund:
tamp_fund_session = tamp_fund.session
sql = "SELECT * FROM fund_rank" sql = "SELECT * FROM fund_rank"
# df = pd.read_sql(sql, con) # df = pd.read_sql(sql, con)
# df = pd.read_csv('fund_rank.csv', encoding='gbk') # df = pd.read_csv('fund_rank.csv', encoding='gbk')
cur = tamp_fund_session.execute(sql) cur = tamp_product_session.execute(sql)
data = cur.fetchall() data = cur.fetchall()
df = pd.DataFrame(list(data), columns=['index', 'fund_id', 'range_return', 'annual_return', 'max_drawdown', df = pd.DataFrame(list(data), columns=['index', 'fund_id', 'range_return', 'annual_return', 'max_drawdown',
'sharp_ratio', 'volatility', 'sortino_ratio', 'downside_risk', 'sharp_ratio', 'volatility', 'sortino_ratio', 'downside_risk',
...@@ -164,73 +173,28 @@ def get_fund_rank(): ...@@ -164,73 +173,28 @@ def get_fund_rank():
return df return df
def get_index_daily(index_id, start_date): def get_index_daily(index_id):
"""获取指数日更数据 """获取指数数据
Args: Args:
index_id: 指数ID index_id: 指数ID
start_date: 数据开始时间
Returns:与组合净值形式相同的表 Returns:与组合净值形式相同的表
""" """
with TAMP_SQL(tamp_fund_engine) as tamp_product: with TAMP_SQL(tamp_fund_engine) as tamp_product:
tamp_product_session = tamp_product.session tamp_product_session = tamp_product.session
sql = "SELECT ts_code, trade_date, close FROM index_daily " \ sql = "SELECT ts_code, trade_date, close FROM index_daily WHERE ts_code='{}'".format(index_id)
"WHERE ts_code='{}' AND trade_date>'{}'".format(index_id, start_date)
# df = pd.read_sql(sql, con).dropna(how='any') # df = pd.read_sql(sql, con).dropna(how='any')
cur = tamp_product_session.execute(sql) cur = tamp_product_session.execute(sql)
data = cur.fetchall() data = cur.fetchall()
df = pd.DataFrame(list(data), columns=['fund_id', 'end_date', 'adj_nav']) df = pd.DataFrame(list(data), columns=['ts_code', 'trade_date', ' close'])
# df.rename({'ts_code': 'fund_id', 'trade_date': 'end_date', 'close': 'adj_nav'}, axis=1, inplace=True) df.rename({'ts_code': 'fund_id', 'trade_date': 'end_date', 'close': 'adj_nav'}, axis=1, inplace=True)
df['end_date'] = pd.to_datetime(df['end_date'])
df.set_index('end_date', drop=True, inplace=True)
df.sort_index(inplace=True, ascending=True)
df = rename_col(df, index_id)
return df
def get_index_monthly(index_id, start_date):
"""获取指数月度数据
Args:
index_id: 指数ID
start_date: 数据开始时间
Returns:与组合净值形式相同的表
"""
with TAMP_SQL(tamp_fund_engine) as tamp_fund:
tamp_fund_session = tamp_fund.session
sql = "SELECT ts_code, trade_date, pct_chg FROM index_monthly " \
"WHERE ts_code='{}' AND trade_date>'{}'".format(index_id, start_date)
# df = pd.read_sql(sql, con).dropna(how='any')
cur = tamp_fund_session.execute(sql)
data = cur.fetchall()
df = pd.DataFrame(list(data), columns=['fund_id', 'end_date', 'pct_chg'])
df['end_date'] = pd.to_datetime(df['end_date']) df['end_date'] = pd.to_datetime(df['end_date'])
df.set_index('end_date', drop=True, inplace=True) df.set_index('end_date', drop=True, inplace=True)
df.sort_index(inplace=True, ascending=True) df.sort_index(inplace=True, ascending=True)
df = rename_col(df, index_id) df = rename_col(df, index_id)
return df
def get_tamp_fund():
"""获取探普产品池净值表
Returns:
"""
with TAMP_SQL(tamp_fund_engine) as tamp_fund:
tamp_fund_session = tamp_fund.session
sql = "SELECT id FROM tamp_fund_info WHERE id LIKE 'HF%'"
cur = tamp_fund_session.execute(sql)
data = cur.fetchall()
# df = pd.read_sql(sql, con)
df = pd.DataFrame(list(data), columns=['fund_id'])
# df.rename({'id': 'fund_id'}, axis=1, inplace=True)
return df return df
...@@ -313,11 +277,11 @@ def get_radar_data(fund): ...@@ -313,11 +277,11 @@ def get_radar_data(fund):
def get_fund_name(fund): def get_fund_name(fund):
with TAMP_SQL(tamp_fund_engine) as tamp_fund: with TAMP_SQL(tamp_fund_engine) as tamp_product:
tamp_fund_session = tamp_fund.session tamp_product_session = tamp_product.session
sql = "SELECT fund_short_name FROM fund_info WHERE id='{}'".format(fund) sql = "SELECT fund_short_name FROM fund_info WHERE id='{}'".format(fund)
# df = pd.read_sql(sql, con) # df = pd.read_sql(sql, con)
cur = tamp_fund_session.execute(sql) cur = tamp_product_session.execute(sql)
data = cur.fetchall() data = cur.fetchall()
df = pd.DataFrame(list(data), columns=['fund_short_name']) df = pd.DataFrame(list(data), columns=['fund_short_name'])
return df return df
...@@ -330,17 +294,14 @@ tamp_fund = get_tamp_fund() ...@@ -330,17 +294,14 @@ tamp_fund = get_tamp_fund()
class PortfolioDiagnose(object): class PortfolioDiagnose(object):
def __init__(self, client_type, portfolio, invest_amount, expect_return=0.2, def __init__(self, client_type, portfolio, invest_amount, expect_return=None,
expect_drawdown=0.1, index_id='000905.SH', invest_type='private', start_date=None, end_date=None): expect_drawdown=None, index_id='000905.SH', invest_type='private', start_date=None, end_date=None):
"""基金诊断 """基金诊断
Args: Args:
client_type: 客户类型:1:保守型, 2:稳健型, 3:平衡型, 4:成长型, 5:进取型 client_type: 客户类型:1:保守型, 2:稳健型, 3:平衡型, 4:成长型, 5:进取型
portfolio: 投资组合:[基金1, 基金2, 基金3...] portfolio: 投资组合:[基金1, 基金2, 基金3...]
invest_amount: 投资金额:10000000元 invest_amount: 投资金额:10000000元
expect_return: 期望收益
expect_drawdown: 期望回撤
index_id: 指数ID
invest_type: 投资类型:public, private, ... invest_type: 投资类型:public, private, ...
start_date: 诊断所需净值的开始日期 start_date: 诊断所需净值的开始日期
end_date: 诊断所需净值的结束日期 end_date: 诊断所需净值的结束日期
...@@ -390,7 +351,6 @@ class PortfolioDiagnose(object): ...@@ -390,7 +351,6 @@ class PortfolioDiagnose(object):
result = fund_info[fund_info['fund_id'] == portfolio[0]] result = fund_info[fund_info['fund_id'] == portfolio[0]]
manager = str(result['manager'].values) manager = str(result['manager'].values)
strategy = result['substrategy'].values strategy = result['substrategy'].values
replaced_fund = replace_fund(manager, strategy, fund_rank) replaced_fund = replace_fund(manager, strategy, fund_rank)
if replaced_fund is not None: if replaced_fund is not None:
...@@ -422,7 +382,7 @@ class PortfolioDiagnose(object): ...@@ -422,7 +382,7 @@ class PortfolioDiagnose(object):
self.no_data_fund.append(portfolio[idx + 1]) self.no_data_fund.append(portfolio[idx + 1])
continue continue
if replaced_fund: if replaced_fund is not None:
prod1 = get_nav(replaced_fund, self.start_date, invest_type=self.invest_type) prod1 = get_nav(replaced_fund, self.start_date, invest_type=self.invest_type)
self.replace_pair[portfolio[idx + 1]] = replaced_fund self.replace_pair[portfolio[idx + 1]] = replaced_fund
self.freq_list.append(get_frequency(prod1)) self.freq_list.append(get_frequency(prod1))
...@@ -503,6 +463,7 @@ class PortfolioDiagnose(object): ...@@ -503,6 +463,7 @@ class PortfolioDiagnose(object):
# if proposal_z_score > 80 and proposal_strategy in add_strategy: # if proposal_z_score > 80 and proposal_strategy in add_strategy:
if proposal_z_score > 60: if proposal_z_score > 60:
proposal_nav = get_tamp_nav(proposal, self.start_date, invest_type=self.invest_type) proposal_nav = get_tamp_nav(proposal, self.start_date, invest_type=self.invest_type)
# 忽略净值周期大于周更的产品 # 忽略净值周期大于周更的产品
if get_frequency(proposal_nav) <= 52: if get_frequency(proposal_nav) <= 52:
...@@ -515,7 +476,6 @@ class PortfolioDiagnose(object): ...@@ -515,7 +476,6 @@ class PortfolioDiagnose(object):
prod = pd.merge(prod, proposal_nav, how='outer', on='end_date').astype(float) prod = pd.merge(prod, proposal_nav, how='outer', on='end_date').astype(float)
prod.sort_index(inplace=True) prod.sort_index(inplace=True)
prod.ffill(inplace=True) prod.ffill(inplace=True)
prod.bfill(inplace=True)
prod = resample(prod, get_trade_cal(), min(self.freq_list)) prod = resample(prod, get_trade_cal(), min(self.freq_list))
self.new_correlation = cal_correlation(prod) self.new_correlation = cal_correlation(prod)
...@@ -550,55 +510,37 @@ class PortfolioDiagnose(object): ...@@ -550,55 +510,37 @@ class PortfolioDiagnose(object):
end3 = time.time() end3 = time.time()
print("遍历产品池获取候选推荐时间:", end3 - end2) print("遍历产品池获取候选推荐时间:", end3 - end2)
# propose_portfolio.to_csv('test_portfolio.csv', encoding='gbk') # propose_portfolio.to_csv('test_portfolio.csv', encoding='gbk')
mu = expected_returns.mean_historical_return(self.propose_portfolio, frequency=min(self.freq_list)) mu = expected_returns.mean_historical_return(self.propose_portfolio, frequency=min(self.freq_list))
S = risk_models.sample_cov(self.propose_portfolio, frequency=min(self.freq_list)) S = risk_models.sample_cov(self.propose_portfolio, frequency=min(self.freq_list))
dd = expected_returns.drawdown_from_prices(self.propose_portfolio) dd = expected_returns.drawdown_from_prices(self.propose_portfolio)
# if self.client_type == 1: # if self.client_type == 1:
# proposal_risk = [[x, get_risk_level(search_rank(fund_rank, x, metric='substrategy'))] for x in # proposal_risk = [[x, get_risk_level(search_rank(fund_rank, x, metric='substrategy'))] for x in
# self.propose_portfolio.columns] # propose_portfolio.columns]
# self.proposal_fund = list(filter(lambda x: x[1] != 'H', proposal_risk)) # self.proposal_fund = list(filter(lambda x: x[1] != 'H', proposal_risk))
# drop_fund_list = list(filter(lambda x: x[1] == 'H', proposal_risk))
# drop_fund_list = [x[0] for x in drop_fund_list] # drop_fund_list = list(filter(lambda x: x[1] = 'H', proposal_risk))
# self.propose_portfolio.drop(drop_fund_list, axis=1, inplace=True) # proposal_portfolio = list((set(self.portfolio) - set(self.no_data_fund) - set(self.replace_pair.keys())) | \
# mu = expected_returns.mean_historical_return(self.propose_portfolio, frequency=min(self.freq_list)) # (set(self.proposal_fund) | set(self.replace_pair.values())))
# S = risk_models.sample_cov(self.propose_portfolio, frequency=min(self.freq_list)) # propose_portfolio.drop()
# dd = expected_returns.drawdown_from_prices(self.propose_portfolio)
propose_risk_mapper = dict() propose_risk_mapper = dict()
for fund in self.propose_portfolio.columns: for fund in self.propose_portfolio.columns:
propose_risk_mapper[fund] = str(get_risk_level(search_rank(fund_rank, fund, metric='substrategy'))) propose_risk_mapper[fund] = str(get_risk_level(search_rank(fund_rank, fund, metric='substrategy')))
if self.client_type == 1: # risk_upper = {"H": 0.0}
risk_upper = {"H": 0.0} # risk_lower = {"L": 0.6, "M": 0.4}
risk_lower = {"L": 0.0}
elif self.client_type == 2: w_low = 1e6 / self.invest_amount
risk_upper = {"H": 0.0} ef = EfficientFrontier(mu, S, expected_drawdown=dd)
risk_lower = {"L": 0.0} # ef.add_sector_constraints(propose_risk_mapper, risk_lower, risk_upper)
elif self.client_type == 3: # weights = ef.nonconvex_objective(deviation_risk_parity, ef.cov_matrix)
risk_upper = {"H": 0.0} ef.efficient_return(0.3)
risk_lower = {"L": 0.0}
elif self.client_type == 4:
risk_upper = {"H": 0.0}
risk_lower = {"L": 0.0}
elif self.client_type == 5:
risk_upper = {"H": 0.0}
risk_lower = {"L": 0.0}
else:
risk_upper = {"H": 0.0}
risk_lower = {"L": 0.0}
raise ValueError
w_low = 1000000 / self.invest_amount
# ef = EfficientFrontier(mu, S, weight_bounds=[w_low, 1], expected_drawdown=dd)
ef = EfficientFrontier(mu, S, weight_bounds=[0, 1], expected_drawdown=dd)
ef.add_sector_constraints(propose_risk_mapper, risk_lower, risk_upper)
ef.efficient_return(target_return=self.expect_return, target_drawdown=self.expect_drawdown)
clean_weights = ef.clean_weights() clean_weights = ef.clean_weights()
# ef.portfolio_performance(verbose=True) # ef.portfolio_performance(verbose=True)
self.new_weights = np.array(list(clean_weights.values())) self.new_weights = np.array(list(clean_weights.values()))
self.new_weights[self.new_weights < w_low] = 0
print(clean_weights) print(clean_weights)
print(self.new_weights)
end4 = time.time() end4 = time.time()
print("模型计算一次时间:", end4 - end3) print("模型计算一次时间:", end4 - end3)
# S = np.asmatrix(S) # S = np.asmatrix(S)
...@@ -622,7 +564,7 @@ class PortfolioDiagnose(object): ...@@ -622,7 +564,7 @@ class PortfolioDiagnose(object):
# self.proposal_weights = calcu_w(w_origin, S, risk_target) # self.proposal_weights = calcu_w(w_origin, S, risk_target)
def return_compare(self): def return_compare(self):
index_data = get_index_daily(self.index_id, self.start_date) index_data = get_index_daily(self.index_id)
index_data = pd.merge(index_data, self.propose_portfolio, how='inner', left_index=True, right_index=True) index_data = pd.merge(index_data, self.propose_portfolio, how='inner', left_index=True, right_index=True)
index_return = index_data.iloc[:, :] / index_data.iloc[0, :] - 1 index_return = index_data.iloc[:, :] / index_data.iloc[0, :] - 1
# origin_fund_return = origin_portfolio.iloc[:, :] / origin_portfolio.iloc[0, :] - 1 # origin_fund_return = origin_portfolio.iloc[:, :] / origin_portfolio.iloc[0, :] - 1
...@@ -668,7 +610,7 @@ class PortfolioDiagnose(object): ...@@ -668,7 +610,7 @@ class PortfolioDiagnose(object):
# 正收益基金数量 # 正收益基金数量
group_hold_data = pd.DataFrame(group_result[group_name]["group_hoding_info"]) group_hold_data = pd.DataFrame(group_result[group_name]["group_hoding_info"])
profit_positive_num = group_hold_data[group_hold_data["profit"] > 0]["profit"].count() profit_positive_num = group_hold_data[group_hold_data["profit"]>0]["profit"].count()
if profit_positive_num > 0: if profit_positive_num > 0:
profit_positive_evaluate = str(profit_positive_num) + "只基金取的正收益," profit_positive_evaluate = str(profit_positive_num) + "只基金取的正收益,"
else: else:
...@@ -737,6 +679,7 @@ class PortfolioDiagnose(object): ...@@ -737,6 +679,7 @@ class PortfolioDiagnose(object):
return ret return ret
def new_evaluation(self, group_name, group_result, data_adaptor): def new_evaluation(self, group_name, group_result, data_adaptor):
group_result_data = group_result[group_name] group_result_data = group_result[group_name]
hold_info = group_result_data["group_hoding_info"] hold_info = group_result_data["group_hoding_info"]
hold_info_df = pd.DataFrame(hold_info) hold_info_df = pd.DataFrame(hold_info)
...@@ -744,7 +687,7 @@ class PortfolioDiagnose(object): ...@@ -744,7 +687,7 @@ class PortfolioDiagnose(object):
data_adaptor.user_customer_order_df["folio_name"] == group_name] data_adaptor.user_customer_order_df["folio_name"] == group_name]
group_order_start_date = pd.to_datetime(group_order_df["confirm_share_date"].min()) group_order_start_date = pd.to_datetime(group_order_df["confirm_share_date"].min())
# 原组合总市值, 区间收益, 年化收益, 波动率, 最大回撤, 夏普比率 # 原组合总市值, 区间收益, 年化收益, 波动率, 最大回撤, 夏普比率
total_asset = round(hold_info_df["market_values"].sum(), 2) total_asset = round(hold_info_df["market_values"].sum(), 2)
old_return = group_result_data["cumulative_return"] old_return = group_result_data["cumulative_return"]
old_return_ratio_year = group_result_data["return_ratio_year"] old_return_ratio_year = group_result_data["return_ratio_year"]
...@@ -767,11 +710,9 @@ class PortfolioDiagnose(object): ...@@ -767,11 +710,9 @@ class PortfolioDiagnose(object):
# 基金名称,策略分级 # 基金名称,策略分级
propose_fund_id_name_list = [propose_fund_df[propose_fund_df["fund_id"] == fund_id]["fund_name"].values[0] for propose_fund_id_name_list = [propose_fund_df[propose_fund_df["fund_id"] == fund_id]["fund_name"].values[0] for
fund_id in propose_fund_id_list] fund_id in propose_fund_id_list]
propose_fund_id_strategy_name_list = [ propose_fund_id_strategy_name_list = [dict_substrategy[int(propose_fund_df[propose_fund_df["fund_id"] == fund_id]["substrategy"].values[0])] for
dict_substrategy[int(propose_fund_df[propose_fund_df["fund_id"] == fund_id]["substrategy"].values[0])] for fund_id in propose_fund_id_list]
fund_id in propose_fund_id_list] propose_fund_asset = [round(self.new_weights[i] * total_asset, 2) for i in range(len(propose_fund_id_name_list))]
propose_fund_asset = [round(self.new_weights[i] * total_asset, 2) for i in
range(len(propose_fund_id_name_list))]
propose_info = {propose_fund_id_strategy_name_list[i]: propose_info = {propose_fund_id_strategy_name_list[i]:
{"fund_name": propose_fund_id_name_list[i], {"fund_name": propose_fund_id_name_list[i],
...@@ -813,50 +754,46 @@ class PortfolioDiagnose(object): ...@@ -813,50 +754,46 @@ class PortfolioDiagnose(object):
# 新组合累积收益df # 新组合累积收益df
propose_fund_return_limit_data = propose_fund_return[propose_fund_return.index >= group_order_start_date] propose_fund_return_limit_data = propose_fund_return[propose_fund_return.index >= group_order_start_date]
start_return = propose_fund_return_limit_data['return'].values[0] start_return = propose_fund_return_limit_data['return'].values[0]
propose_fund_return_limit_data["new_return"] = (propose_fund_return_limit_data["return"] - start_return) / ( propose_fund_return_limit_data["new_return"] = (propose_fund_return_limit_data["return"] - start_return)/(1+start_return)
1 + start_return)
# 新组合累积收益 # 新组合累积收益
new_return_ratio = propose_fund_return_limit_data["new_return"].values[-1] new_return_ratio = propose_fund_return_limit_data["new_return"].values[-1]
# 新组合区间年化收益率 # 新组合区间年化收益率
freq_max = group_order_df["freq"].max() freq_max = group_order_df["freq"].max()
n_freq = freq_days(int(freq_max)) n_freq = freq_days(int(freq_max))
new_return_ratio_year = annual_return(propose_fund_return_limit_data["new_return"].values[-1], new_return_ratio_year = annual_return(propose_fund_return_limit_data["new_return"].values[-1], propose_fund_return_limit_data, n_freq)
propose_fund_return_limit_data, n_freq)
# 新组合波动率 # 新组合波动率
new_volatility = volatility(propose_fund_return_limit_data["new_return"] + 1, n_freq) new_volatility = volatility(propose_fund_return_limit_data["new_return"]+1, n_freq)
# 新组合最大回撤 # 新组合最大回撤
new_drawdown = max_drawdown(propose_fund_return_limit_data["new_return"] + 1) new_drawdown = max_drawdown(propose_fund_return_limit_data["new_return"]+1)
# 新组合夏普比率 # 新组合夏普比率
sim = simple_return(propose_fund_return_limit_data["new_return"] + 1) sim = simple_return(propose_fund_return_limit_data["new_return"]+1)
exc = excess_return(sim, BANK_RATE, n_freq) exc = excess_return(sim, BANK_RATE, n_freq)
new_sharpe = sharpe_ratio(exc, sim, n_freq) new_sharpe = sharpe_ratio(exc, sim, n_freq)
# 指数收益 # 指数收益
index_return = index_return[index_return.index >= group_order_start_date] index_return = index_return[index_return.index >= group_order_start_date]
start_index_return = index_return["adj_nav"].values[0] start_index_return = index_return[" close"].values[0]
index_return["new_index_return"] = (index_return["adj_nav"] - start_index_return) / (1 + start_index_return) index_return["new_index_return"] = (index_return[" close"] - start_index_return) / (1 + start_index_return)
index_return_ratio = index_return["new_index_return"].values[-1] index_return_ratio = index_return["new_index_return"].values[-1]
index_return_ratio_year = annual_return(index_return["new_index_return"].values[-1], index_return_ratio_year = annual_return(index_return["new_index_return"].values[-1], index_return["new_index_return"], n_freq)
index_return["new_index_return"], n_freq) index_volatility = volatility(index_return["new_index_return"]+1, n_freq)
index_volatility = volatility(index_return["new_index_return"] + 1, n_freq) index_drawdown = max_drawdown(index_return["new_index_return"]+1)
index_drawdown = max_drawdown(index_return["new_index_return"] + 1) index_sim = simple_return(propose_fund_return_limit_data["new_return"]+1)
index_sim = simple_return(propose_fund_return_limit_data["new_return"] + 1)
index_exc = excess_return(index_sim, BANK_RATE, n_freq) index_exc = excess_return(index_sim, BANK_RATE, n_freq)
index_sharpe = sharpe_ratio(index_exc, index_sim, n_freq) index_sharpe = sharpe_ratio(index_exc, index_sim, n_freq)
# 收益对比数据 # 收益对比数据
return_compare_df = pd.merge(index_return[["new_index_return"]], old_return_df[["cum_return_ratio"]], return_compare_df = pd.merge(index_return[["new_index_return"]], old_return_df[["cum_return_ratio"]], right_index=True,
right_index=True, left_index=True)
left_index=True)
return_compare_df = pd.merge(return_compare_df, propose_fund_return_limit_data["new_return"], right_index=True, return_compare_df = pd.merge(return_compare_df, propose_fund_return_limit_data["new_return"], right_index=True,
left_index=True) left_index=True)
return_compare_df["date"] = return_compare_df.index return_compare_df["date"] = return_compare_df.index
return_compare_df["date"] = return_compare_df["date"].apply(lambda x: x.strftime("%Y-%m-%d")) return_compare_df["date"] = return_compare_df["date"].apply(lambda x: x.strftime("%Y-%m-%d"))
return_compare_df.iloc[1:-1, :]["date"] = "" return_compare_df.iloc[1:-1,:]["date"] = ""
return_compare_result = { return_compare_result = {
"new_combination": {"name": "新组合", "data": return_compare_df["new_return"].values}, "new_combination": {"name": "新组合", "data": return_compare_df["new_return"].values},
"index": {"name": "中证500", "data": return_compare_df["new_index_return"].values}, "index": {"name": "中证500", "data": return_compare_df["new_index_return"].values},
...@@ -865,20 +802,15 @@ class PortfolioDiagnose(object): ...@@ -865,20 +802,15 @@ class PortfolioDiagnose(object):
} }
# 指标对比 # 指标对比
old_indicator = {"group_name": "现有持仓组合", "return_ratio": round((old_return - 1) * 100, 2), old_indicator = {"group_name": "现有持仓组合", "return_ratio": round((old_return-1)*100, 2), "return_ratio_year": round(old_return_ratio_year*100,2),
"return_ratio_year": round(old_return_ratio_year * 100, 2), "volatility": round(old_volatility*100, 2), "max_drawdown": round(old_max_drawdown[0]*100, 2), "sharpe": round(old_sharpe, 2)}
"volatility": round(old_volatility * 100, 2), new_indicator = {"group_name": "建议优化组合", "return_ratio": round(new_return_ratio*100, 2), "return_ratio_year": round(new_return_ratio_year*100, 2),
"max_drawdown": round(old_max_drawdown[0] * 100, 2), "sharpe": round(old_sharpe, 2)} "volatility": round(new_volatility*100, 2), "max_drawdown": round(new_drawdown[0]*100, 2), "sharpe": round(new_sharpe, 2)}
new_indicator = {"group_name": "建议优化组合", "return_ratio": round(new_return_ratio * 100, 2), index_indicator = {"group_name": "中证500", "return_ratio": round(index_return_ratio*100, 2), "return_ratio_year": round(index_return_ratio_year*100, 2),
"return_ratio_year": round(new_return_ratio_year * 100, 2), "volatility": round(index_volatility*100, 2), "max_drawdown": round(index_drawdown[0]*100, 2), "sharpe": round(index_sharpe, 2)}
"volatility": round(new_volatility * 100, 2), "max_drawdown": round(new_drawdown[0] * 100, 2),
"sharpe": round(new_sharpe, 2)}
index_indicator = {"group_name": "中证500", "return_ratio": round(index_return_ratio * 100, 2),
"return_ratio_year": round(index_return_ratio_year * 100, 2),
"volatility": round(index_volatility * 100, 2),
"max_drawdown": round(index_drawdown[0] * 100, 2), "sharpe": round(index_sharpe, 2)}
indicator_compare = [new_indicator, old_indicator, index_indicator] indicator_compare = [new_indicator, old_indicator, index_indicator]
# 在保留{}的基础上,建议赎回{},并增配{}后,整体组合波动率大幅降低,最大回撤从{}降到不足{},年化收益率提升{}个点 # 在保留{}的基础上,建议赎回{},并增配{}后,整体组合波动率大幅降低,最大回撤从{}降到不足{},年化收益率提升{}个点
hold_fund = set(self.portfolio) - set(self.abandon_fund_score + self.abandon_fund_corr + self.no_data_fund) hold_fund = set(self.portfolio) - set(self.abandon_fund_score + self.abandon_fund_corr + self.no_data_fund)
hold_fund_name = [get_fund_name(x).values[0][0] for x in hold_fund] hold_fund_name = [get_fund_name(x).values[0][0] for x in hold_fund]
...@@ -928,16 +860,6 @@ class PortfolioDiagnose(object): ...@@ -928,16 +860,6 @@ class PortfolioDiagnose(object):
70 <= z_score < 80, 70 <= z_score < 80,
z_score < 70], [0, 1, 2]).item() z_score < 70], [0, 1, 2]).item()
index_return_monthly = get_index_monthly(self.index_id, self.start_date)
fund_nav = get_tamp_nav(fund_id, self.start_date, invest_type=self.invest_type)
fund_nav_monthly = fund_nav.groupby([fund_nav.index.year, fund_nav.index.month]).tail(1)
fund_nav_monthly = rename_col(fund_nav_monthly, fund_id)
fund_return_monthly = simple_return(fund_nav_monthly[fund_id].astype(float))
index_return_monthly.index = index_return_monthly.index.strftime('%Y-%m')
fund_return_monthly.index = fund_return_monthly.index.strftime('%Y-%m')
compare = pd.merge(index_return_monthly, fund_return_monthly, how='inner', left_index=True, right_index=True)
fund_win_rate = ((compare[fund_id] - compare['pct_chg']) > 0).sum()
return_rank = search_rank(fund_rank, fund_id, metric='annual_return_rank') return_rank = search_rank(fund_rank, fund_id, metric='annual_return_rank')
return_level = np.select([return_rank >= 0.8, return_level = np.select([return_rank >= 0.8,
0.7 <= return_rank < 0.8, 0.7 <= return_rank < 0.8,
...@@ -961,7 +883,7 @@ class PortfolioDiagnose(object): ...@@ -961,7 +883,7 @@ class PortfolioDiagnose(object):
sharp_rank < 0.6], [0, 1, 2]).item() sharp_rank < 0.6], [0, 1, 2]).item()
data = {1: [total_level, return_level, drawdown_level, sharp_level], data = {1: [total_level, return_level, drawdown_level, sharp_level],
2: [return_triple, str(fund_win_rate), return_bool], 2: [return_triple, "12", return_bool],
3: [drawdown_triple, drawdown_triple, format(drawdown_value, '.2%'), drawdown_triple], 3: [drawdown_triple, drawdown_triple, format(drawdown_value, '.2%'), drawdown_triple],
4: [return_bool, drawdown_bool, drawdown_bool, return_bool, drawdown_bool]} 4: [return_bool, drawdown_bool, drawdown_bool, return_bool, drawdown_bool]}
...@@ -998,7 +920,7 @@ class PortfolioDiagnose(object): ...@@ -998,7 +920,7 @@ class PortfolioDiagnose(object):
sentence = { sentence = {
1: "该基金整体表现%s,收益能力%s,回撤控制能力%s,风险收益比例%s;\n", 1: "该基金整体表现%s,收益能力%s,回撤控制能力%s,风险收益比例%s;\n",
2: "在收益方面,该基金年化收益能力%s同类基金平均水平,有%s区间跑赢指数,绝对收益能力%s;\n", 2: "在收益方面,该基金年化收益能力%s同类基金平均水平,有%s区间跑赢指数,绝对收益能力%s;\n",
3: "在风险方面,该基金抵御风险能力%s,在同类基金中处于%s等水平,最大回撤为%s,%s同类基金平均水平;\n", 3: "在风险方面,该基金抵御风险能力%s,在同类基金中处于%s等水平,最大回撤为%s,%s同类基金平均水平;\n",
4: "该基金收益%s的同时回撤%s,也就是说,该基金在用%s风险换取%s收益,存在%s风险;\n", 4: "该基金收益%s的同时回撤%s,也就是说,该基金在用%s风险换取%s收益,存在%s风险;\n",
5: "基金经理,投资年限%s年,经验丰富;投资能力较强,生涯中共管理过%s只基金,历任的%s只基金平均业绩在同类中处于上游水平,其中%s只排名在前%s;生涯年化回报率%s,同期大盘只有%s;"} 5: "基金经理,投资年限%s年,经验丰富;投资能力较强,生涯中共管理过%s只基金,历任的%s只基金平均业绩在同类中处于上游水平,其中%s只排名在前%s;生涯年化回报率%s,同期大盘只有%s;"}
...@@ -1020,14 +942,6 @@ class PortfolioDiagnose(object): ...@@ -1020,14 +942,6 @@ class PortfolioDiagnose(object):
ret.append(single_sentence) ret.append(single_sentence)
i += 1 i += 1
fund_name = get_fund_name(fund_id).values[0][0] fund_name = get_fund_name(fund_id).values[0][0]
if not ret:
try:
default_evaluation = pd.read_csv("evaluation.csv", encoding='utf-8', names=['fund_id', 'eval'])
ret.append('1、' + default_evaluation[default_evaluation['fund_id'] == fund_id]['eval'].values[0])
except Exception:
pass
evaluation_dict = {'name': fund_name, 'data': ret} evaluation_dict = {'name': fund_name, 'data': ret}
if fund_id in self.abandon_fund_score + self.abandon_fund_corr: if fund_id in self.abandon_fund_score + self.abandon_fund_corr:
evaluation_dict['status'] = "换仓" evaluation_dict['status'] = "换仓"
...@@ -1076,4 +990,4 @@ if __name__ == '__main__': ...@@ -1076,4 +990,4 @@ if __name__ == '__main__':
print('旧组合相关性:', portfolio_diagnose.old_correlation) print('旧组合相关性:', portfolio_diagnose.old_correlation)
print('新组合相关性:', portfolio_diagnose.new_correlation) print('新组合相关性:', portfolio_diagnose.new_correlation)
print('旧组合个基评价:', portfolio_diagnose.old_portfolio_evaluation()) print('旧组合个基评价:', portfolio_diagnose.old_portfolio_evaluation())
print('新组合个基评价:', portfolio_diagnose.propose_fund_evaluation()) print('新组合个基评价:', portfolio_diagnose.propose_fund_evaluation())
\ No newline at end of file
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