#!/usr/bin/python3.6 # -*- coding: utf-8 -*- # @Time : 2020/11/23 15:29 # @Author : Jie. Z # @Email : zhaojiestudy@163.com # @File : result_service.py # @Software: PyCharm import pandas as pd import numpy as np import datetime from decimal import Decimal from app.service.data_service_v2_1 import UserCustomerDataAdaptor from app.utils.fund_rank import get_frequency from app.utils.week_evaluation import * class UserCustomerResultAdaptor(UserCustomerDataAdaptor): total_result_data = {} group_result_data = {} def __init__(self, user_id, customer_id, end_date=str(datetime.date.today())): super().__init__(user_id, customer_id, end_date) # 组合结果数据 def calculate_group_result_data(self): for folio in self.group_data.keys(): folio_report_data = {} cur_folio_result_cnav_data = self.group_data[folio]["result_cnav_data"] cur_folio_order_data = self.group_data[folio]["order_df"].copy() # freq_max = cur_folio_order_data["freq"].max() freq_list = [get_frequency(cur_folio_result_cnav_data[[p_nav]]) for p_nav in cur_folio_result_cnav_data.columns] freq_dict = {250: 1, 52: 2, 24: 4, 12: 3, 4: 5} freq_max = freq_dict[min(freq_list)] first_trade_date = cur_folio_order_data["confirm_share_date"].min() fund_id_list = list(cur_folio_order_data["fund_id"].unique()) fund_id_list_earn = [i + "_earn" for i in fund_id_list] # fund_id_list_amount = [i + "_amount" for i in fund_id_list] profit_df = cur_folio_result_cnav_data[fund_id_list_earn] folio_report_data["fund_id_list"] = fund_id_list # 组合收益率数组 # return_ratio_df, contribution_decomposition= self.combination_yield(cur_folio_result_cnav_data, fund_id_list) # resample_df = resample(return_ratio_df, self.trade_cal_date, freq_max) resample_cur_folio_result_cnav_data = resample(cur_folio_result_cnav_data, self.trade_cal_date, freq_max) if resample_cur_folio_result_cnav_data.index.values[-1] > self.end_date: last = resample_cur_folio_result_cnav_data.index.values[-1] resample_cur_folio_result_cnav_data["index_date"] = resample_cur_folio_result_cnav_data.index resample_cur_folio_result_cnav_data.loc[last, "index_date"] = self.end_date resample_cur_folio_result_cnav_data.set_index("index_date", inplace=True) resample_cur_folio_result_cnav_data = resample_cur_folio_result_cnav_data[resample_cur_folio_result_cnav_data.index <= self.end_date] return_ratio_df, month_return_ratio_df, contribution_decomposition = self.combination_yield(resample_cur_folio_result_cnav_data, fund_id_list) resample_df = resample(return_ratio_df, self.trade_cal_date, freq_max) resample_df = resample_df[resample_df.index <= self.end_date] # 收益分解df contribution_decomposition_df = contribution_decomposition.fillna(0)*100 p_plot_data = [] for a_fund_id in list(contribution_decomposition_df.columns): a_name = cur_folio_order_data[cur_folio_order_data["fund_id"]==a_fund_id]["fund_name"].values[0] plot_data = {'name': a_name, 'data': contribution_decomposition_df[a_fund_id].astype(np.float64).values} p_plot_data.append(plot_data) x_lables_data = list(contribution_decomposition_df.index) cumulative_data = {'name': '总收益', 'data': ((month_return_ratio_df["cum_return_ratio"] - 1)*100).values} folio_report_data["contribution_decomposition"] = {"xlabels": x_lables_data, "product_list": p_plot_data, "cumulative": cumulative_data} # 总成本 total_cost = round(float((cur_folio_order_data[cur_folio_order_data["order_type"] == 1]["confirm_share"]*cur_folio_order_data[cur_folio_order_data["order_type"] == 1]["nav"]).sum()), 2) folio_report_data["total_cost"] = total_cost # 累积盈利 cumulative_profit = profit_df.sum().sum() folio_report_data["cumulative_profit"] = float(cumulative_profit) # 区间年化收益率 n_freq = freq_days(int(freq_max)) return_ratio_year = annual_return((resample_df["cum_return_ratio"].values[-1]-1), resample_df, n_freq) folio_report_data["return_ratio_year"] = float(return_ratio_year) # 波动率 volatility_ = volatility(resample_df["cum_return_ratio"], n_freq) folio_report_data["volatility"] = float(volatility_) # 最大回撤 drawdown = max_drawdown(resample_df["cum_return_ratio"]) folio_report_data["max_drawdown"] = drawdown # 夏普比率 sim = simple_return(resample_df["cum_return_ratio"]) exc = excess_return(sim, BANK_RATE, n_freq) try: sharpe = sharpe_ratio(exc, sim, n_freq) except ZeroDivisionError: sharpe = 0.0 folio_report_data["sharpe"] = float(sharpe) # 期末资产 ending_assets = cumulative_profit + total_cost folio_report_data["ending_assets"] = float(ending_assets) # 本月收益 cur_month_profit_df = profit_df.loc[self.month_start_date:self.end_date+datetime.timedelta(days=1), fund_id_list_earn] cur_month_profit = cur_month_profit_df.sum().sum() folio_report_data["cur_month_profit"] = float(cur_month_profit) # 本月累积收益率 last_profit_ratio = return_ratio_df.loc[:self.month_start_date, "cum_return_ratio"].values cur_profit_ratio = return_ratio_df.loc[self.month_start_date - datetime.timedelta(days=1):, "cum_return_ratio"].values if len(last_profit_ratio) <= 0: cur_month_profit_ratio = cur_profit_ratio[-1] - 1 else: cur_month_profit_ratio = (cur_profit_ratio[-1] - last_profit_ratio[-1]) / last_profit_ratio[-1] folio_report_data["cur_month_profit_ratio"] = float(cur_month_profit_ratio) # 今年累积收益 cur_year_date = pd.to_datetime(str(datetime.date(year=self.end_date.year, month=1, day=1))) cur_year_profit_df = profit_df.loc[cur_year_date:self.end_date + datetime.timedelta(days=1), fund_id_list_earn] cur_year_profit = cur_year_profit_df.sum().sum() folio_report_data["cur_year_profit"] = float(cur_year_profit) # 今年累积收益率 last_profit_ratio = return_ratio_df.loc[:cur_year_date, "cum_return_ratio"].values cur_profit_ratio = return_ratio_df.loc[cur_year_date:, "cum_return_ratio"].values if len(last_profit_ratio) <= 0: cur_year_profit_ratio = cur_profit_ratio[-1] - 1 else: cur_year_profit_ratio = (cur_profit_ratio[-1] - last_profit_ratio[-1]) / last_profit_ratio[-1] folio_report_data["cur_year_profit_ratio"] = float(cur_year_profit_ratio) # 累积收益率 cumulative_return= return_ratio_df["cum_return_ratio"].values[-1] folio_report_data["cumulative_return"] = float(cumulative_return) # 月度分组 def year_month(x): a = x.year b = x.month return str(a) + "/" + str(b) profit_df_cp = profit_df.copy() profit_df_cp["date"] = profit_df_cp.index grouped = profit_df_cp.groupby(profit_df_cp["date"].apply(year_month)) sum_group = grouped.agg(np.sum) month_sum = sum_group.sum(axis=1) # 贡献分解 month_earn = sum_group.div(month_sum, axis='rows') month_earn["datetime"] = pd.to_datetime(month_earn.index) month_earn.sort_values(by="datetime", inplace=True) del month_earn["datetime"] col = list(month_earn.columns) col_ = {x: x.replace('_earn', '') for x in list(col)} month_earn.rename(columns=col_, inplace=True) # folio_report_data["contribution_decomposition"] = month_earn # 组合内单个基金净值数据 组合内基金持仓数据 result_fund_nav_info, result_fund_hoding_info = self.group_fund_basic_info_data(cur_folio_order_data, cur_folio_result_cnav_data, cumulative_profit, total_cost) # 拼接组合以及综合结果数据 folio_report_data["group_nav_info"] = result_fund_nav_info folio_report_data["group_hoding_info"] = result_fund_hoding_info folio_report_data["group_hoding_info_total"] = \ {"total_cost": "%.2f" % round(float(total_cost)/10000.0, 2), "cur_month_profit": "%.2f" % round(cur_month_profit/10000.0, 2), "cur_month_profit_ratio": "%.2f" % round(cur_month_profit_ratio*100, 2), "ending_assets": "%.2f" % round(ending_assets/10000.0, 2), "weight": 100, "cumulative_profit": "%.2f" % round(cumulative_profit/10000.0, 2), "cumulative_return": "%.2f" % round((cumulative_return-1)*100, 2), "return_ratio_year": "%.2f" % round(return_ratio_year*100, 2)} # 对应指数数据 index_df = self.get_customer_index_nav_data() index_result = self.signal_fund_profit_result(index_df[index_df.index >= pd.to_datetime(first_trade_date)], "index") folio_report_data["index_result"] = index_result folio_report_data["return_df"] = resample_df self.group_result_data[folio] = folio_report_data return self.group_result_data # 综述数据 def calculate_total_data(self): report_data = {} cur_folio_result_cnav_data = self.total_customer_order_cnav_df.copy() cur_folio_order_data = self.user_customer_order_df.copy() # freq_max = cur_folio_order_data["freq"].max() freq_list = [get_frequency(cur_folio_result_cnav_data[[p_nav]]) for p_nav in cur_folio_result_cnav_data.columns] freq_dict = {250: 1, 52: 2, 24: 4, 12: 3, 4: 5} freq_max = freq_dict[min(freq_list)] # fund_id_list = list(cur_folio_order_data["fund_id"].unique()) fund_id_list_earn = [i + "_earn" for i in fund_id_list] fund_id_list_amount = [i + "_net_amount" for i in fund_id_list] profit_df = cur_folio_result_cnav_data[fund_id_list_earn] amount_df = cur_folio_result_cnav_data[fund_id_list_amount].copy() # 持仓周期 first_trade_date = cur_folio_order_data["confirm_share_date"].min() hold_days = (self.end_date - pd.to_datetime(first_trade_date)).days report_data["hold_days"] = hold_days # 组合收益率数组 # return_ratio_df = self.combination_yield(cur_folio_result_cnav_data, fund_id_list) # resample_df = resample(return_ratio_df, self.trade_cal_date, freq_max) resample_cur_folio_result_cnav_data = resample(cur_folio_result_cnav_data, self.trade_cal_date, freq_max) if resample_cur_folio_result_cnav_data.index.values[-1] > self.end_date: last = resample_cur_folio_result_cnav_data.index.values[-1] resample_cur_folio_result_cnav_data["index_date"] = resample_cur_folio_result_cnav_data.index resample_cur_folio_result_cnav_data.loc[last, "index_date"] = self.end_date resample_cur_folio_result_cnav_data.set_index("index_date", inplace=True) resample_cur_folio_result_cnav_data = resample_cur_folio_result_cnav_data[resample_cur_folio_result_cnav_data.index <=self.end_date] return_ratio_df, month_return_ratio_df, contribution_decomposition = self.combination_yield(resample_cur_folio_result_cnav_data, fund_id_list) resample_df = resample(return_ratio_df, self.trade_cal_date, freq_max) resample_df = resample_df[resample_df.index <= self.end_date] # 总成本 total_cost = round(float((cur_folio_order_data[cur_folio_order_data["order_type"] == 1]["confirm_share"]*cur_folio_order_data[cur_folio_order_data["order_type"] == 1]["nav"]).sum()), 2) report_data["total_cost"] = total_cost # 累积盈利 cumulative_profit = profit_df.sum().sum() report_data["cumulative_profit"] = float(cumulative_profit) # 区间年化收益 n_freq = freq_days(int(freq_max)) return_ratio_year = annual_return((resample_df["cum_return_ratio"].values[-1] - 1), resample_df, n_freq) report_data["return_ratio_year"] = float(return_ratio_year) # # 波动率 # volatility_ = volatility(resample_df["cum_return_ratio"], n_freq) # report_data["volatility"] = float(volatility_) # 最大回撤 drawdown = max_drawdown(resample_df["cum_return_ratio"]) report_data["max_drawdown"] = drawdown # # # 夏普比率 # sim = simple_return(resample_df["cum_return_ratio"]) # exc = excess_return(sim, BANK_RATE, n_freq) # sharpe = sharpe_ratio(exc, sim, n_freq) # report_data["sharpe"] = float(sharpe) # 期末资产 ending_assets = cumulative_profit + total_cost report_data["ending_assets"] = float(ending_assets) # 本月收益 cur_month_profit_df = profit_df.loc[self.month_start_date:self.end_date + datetime.timedelta(days=1), fund_id_list_earn] cur_month_profit = cur_month_profit_df.sum().sum() report_data["cur_month_profit"] = float(cur_month_profit) # 本月累积收益率 last_profit_ratio = return_ratio_df.loc[:self.month_start_date, "cum_return_ratio"].values cur_profit_ratio = return_ratio_df.loc[self.month_start_date:, "cum_return_ratio"].values if len(last_profit_ratio) <= 0: cur_month_profit_ratio = cur_profit_ratio[-1] - 1 else: cur_month_profit_ratio = (cur_profit_ratio[-1] - last_profit_ratio[-1]) / last_profit_ratio[-1] report_data["cur_month_profit_ratio"] = float(cur_month_profit_ratio) # 今年累积收益 cur_year_date = pd.to_datetime(str(datetime.date(year=self.end_date.year, month=1, day=1))) cur_year_profit_df = profit_df.loc[cur_year_date:self.end_date + datetime.timedelta(days=1), fund_id_list_earn] cur_year_profit = cur_year_profit_df.sum().sum() report_data["cur_year_profit"] = float(cur_year_profit) # 今年累积收益率 last_profit_ratio = return_ratio_df.loc[:cur_year_date, "cum_return_ratio"].values cur_profit_ratio = return_ratio_df.loc[cur_year_date:, "cum_return_ratio"].values if len(last_profit_ratio) <= 0: cur_year_profit_ratio = cur_profit_ratio[-1] - 1 else: cur_year_profit_ratio = (cur_profit_ratio[-1] - last_profit_ratio[-1]) / last_profit_ratio[-1] report_data["cur_year_profit_ratio"] = float(cur_year_profit_ratio) # 月度回报 def year_month(x): a = x.year b = x.month return str(a) + "/" + str(b) profit_df_cp = profit_df.copy() profit_df_cp["date"] = profit_df_cp.index grouped = profit_df_cp.groupby(profit_df_cp["date"].apply(year_month)) sum_group = grouped.agg(np.sum) month_sum = sum_group.sum(axis=1) return_ratio_df["date"] = return_ratio_df.index return_group = return_ratio_df.groupby(return_ratio_df["date"].apply(year_month)) month_last_return_ratio = return_group.last()["cum_return_ratio"] month_sum = month_sum[month_sum.index.isin(month_last_return_ratio.index.values)] month_result = pd.DataFrame({"date": month_sum.index, "profit": month_sum.values, "ratio": month_last_return_ratio.values}) month_result["datetime"] = pd.to_datetime(month_result["date"]) month_result.sort_values(by="datetime", inplace=True) report_data["month_return"] = month_result # amount_df["date"] = amount_df.index grouped_amount = amount_df.groupby(amount_df["date"].apply(year_month)) month_amount = grouped_amount.last() del month_amount["date"] month_amount_sum = month_amount.sum(axis=1) # 月度回报表格数据 start_year = self.start_date.year now_year = datetime.datetime.now().year month_return_data_dict = {} for i in range(now_year-start_year+1): month_return_data_dict[start_year+i] = {j+1: {"profit": "-", "net_amount": "-"} for j in range(12)} for d_index, d_row in month_sum.items(): cur_year = int(d_index[:4]) cur_month = int(d_index[5:]) cur_profit = round(d_row/10000.0, 2) cur_net_amount = round(month_amount_sum.loc[d_index]/10000, 2) month_return_data_dict[cur_year][cur_month]["profit"] = "%.2f"%cur_profit month_return_data_dict[cur_year][cur_month]["net_amount"] = "%.2f"%cur_net_amount # 组合月度回报表 report_data["month_return_data_dict"] = month_return_data_dict # # 贡献分解 # month_earn = sum_group.div(month_sum, axis='rows') # report_data["contribution_decomposition"] = month_earn # 累积收益率 cumulative_return = return_ratio_df["cum_return_ratio"].values[-1] report_data["cumulative_return"] = float(cumulative_return) # 对应指数数据 index_df = self.get_customer_index_nav_data() index_result = self.signal_fund_profit_result(index_df[index_df.index >= pd.to_datetime(first_trade_date)], "index") report_data["index_result"] = index_result # self.__month_return(cur_folio_result_cnav_data, fund_id_list) self.total_result_data = report_data return report_data # 基金净值数据,持仓数据 def group_fund_basic_info_data(self, p_order_df, p_result_cnav_data, p_sum_profit, p_total_amount): group_fund_basic_info = [] group_fund_hoding_info = [] freq_max = p_order_df["freq"].max() n_freq = freq_days(int(freq_max)) resample_df = resample(p_result_cnav_data, self.trade_cal_date, freq_max) for index, row in p_order_df.iterrows(): if row['order_type'] == 2 or row["confirm_share"] <= 0: continue cur_fund_id = str(row["fund_id"]) cur_fund_performance = self.all_fund_performance[cur_fund_id] if len(cur_fund_performance) <=0: fund_basic_info = {"fund_name": row["fund_name"], "confirm_nav": round(row["nav"], 4)} fund_basic_info["cur_nav"] = round(float(self.fund_nav_total[cur_fund_id].dropna().values[-1]), 4) fund_basic_info["cur_cnav"] = round(float(self.fund_cnav_total[cur_fund_id].dropna().values[-1]), 4) fund_basic_info["ret_1w"] = "-" # 上周 fund_basic_info["ret_cum_1m"] = "-" # 最近一个月 fund_basic_info["ret_cum_6m"] = "-" # 最近半年 fund_basic_info["ret_cum_1y"] = "-" # 最近一年 fund_basic_info["ret_cum_ytd"] = "-" # 今年以来 fund_basic_info["ret_cum_incep"] = "-" # 成立以来 # 申购以来 confirm_date = pd.to_datetime(row["confirm_share_date"]) confirm_cnav = float(p_result_cnav_data.loc[confirm_date, cur_fund_id]) fund_basic_info["ret_after_confirm"] = round( (fund_basic_info["cur_cnav"] - confirm_cnav) / confirm_cnav * 100, 2) # 分红 distribution_df = self.all_fund_distribution[cur_fund_id] if distribution_df.empty: fund_basic_info["distribution"] = "-" else: distribution_df["price_date"] = pd.to_datetime(distribution_df["price_date"]) distribution = float( distribution_df[distribution_df["price_date"] > confirm_date]["distribution"].sum()) fund_basic_info["distribution"] = round(distribution, 4) if distribution != 0 else "-" else: cur_fund_info_series = cur_fund_performance.iloc[-1] # 基金净值数据 fund_basic_info = {"fund_name": row["fund_name"], "confirm_nav": round(row["nav"],4)} fund_basic_info["cur_nav"] = round(float(self.fund_nav_total[cur_fund_id].dropna().values[-1]), 4) fund_basic_info["cur_cnav"] = round(float(self.fund_cnav_total[cur_fund_id].dropna().values[-1]), 4) fund_basic_info["ret_1w"] = str(round(cur_fund_info_series["ret_1w"]*100, 2)) + "%" if cur_fund_info_series["ret_1w"] is not None else "-" # 上周 fund_basic_info["ret_cum_1m"] = str(round(cur_fund_info_series["ret_cum_1m"]*100, 2)) + "%" if cur_fund_info_series["ret_cum_1m"] is not None else "-" # 最近一个月 fund_basic_info["ret_cum_6m"] = str(round(cur_fund_info_series["ret_cum_6m"]*100, 2)) + "%" if cur_fund_info_series["ret_cum_6m"] is not None else "-" # 最近半年 fund_basic_info["ret_cum_1y"] = str(round(cur_fund_info_series["ret_cum_1y"]*100, 2)) + "%" if cur_fund_info_series["ret_cum_1y"] is not None else "-" # 最近一年 fund_basic_info["ret_cum_ytd"] = str(round(cur_fund_info_series["ret_cum_ytd"]*100, 2)) + "%" if cur_fund_info_series["ret_cum_ytd"] is not None else "-" # 今年以来 fund_basic_info["ret_cum_incep"] = str(round(cur_fund_info_series["ret_cum_incep"]*100, 2)) + "%" if cur_fund_info_series["ret_cum_incep"] is not None else "-" # 成立以来 # 申购以来 confirm_date = pd.to_datetime(row["confirm_share_date"]) confirm_cnav = float(p_result_cnav_data.loc[confirm_date, cur_fund_id]) fund_basic_info["ret_after_confirm"] = str(round((fund_basic_info["cur_cnav"] - confirm_cnav)/confirm_cnav*100, 2)) + "%" # 分红 distribution_df = self.all_fund_distribution[cur_fund_id] if distribution_df.empty: fund_basic_info["distribution"] = "-" else: distribution_df["price_date"] = pd.to_datetime(distribution_df["price_date"]) distribution = float(distribution_df[distribution_df["price_date"] > confirm_date]["distribution"].sum()) fund_basic_info["distribution"] = round(distribution, 4) if distribution != 0 else "-" group_fund_basic_info.append(fund_basic_info) # 基金持仓数据 total_market_values = p_sum_profit + p_total_amount # 月末总市值 fund_hoding_info = {"fund_strategy_name": dict_substrategy[int(row["substrategy"])], "fund_name": row["fund_name"]} fund_hoding_info["confirm_date"] = row["confirm_share_date"].strftime("%Y-%m-%d") fund_hoding_info["hold_year"] = "%.2f" % round((self.end_date - pd.to_datetime(row["confirm_share_date"])).days/365.0, 2) # 存续年数 fund_hoding_info["market_values"] = round((float(row["confirm_share"]) * (fund_basic_info["cur_cnav"] - confirm_cnav) + float(row["confirm_amount"]))/10000, 2) temp_market_values = float(row["confirm_share"]) * (fund_basic_info["cur_cnav"] - confirm_cnav) + float(row["confirm_amount"]) fund_hoding_info["weight"] = "%.2f" % round(float(fund_hoding_info["market_values"]) / total_market_values * 10000.0 * 100, 2) # 月末占比 fund_hoding_info["cost"] = "%.2f" % round(float(row["confirm_amount"])/10000, 2) # 投资本金 # 当月收益 if row['confirm_share_date'] > self.month_start_date: cal_month_start_date = row['confirm_share_date'] last_month_cnav_serise = p_result_cnav_data[p_result_cnav_data.index == pd.to_datetime(cal_month_start_date)][ row["fund_id"]].dropna() else: cal_month_start_date = self.month_start_date - datetime.timedelta(days=1) last_month_cnav_serise = p_result_cnav_data[p_result_cnav_data.index= len(amount_ratio_shift): amount_ratio_shift.iloc[num_va] = 0 else: amount_ratio_shift.iloc[num_va] = amount_ratio_shift.values[num_va+1] nav_net_amount_df[amount_name + "_profit_ratio_weight"] = amount_ratio_shift * nav_net_amount_df[amount_name + "_profit_ratio"] nav_net_amount_df[amount_name + "_profit_cum_ratio_weight"] = (fund_profit_ratio.cumprod()-1)*amount_ratio_shift # enter_date = nav_net_amount_df[amount_name+"_profit_ratio"].dropna() fund_id_list_profit_ratio_weight = [i + "_profit_ratio_weight" for i in fund_id_list] nav_profit_ratio_weight = nav_net_amount_df[fund_id_list_profit_ratio_weight].copy().fillna(method='ffill') # 组合收益率 return_ratio = nav_profit_ratio_weight.sum(axis=1) # 组合累积收益率 # return_ratio_list = list(return_ratio.values) cum_return_ratio = (return_ratio + 1).fillna(0).cumprod() # 收益率df cum_return_ratio_df = pd.DataFrame(return_ratio.values, columns=["return_ratio"]) cum_return_ratio_df["cum_return_ratio"] = cum_return_ratio.values cum_return_ratio_df.index = return_ratio.index # 单个基金累计收益分解df weight_name_list = [i + "_profit_cum_ratio_weight" for i in fund_id_list] signal_fund_cum_weight = nav_net_amount_df[weight_name_list] re_name = {x: x.replace("_profit_cum_ratio_weight", "") for x in weight_name_list} signal_fund_cum_weight.rename(columns=re_name, inplace=True) # 月度分组 def year_month(x): a = x.year b = x.month return str(a) + "/" + str(b) profit_df_cp = signal_fund_cum_weight.copy() profit_df_cp["date"] = list(profit_df_cp.index) grouped = profit_df_cp.groupby(profit_df_cp["date"].apply(year_month)) month_signal_fund_cum = grouped.last() month_signal_fund_cum.rename(columns={"date": "datetime"}, inplace=True) month_signal_fund_cum.sort_values(by="datetime", inplace=True) del month_signal_fund_cum["datetime"] p_cum_df = cum_return_ratio_df.copy() p_cum_df["date"] = list(p_cum_df.index) cum_grouped = p_cum_df.groupby(p_cum_df["date"].apply(year_month)) month_fund_cum = cum_grouped.last() month_fund_cum.rename(columns={"date": "datetime"}, inplace=True) month_fund_cum.sort_values(by="datetime", inplace=True) del month_fund_cum["datetime"] return cum_return_ratio_df, month_fund_cum, month_signal_fund_cum @staticmethod def signal_fund_profit_result(p_fund_nav_df, cur_fund_id): result = {"fund_id": cur_fund_id} fund_nav_df = p_fund_nav_df.copy() profit = fund_nav_df[cur_fund_id].dropna() - fund_nav_df[cur_fund_id].dropna().shift(1) fund_nav_df[cur_fund_id + "_profit"] = profit fund_nav_df[cur_fund_id + "_profit_ratio"] = profit / fund_nav_df[cur_fund_id].dropna().shift(1) # 累积收益率 return_ratio_list = list(fund_nav_df[cur_fund_id + "_profit_ratio"].astype("float64").values) cum_return_ratio = [] last_ratio = 0 for i in range(len(return_ratio_list)): if i == 0: last_ratio = 1 + return_ratio_list[i] if str(return_ratio_list[0]) != 'nan' else 1 cum_return_ratio.append(last_ratio) continue cur_ratio = (1 + return_ratio_list[i]) * last_ratio cum_return_ratio.append(cur_ratio) last_ratio = cur_ratio fund_nav_df['cum_return_ratio'] = cum_return_ratio # 区间收益率 result["return_ratio"] = cum_return_ratio[-1] # 区间年化收益 n_freq = freq_days(1) return_ratio_year = annual_return((fund_nav_df["cum_return_ratio"].values[-1] - 1), fund_nav_df, n_freq) result["return_ratio_year"] = float(return_ratio_year) # 波动率 volatility_ = volatility(fund_nav_df["cum_return_ratio"], n_freq) result["volatility"] = float(volatility_) # 最大回撤 drawdown = max_drawdown(fund_nav_df["cum_return_ratio"]) result["max_drawdown"] = drawdown # 夏普比率 sim = simple_return(fund_nav_df["cum_return_ratio"]) exc = excess_return(sim, BANK_RATE, n_freq) try: sharpe = sharpe_ratio(exc, sim, n_freq) except ZeroDivisionError: sharpe = 0.0 result["sharpe"] = float(sharpe) return result def get_month_return_chart(self): res = self.total_result_data["month_return"] xlabels = res["date"].values res["profit"] = res["profit"].apply(lambda x: round(x/10000.0, 2)) res["ratio"] = res["ratio"].apply(lambda x: round((x-1)*100, 2)) product_list = {'name': '月度回报', 'data': res["profit"].values} cumulative = {'name': '累积收益', 'data': res["ratio"].values} return xlabels, [product_list], cumulative def get_total_basic_data(self): return self.total_result_data def get_group_data(self): return self.group_result_data # def __month_return(self, folio_cnav_data): # # 月度回报 # def year_month(x): # a = x.year # b = x.month # return str(a) + "-" + str(b) # p_folio_cnav_data = folio_cnav_data.copy() # p_folio_cnav_data["date"] = p_folio_cnav_data.index # grouped_data = p_folio_cnav_data.groupby(p_folio_cnav_data["date"].apply(year_month))