Commit ac64e3d0 authored by pengxiong's avatar pengxiong

Merge branch 'dev' of http://47.100.44.39:10001/pengxiong/fund_report into dev

parents be101748 06ecd2b6
...@@ -648,9 +648,9 @@ class PortfolioDiagnose(object): ...@@ -648,9 +648,9 @@ class PortfolioDiagnose(object):
def old_evaluation(self, group_name, group_result, data_adaptor): def old_evaluation(self, group_name, group_result, data_adaptor):
start_year = data_adaptor.start_date.year start_year = data_adaptor.start_date.year
start_month = data_adaptor.start_date.month start_month = data_adaptor.start_date.month
current_year = datetime.datetime.now().year current_year = data_adaptor.end_date.year
current_month = datetime.datetime.now().month current_month = data_adaptor.end_date.month
current_day = datetime.datetime.now().day current_day = data_adaptor.end_date.day
past_month = (current_year - start_year) * 12 + current_month - start_month past_month = (current_year - start_year) * 12 + current_month - start_month
# 投入成本(万元) # 投入成本(万元)
...@@ -755,162 +755,165 @@ class PortfolioDiagnose(object): ...@@ -755,162 +755,165 @@ 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):
try:
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)
group_order_df = data_adaptor.user_customer_order_df[ group_order_df = data_adaptor.user_customer_order_df[
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"]
old_volatility = group_result_data["volatility"] old_volatility = group_result_data["volatility"]
old_max_drawdown = group_result_data["max_drawdown"] old_max_drawdown = group_result_data["max_drawdown"]
old_sharpe = group_result_data["sharpe"] old_sharpe = group_result_data["sharpe"]
# 建议基金数据 # 建议基金数据
index_return, propose_fund_return = self.return_compare() index_return, propose_fund_return = self.return_compare()
propose_fund_id_list = list(propose_fund_return.columns) propose_fund_id_list = list(propose_fund_return.columns)
propose_fund_id_list.remove("return") propose_fund_id_list.remove("return")
with TAMP_SQL(tamp_product_engine) as tamp_product: with TAMP_SQL(tamp_product_engine) as tamp_product:
tamp_product_session = tamp_product.session tamp_product_session = tamp_product.session
sql_product = "select distinct `id`, `fund_short_name`, `nav_frequency`, `substrategy` from `fund_info`" sql_product = "select distinct `id`, `fund_short_name`, `nav_frequency`, `substrategy` from `fund_info`"
cur = tamp_product_session.execute(sql_product) cur = tamp_product_session.execute(sql_product)
data = cur.fetchall() data = cur.fetchall()
product_df = pd.DataFrame(list(data), columns=['fund_id', 'fund_name', 'freq', 'substrategy']) product_df = pd.DataFrame(list(data), columns=['fund_id', 'fund_name', 'freq', 'substrategy'])
propose_fund_df = product_df[product_df["fund_id"].isin(propose_fund_id_list)] propose_fund_df = product_df[product_df["fund_id"].isin(propose_fund_id_list)]
# 基金名称,策略分级 # 基金名称,策略分级
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 = [dict_substrategy[int(propose_fund_df[propose_fund_df["fund_id"] == fund_id]["substrategy"].values[0])] for propose_fund_id_strategy_name_list = [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],
"substrategy": propose_fund_id_strategy_name_list[i], "substrategy": propose_fund_id_strategy_name_list[i],
"asset": propose_fund_asset[i]} "asset": propose_fund_asset[i]}
for i in range(len(propose_fund_id_list))} for i in range(len(propose_fund_id_list))}
# 调仓建议 # 调仓建议
suggestions_result = {} suggestions_result = {}
old_hold_fund_name_list = list(hold_info_df["fund_name"]) old_hold_fund_name_list = list(hold_info_df["fund_name"])
for hold in hold_info: for hold in hold_info:
suggestions = {}
if hold["fund_strategy_name"] not in suggestions_result.keys():
suggestions_result[hold["fund_strategy_name"]] = {}
suggestions["fund_strategy_name"] = hold["fund_strategy_name"]
suggestions["fund_name"] = hold["fund_name"]
suggestions["before_optimization"] = hold["market_values"]
suggestions["after_optimization"] = 0
if suggestions["fund_strategy_name"] in propose_fund_id_strategy_name_list:
suggestions["after_optimization"] = 0
suggestions_result[hold["fund_strategy_name"]][suggestions["fund_name"]] = suggestions
for key, value in propose_info.items():
if value["fund_name"] not in old_hold_fund_name_list:
suggestions = {} suggestions = {}
if key not in suggestions_result.keys(): if hold["fund_strategy_name"] not in suggestions_result.keys():
suggestions_result[key] = {} suggestions_result[hold["fund_strategy_name"]] = {}
suggestions["fund_strategy_name"] = value["substrategy"] suggestions["fund_strategy_name"] = hold["fund_strategy_name"]
suggestions["fund_name"] = value["fund_name"] suggestions["fund_name"] = hold["fund_name"]
suggestions["before_optimization"] = 0 suggestions["before_optimization"] = hold["market_values"]
suggestions["after_optimization"] = value["asset"] suggestions["after_optimization"] = 0
suggestions_result[key][suggestions["fund_name"]] = suggestions if suggestions["fund_strategy_name"] in propose_fund_id_strategy_name_list:
for key, value in suggestions_result.items(): suggestions["after_optimization"] = 0
suggestions_result[key] = list(value.values()) suggestions_result[hold["fund_strategy_name"]][suggestions["fund_name"]] = suggestions
suggestions_result_asset = {"before": total_asset, "after": total_asset}
for key, value in propose_info.items():
# 旧组合累积收益df if value["fund_name"] not in old_hold_fund_name_list:
old_return_df = group_result_data["return_df"] suggestions = {}
old_return_df["cum_return_ratio"] = old_return_df["cum_return_ratio"] - 1 if key not in suggestions_result.keys():
# 新组合累积收益df suggestions_result[key] = {}
propose_fund_return_limit_data = propose_fund_return[propose_fund_return.index >= group_order_start_date] suggestions["fund_strategy_name"] = value["substrategy"]
start_return = propose_fund_return_limit_data['return'].values[0] suggestions["fund_name"] = value["fund_name"]
propose_fund_return_limit_data["new_return"] = (propose_fund_return_limit_data["return"] - start_return)/(1+start_return) suggestions["before_optimization"] = 0
suggestions["after_optimization"] = value["asset"]
# 新组合累积收益 suggestions_result[key][suggestions["fund_name"]] = suggestions
new_return_ratio = propose_fund_return_limit_data["new_return"].values[-1] for key, value in suggestions_result.items():
# 新组合区间年化收益率 suggestions_result[key] = list(value.values())
freq_max = group_order_df["freq"].max() suggestions_result_asset = {"before": total_asset, "after": total_asset}
n_freq = freq_days(int(freq_max))
new_return_ratio_year = annual_return(propose_fund_return_limit_data["new_return"].values[-1], propose_fund_return_limit_data, n_freq) # 旧组合累积收益df
old_return_df = group_result_data["return_df"]
# 新组合波动率 old_return_df["cum_return_ratio"] = old_return_df["cum_return_ratio"] - 1
new_volatility = volatility(propose_fund_return_limit_data["new_return"]+1, n_freq) # 新组合累积收益df
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]
new_drawdown = max_drawdown(propose_fund_return_limit_data["new_return"]+1) propose_fund_return_limit_data["new_return"] = (propose_fund_return_limit_data["return"] - start_return)/(1+start_return)
# 新组合夏普比率 # 新组合累积收益
sim = simple_return(propose_fund_return_limit_data["new_return"]+1) new_return_ratio = propose_fund_return_limit_data["new_return"].values[-1]
exc = excess_return(sim, BANK_RATE, n_freq) # 新组合区间年化收益率
new_sharpe = sharpe_ratio(exc, sim, n_freq) freq_max = group_order_df["freq"].max()
n_freq = freq_days(int(freq_max))
# 指数收益 new_return_ratio_year = annual_return(propose_fund_return_limit_data["new_return"].values[-1], propose_fund_return_limit_data, n_freq)
index_return = index_return[index_return.index >= group_order_start_date]
start_index_return = index_return[" close"].values[0] # 新组合波动率
index_return["new_index_return"] = (index_return[" close"] - start_index_return) / (1 + start_index_return) new_volatility = volatility(propose_fund_return_limit_data["new_return"]+1, n_freq)
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["new_index_return"], n_freq) # 新组合最大回撤
index_volatility = volatility(index_return["new_index_return"]+1, n_freq) new_drawdown = max_drawdown(propose_fund_return_limit_data["new_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_exc = excess_return(index_sim, BANK_RATE, n_freq) sim = simple_return(propose_fund_return_limit_data["new_return"]+1)
index_sharpe = sharpe_ratio(index_exc, index_sim, n_freq) exc = excess_return(sim, BANK_RATE, n_freq)
new_sharpe = sharpe_ratio(exc, sim, n_freq)
# 收益对比数据
return_compare_df = pd.merge(index_return[["new_index_return"]], old_return_df[["cum_return_ratio"]], right_index=True, # 指数收益
left_index=True) index_return = index_return[index_return.index >= group_order_start_date]
return_compare_df = pd.merge(return_compare_df, propose_fund_return_limit_data["new_return"], right_index=True, start_index_return = index_return[" close"].values[0]
left_index=True) index_return["new_index_return"] = (index_return[" close"] - start_index_return) / (1 + start_index_return)
return_compare_df["date"] = return_compare_df.index index_return_ratio = index_return["new_index_return"].values[-1]
return_compare_df["date"] = return_compare_df["date"].apply(lambda x: x.strftime("%Y-%m-%d")) index_return_ratio_year = annual_return(index_return["new_index_return"].values[-1], index_return["new_index_return"], n_freq)
return_compare_df.iloc[1:-1,:]["date"] = "" index_volatility = volatility(index_return["new_index_return"]+1, n_freq)
return_compare_result = { index_drawdown = max_drawdown(index_return["new_index_return"]+1)
"new_combination": {"name": "新组合", "data": return_compare_df["new_return"].values}, index_sim = simple_return(propose_fund_return_limit_data["new_return"]+1)
"index": {"name": "中证500", "data": return_compare_df["new_index_return"].values}, index_exc = excess_return(index_sim, BANK_RATE, n_freq)
"origin_combination": {"name": "原组合", "data": return_compare_df["cum_return_ratio"].values}, index_sharpe = sharpe_ratio(index_exc, index_sim, n_freq)
"xlabels": return_compare_df["date"].values
} # 收益对比数据
return_compare_df = pd.merge(index_return[["new_index_return"]], old_return_df[["cum_return_ratio"]], right_index=True,
# 指标对比 left_index=True)
old_indicator = {"group_name": "现有持仓组合", "return_ratio": round((old_return-1)*100, 2), "return_ratio_year": round(old_return_ratio_year*100,2), return_compare_df = pd.merge(return_compare_df, propose_fund_return_limit_data["new_return"], right_index=True,
"volatility": round(old_volatility*100, 2), "max_drawdown": round(old_max_drawdown[0]*100, 2), "sharpe": round(old_sharpe, 2)} left_index=True)
new_indicator = {"group_name": "建议优化组合", "return_ratio": round(new_return_ratio*100, 2), "return_ratio_year": round(new_return_ratio_year*100, 2), return_compare_df["date"] = return_compare_df.index
"volatility": round(new_volatility*100, 2), "max_drawdown": round(new_drawdown[0]*100, 2), "sharpe": round(new_sharpe, 2)} return_compare_df["date"] = return_compare_df["date"].apply(lambda x: x.strftime("%Y-%m-%d"))
index_indicator = {"group_name": "中证500", "return_ratio": round(index_return_ratio*100, 2), "return_ratio_year": round(index_return_ratio_year*100, 2), return_compare_df.iloc[1:-1,:]["date"] = ""
"volatility": round(index_volatility*100, 2), "max_drawdown": round(index_drawdown[0]*100, 2), "sharpe": round(index_sharpe, 2)} return_compare_result = {
indicator_compare = [new_indicator, old_indicator, index_indicator] "new_combination": {"name": "新组合", "data": return_compare_df["new_return"].values},
"index": {"name": "中证500", "data": return_compare_df["new_index_return"].values},
"origin_combination": {"name": "原组合", "data": return_compare_df["cum_return_ratio"].values},
# 在保留{}的基础上,建议赎回{},并增配{}后,整体组合波动率大幅降低,最大回撤从{}降到不足{},年化收益率提升{}个点 "xlabels": return_compare_df["date"].values
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]
abandon_fund = (self.abandon_fund_score + self.abandon_fund_corr) # 指标对比
abandon_fund_name = [get_fund_name(x).values[0][0] for x in abandon_fund] old_indicator = {"group_name": "现有持仓组合", "return_ratio": round((old_return-1)*100, 2), "return_ratio_year": round(old_return_ratio_year*100,2),
proposal_fund = self.proposal_fund "volatility": round(old_volatility*100, 2), "max_drawdown": round(old_max_drawdown[0]*100, 2), "sharpe": round(old_sharpe, 2)}
proposal_fund_name = [get_fund_name(x).values[0][0] for x in proposal_fund] new_indicator = {"group_name": "建议优化组合", "return_ratio": round(new_return_ratio*100, 2), "return_ratio_year": round(new_return_ratio_year*100, 2),
"volatility": round(new_volatility*100, 2), "max_drawdown": round(new_drawdown[0]*100, 2), "sharpe": round(new_sharpe, 2)}
sentence = [] index_indicator = {"group_name": "中证500", "return_ratio": round(index_return_ratio*100, 2), "return_ratio_year": round(index_return_ratio_year*100, 2),
if hold_fund is not None: "volatility": round(index_volatility*100, 2), "max_drawdown": round(index_drawdown[0]*100, 2), "sharpe": round(index_sharpe, 2)}
sentence.append("在保留" + "".join([i + "," for i in hold_fund_name]).rstrip(",") + "的基础上") indicator_compare = [new_indicator, old_indicator, index_indicator]
if abandon_fund is not None:
sentence.append("建议赎回" + "".join([i + "," for i in abandon_fund_name]).rstrip(","))
if proposal_fund is not None: # 在保留{}的基础上,建议赎回{},并增配{}后,整体组合波动率大幅降低,最大回撤从{}降到不足{},年化收益率提升{}个点
sentence.append("增配" + "".join([i + "," for i in proposal_fund_name]).rstrip(",") + "后") hold_fund = set(self.portfolio) - set(self.abandon_fund_score + self.abandon_fund_corr + self.no_data_fund)
if new_volatility < old_volatility * 0.9: hold_fund_name = [get_fund_name(x).values[0][0] for x in hold_fund]
sentence.append("整体组合波动率大幅降低") abandon_fund = (self.abandon_fund_score + self.abandon_fund_corr)
if new_drawdown < old_max_drawdown: abandon_fund_name = [get_fund_name(x).values[0][0] for x in abandon_fund]
sentence.append("最大回撤从{:.2%}降到不足{:.2%}".format(old_max_drawdown[0], new_drawdown[0])) proposal_fund = self.proposal_fund
if new_return_ratio_year > old_return_ratio_year: proposal_fund_name = [get_fund_name(x).values[0][0] for x in proposal_fund]
sentence.append("年化收益率提升{:.2f}个点".format((new_return_ratio_year - old_return_ratio_year) * 100))
sentence = []
whole_sentence = ",".join(sentence).lstrip(",") + "。" if hold_fund is not None:
return suggestions_result, suggestions_result_asset, return_compare_result, indicator_compare, whole_sentence sentence.append("在保留" + "".join([i + "," for i in hold_fund_name]).rstrip(",") + "的基础上")
if abandon_fund is not None:
sentence.append("建议赎回" + "".join([i + "," for i in abandon_fund_name]).rstrip(","))
if proposal_fund is not None:
sentence.append("增配" + "".join([i + "," for i in proposal_fund_name]).rstrip(",") + "后")
if new_volatility < old_volatility * 0.9:
sentence.append("整体组合波动率大幅降低")
if new_drawdown < old_max_drawdown:
sentence.append("最大回撤从{:.2%}降到不足{:.2%}".format(old_max_drawdown[0], new_drawdown[0]))
if new_return_ratio_year > old_return_ratio_year:
sentence.append("年化收益率提升{:.2f}个点".format((new_return_ratio_year - old_return_ratio_year) * 100))
whole_sentence = ",".join(sentence).lstrip(",") + "。"
return suggestions_result, suggestions_result_asset, return_compare_result, indicator_compare, whole_sentence
except Exception as e:
repr(e)
return None
def single_evaluation(self, fund_id): def single_evaluation(self, fund_id):
""" """
...@@ -1044,19 +1047,29 @@ class PortfolioDiagnose(object): ...@@ -1044,19 +1047,29 @@ class PortfolioDiagnose(object):
return evaluation_dict return evaluation_dict
def old_portfolio_evaluation(self, ): def old_portfolio_evaluation(self, ):
result = [] try:
for fund in self.portfolio: result = []
try: for fund in self.portfolio:
result.append(self.single_evaluation(fund)) try:
except IndexError: result.append(self.single_evaluation(fund))
continue except IndexError:
return result continue
return result
except Exception as e:
repr(e)
return None
def propose_fund_evaluation(self, ): def propose_fund_evaluation(self, ):
result = [] try:
for fund in self.proposal_fund: result = []
result.append(self.single_evaluation(fund)) for fund in self.proposal_fund:
return result result.append(self.single_evaluation(fund))
return result
except Exception as e:
repr(e)
return None
def single_fund_radar(self): def single_fund_radar(self):
radar_data = [] radar_data = []
......
...@@ -1559,21 +1559,21 @@ ...@@ -1559,21 +1559,21 @@
<th>基金简称</th> <th>基金简称</th>
<th>买入时间</th> <th>买入时间</th>
<th>存续年数</th> <th>存续年数</th>
<th>投资本金 (万元</th> <th>投资本金 (万元)</th>
<th>当月收益</th> <th>当月收益 (万元)</th>
<th>当月收益率</th> <th>当月收益率 (%)</th>
<th>月末市值 (万元</th> <th>月末市值 (万元)</th>
<th>月末占比</th> <th>月末占比 (%)</th>
<th>累计收益</th> <th>累计收益 (万元)</th>
<th>累计收益率</th> <th>累计收益率 (%)</th>
<th>年化收益率</th> <th>年化收益率 (%)</th>
</tr> </tr>
{% for one in group_hoding_info %} {% for one in group_hoding_info %}
<tr> <tr>
<td rowspan="1">{{one.fund_strategy_name}}</td> <td rowspan="1">{{one.fund_strategy_name}}</td>
<td>{{one.fund_name}}</td> <td>{{one.fund_name}}</td>
<td class="text_red">{{one.confirm_date}}</td> <td>{{one.confirm_date}}</td>
<td class="text_green">{{one.hold_year}}</td> <td>{{one.hold_year}}</td>
<td>{{one.cost}}</td> <td>{{one.cost}}</td>
<td>{{one.profit}}</td> <td>{{one.profit}}</td>
<td>{{one.month_return_ratio}}</td> <td>{{one.month_return_ratio}}</td>
...@@ -1590,7 +1590,7 @@ ...@@ -1590,7 +1590,7 @@
<td>{{group_hoding_info_total["cur_month_profit"]}}</td> <td>{{group_hoding_info_total["cur_month_profit"]}}</td>
<td>{{group_hoding_info_total["cur_month_profit_ratio"]}}</td> <td>{{group_hoding_info_total["cur_month_profit_ratio"]}}</td>
<td>{{group_hoding_info_total["ending_assets"]}}</td> <td>{{group_hoding_info_total["ending_assets"]}}</td>
<td>100</td> <td>100%</td>
<td>{{group_hoding_info_total["cumulative_profit"]}}</td> <td>{{group_hoding_info_total["cumulative_profit"]}}</td>
<td>{{group_hoding_info_total["cumulative_return"]}}</td> <td>{{group_hoding_info_total["cumulative_return"]}}</td>
<td>{{group_hoding_info_total["return_ratio_year"]}}</td> <td>{{group_hoding_info_total["return_ratio_year"]}}</td>
......
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