#!/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 import UserCustomerDataAdaptor
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"]
            freq_max = cur_folio_order_data["freq"].max()
            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)
            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 = float(cur_folio_order_data[cur_folio_order_data["order_type"] == 1]["confirm_amount"].sum() - \
                         cur_folio_order_data[cur_folio_order_data["order_type"] == 2]["confirm_amount"].sum())
            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:, "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
        freq_max = cur_folio_order_data["freq"].max()
        #
        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)
        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 = float(cur_folio_order_data[cur_folio_order_data["order_type"] == 1]["confirm_amount"].sum() - \
                           cur_folio_order_data[cur_folio_order_data["order_type"] == 2]["confirm_amount"].sum())
        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():
            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)
            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)     # 投资本金
            # 当月收益
            last_month_cnav_serise = p_result_cnav_data[p_result_cnav_data.index<pd.to_datetime(self.month_start_date)][row["fund_id"]].dropna()
            if len(last_month_cnav_serise) == 0:
                fund_hoding_info["profit"] = round(float(row["confirm_share"]) * (fund_basic_info["cur_cnav"] - confirm_cnav) / 10000, 2)
            else:
                last_month_cnav = float(last_month_cnav_serise.values[-1])
                fund_hoding_info["profit"] = round(float(row["confirm_share"]) * (fund_basic_info["cur_cnav"] - last_month_cnav)/10000, 2)
            # 当月收益率
            fund_hoding_info["month_return_ratio"] = "%.2f" % round(float(fund_hoding_info["profit"]) / float(fund_hoding_info["market_values"])*100, 2)
            # 累积收益
            fund_hoding_info["cum_profit"] = "%.2f" % round(float(row["confirm_share"]) * (fund_basic_info["cur_cnav"] - confirm_cnav) / 10000, 2)
            # 累积收益率
            fund_hoding_info["cum_profit_ratio"] = "%.2f" % round((fund_basic_info["cur_cnav"] - confirm_cnav)/confirm_cnav*100, 2)
            # 累积年化收益率
            cur_resample_df = resample_df[[row["fund_id"]]].dropna()
            return_ratio_year = annual_return(float(fund_hoding_info["cum_profit_ratio"])/100.0, cur_resample_df, n_freq)
            fund_hoding_info["return_ratio_year"] = "%.2f" % round(float(return_ratio_year)*100, 2)
            group_fund_hoding_info.append(fund_hoding_info)
        return group_fund_basic_info, group_fund_hoding_info

    @staticmethod
    def combination_yield(p_combina_df, fund_id_list):
        fund_id_list_amount = [i + "_net_amount" for i in fund_id_list]
        fund_id_list_profit_ratio = [i + "_profit_ratio" for i in fund_id_list]


        nav_net_amount_df = p_combina_df[fund_id_list + fund_id_list_amount+fund_id_list_profit_ratio].copy()
        # nav_net_amount_df = resample(return_ratio_df, self.trade_cal_date, freq_max)
        nav_net_amount_df["sum_net_amount"] = nav_net_amount_df[fund_id_list_amount].sum(axis=1).apply(lambda x: Decimal.from_float(x))
        for amount_name in fund_id_list:
            price = nav_net_amount_df[amount_name].dropna()
            profit = price.diff().fillna(Decimal(0))
            profit_ratio_new = profit / price.shift(1)
            profit_ratio_old = nav_net_amount_df[amount_name+"_profit_ratio"]
            nan_index = profit_ratio_new[pd.isna(profit_ratio_new)].index
            profit_ratio_new[nan_index] = profit_ratio_old[nan_index]
            nav_net_amount_df[amount_name + "_profit_ratio"] = profit_ratio_new
            nav_net_amount_df[amount_name+"_amount_ratio"] = nav_net_amount_df[amount_name+"_net_amount"]/(nav_net_amount_df["sum_net_amount"])

            fund_profit_ratio = nav_net_amount_df[amount_name + "_profit_ratio"].dropna() + 1
            amount_ratio_shift = nav_net_amount_df[amount_name + "_amount_ratio"].shift(1)
            num_va = len(amount_ratio_shift[amount_ratio_shift.values==0])
            if num_va+1 >= 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))
