diff --git a/app/service/data_service.py b/app/service/data_service.py index df1aea40e6b130d95475af1b129b018a8df99c40..61c972b20ad8145a3849c3829f17ccff6cf33919 100644 --- a/app/service/data_service.py +++ b/app/service/data_service.py @@ -39,6 +39,7 @@ class UserCustomerDataAdaptor: self.user_customer_order_df = self.get_user_customer_order_data() self.fund_nav_total, self.fund_cnav_total = self.get_customer_fund_nav_data() self.get_customer_index_nav_data() + self.total_customer_order_cnav_df = self.total_combine_data() self.group_operate() @staticmethod @@ -133,7 +134,6 @@ class UserCustomerDataAdaptor: # 分组åˆè®¡ç®— def group_operate(self): - for folio in self.user_customer_order_df["folio_name"].unique(): cur_folio_order_df = self.user_customer_order_df[self.user_customer_order_df["folio_name"] == folio] fund_id_list = list(self.user_customer_order_df["fund_id"].unique()) @@ -216,5 +216,64 @@ class UserCustomerDataAdaptor: self.group_data[p_folio] = {"result_cnav_data": cnav_df, "order_df": p_order_df} return cnav_df + # æ‰€æœ‰çš„æ•°æ®æ“作 def total_combine_data(self): - pass + + p_order_df = self.user_customer_order_df.copy() + p_nav_df = self.fund_nav_total.copy() + p_cnav_df = self.fund_cnav_total.copy() + + start_date = pd.to_datetime(p_order_df["confirm_share_date"].min()) + cnav_df = p_cnav_df[p_cnav_df.index >= start_date].copy() + + p_fund_id_list = list(p_order_df["fund_id"].unique()) + for p_fund_id in p_fund_id_list: + order_min_date = p_order_df[p_order_df["fund_id"] == p_fund_id]["confirm_share_date"].min() + if pd.to_datetime(order_min_date) > start_date: + cnav_df.loc[:order_min_date - datetime.timedelta(days=1), p_fund_id] = np.nan + + for index, row in p_order_df.iterrows(): + cur_fund_id = str(row["fund_id"]) + confirm_share_date = pd.to_datetime(row["confirm_share_date"]) + + # æ ¹æ®ç¡®è®¤å‡€å€¼æ—¥æŸ¥çœ‹æ˜¯å¦å«æœ‰ç´¯ç§¯å‡€å€¼çš„æ•°æ®ï¼Œå¦‚果没有按照å‰åŽå·®å€¼æŽ¨ç®—当天累积净值 + if pd.isnull(cnav_df.loc[confirm_share_date, cur_fund_id]): + last_nav_data = p_nav_df[p_nav_df.index < confirm_share_date][cur_fund_id].dropna().tail(1) + last_cnav_data = p_cnav_df[p_cnav_df.index < confirm_share_date][cur_fund_id].dropna().tail(1) + # 判æ–上个净值日和当å‰ç¡®è®¤æ—¥ä¹‹ä¸æ˜¯å¦å˜åœ¨åˆ†çº¢æ—¥ + """need add judge""" + + if len(last_nav_data) < 1: + cnav_df.loc[confirm_share_date, cur_fund_id] = row["nav"] + else: + diff_nav = row["nav"] - last_nav_data.values[0] + cur_cnav = last_cnav_data.values[0] + diff_nav + cnav_df.loc[confirm_share_date, cur_fund_id] = cur_cnav + + cnav_df = cnav_df.dropna(axis=0, how="all").fillna(method='ffill') + for index, row in p_order_df.iterrows(): + cur_fund_id = str(row["fund_id"]) + confirm_share_date = pd.to_datetime(row["confirm_share_date"]) + if cur_fund_id + "_amount" not in cnav_df: + profit = cnav_df[cur_fund_id].dropna() - cnav_df[cur_fund_id].dropna().shift(1) + cnav_df[cur_fund_id + "_profit"] = profit + cnav_df[cur_fund_id + "_profit_ratio"] = profit / cnav_df[cur_fund_id].dropna().shift(1) + cnav_df[cur_fund_id + "_amount"] = 0 + cnav_df[cur_fund_id + "_earn"] = 0 + # cnav_df[cur_fund_id + "_cum_earn"] = 0 + cnav_df[cur_fund_id + "_share"] = 0 + + # buy + if row['order_type'] == 1: + cnav_df.loc[confirm_share_date:, cur_fund_id + "_amount"] += row["confirm_amount"] + cnav_df.loc[confirm_share_date:, cur_fund_id + "_share"] += row["confirm_share"] + # sell + elif row['order_type'] == 2: + cnav_df.loc[confirm_share_date:, cur_fund_id + "_amount"] -= row["confirm_amount"] + cnav_df.loc[confirm_share_date:, cur_fund_id + "_share"] -= row["confirm_share"] + + cnav_df[cur_fund_id + "_earn"] = cnav_df[cur_fund_id + "_profit"] * cnav_df[cur_fund_id + "_share"] + cnav_df[cur_fund_id + "_earn"] = cnav_df[cur_fund_id + "_earn"].apply(lambda x: float(x)) + cnav_df[cur_fund_id + "_cum_earn"] = cnav_df[cur_fund_id + "_earn"].cumsum() + + return cnav_df diff --git a/app/service/result_service.py b/app/service/result_service.py index c5f1b25aa7767889d5884a342832e2f6994ed92d..6b81f2ca4f19314609d718bc67925307ad0601d1 100644 --- a/app/service/result_service.py +++ b/app/service/result_service.py @@ -60,17 +60,16 @@ def resample(df, trading_cal, freq): class UserCustomerResultAdaptor(UserCustomerDataAdaptor): total_result_data = {} - group_result_data = [] + group_result_data = {} def __init__(self, user_id, customer_id, end_date=str(datetime.date.today())): # super().__init__() super().__init__(user_id, customer_id, end_date) - # ç»¼è¿°æ•°æ® - def get_total_data(self): + # 组åˆç»“æžœæ•°æ® + def get_group_result_data(self): for folio in self.group_data.keys(): - # self.group_result_data.append({folio: {}}) folio_report_data = {} cur_folio_result_cnav_data = self.group_data[folio]["result_cnav_data"] @@ -79,7 +78,7 @@ class UserCustomerResultAdaptor(UserCustomerDataAdaptor): 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] + # fund_id_list_amount = [i + "_amount" for i in fund_id_list] profit_df = cur_folio_result_cnav_data[fund_id_list_earn] # ç»„åˆæ”¶ç›ŠçŽ‡æ•°ç»„ @@ -106,7 +105,7 @@ class UserCustomerResultAdaptor(UserCustomerDataAdaptor): # 最大回撤 drawdown = max_drawdown(resample_df["cum_return_ratio"]) - folio_report_data["max_drawdown"] = float(drawdown) + folio_report_data["max_drawdown"] = drawdown # 夿™®æ¯”率 sim = simple_return(resample_df["cum_return_ratio"]) @@ -147,25 +146,25 @@ class UserCustomerResultAdaptor(UserCustomerDataAdaptor): 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) - # 月度回报 - 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) - folio_report_data["month_return"] = month_sum - - # 贡献分解 - month_earn = sum_group.div(month_sum, axis='rows') - folio_report_data["contribution_decomposition"] = month_earn - - # 累积收益率 - cumulative_return= return_ratio_df["cum_return_ratio"].values[-1] - folio_report_data["contribution_decomposition"] = 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) + # folio_report_data["month_return"] = month_sum + # + # # 贡献分解 + # month_earn = sum_group.div(month_sum, axis='rows') + # folio_report_data["contribution_decomposition"] = month_earn + # + # # 累积收益率 + # cumulative_return= return_ratio_df["cum_return_ratio"].values[-1] + # folio_report_data["contribution_decomposition"] = float(cumulative_return) # 组åˆå†…å•ä¸ªåŸºé‡‘å‡€å€¼æ•°æ® ç»„åˆå†…基金æŒä»“æ•°æ® result_fund_nav_info, result_fund_hoding_info = self.group_fund_basic_info_data(fund_id_list, cur_folio_order_data, cur_folio_result_cnav_data, cumulative_profit, total_cost) @@ -174,10 +173,119 @@ class UserCustomerResultAdaptor(UserCustomerDataAdaptor): folio_report_data["group_nav_info"] = result_fund_nav_info folio_report_data["group_hoding_info"] = result_fund_hoding_info - continue + self.group_result_data[folio] = folio_report_data + + return self.group_result_data + + # ç»¼è¿°æ•°æ® + def get_total_data(self): + report_data = {} + + cur_folio_result_cnav_data = self.total_customer_order_cnav_df + 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] + profit_df = cur_folio_result_cnav_data[fund_id_list_earn] + + # æŒä»“周期 + 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, freq_max) + + # æ€»æˆæœ¬ + 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) + report_data["month_return"] = month_sum + + # # 贡献分解 + # 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["contribution_decomposition"] = float(cumulative_return) + + self.total_result_data = report_data + return report_data # 组åˆåŸºé‡‘å‡€å€¼æ•°æ® - def group_fund_basic_info_data(self, p_fund_id_list, p_order_df, p_result_cnav_data, p_sum_profit, p_total_amount): + 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 = [] for index, row in p_order_df.iterrows(): @@ -261,5 +369,7 @@ class UserCustomerResultAdaptor(UserCustomerDataAdaptor): cum_return_ratio_df.index = return_ratio.index return cum_return_ratio_df - + @staticmethod + def signal_fund_profit_result(): + pass