From a570b2f074e9ea537100387eb89305a647307b81 Mon Sep 17 00:00:00 2001
From: zhaojie01 <zhaojie01@wealthgrow.cn>
Date: Tue, 22 Dec 2020 15:43:24 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dbug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 app/service/portfolio_diagnose.py     | 44 +++++++++++++++++++--------
 app/templates/v2/monthReportV2.1.html | 16 +++++-----
 app/utils/fund_rank.py                |  7 +++--
 app/utils/jinjia2html_v2.py           | 14 +++++----
 app/utils/week_evaluation.py          |  9 +++++-
 5 files changed, 61 insertions(+), 29 deletions(-)

diff --git a/app/service/portfolio_diagnose.py b/app/service/portfolio_diagnose.py
index 183e0e3..3862efc 100644
--- a/app/service/portfolio_diagnose.py
+++ b/app/service/portfolio_diagnose.py
@@ -381,8 +381,10 @@ class PortfolioDiagnose(object):
         if self.end_date is None:
             self.end_date = datetime.datetime(datetime.date.today().year,
                                               datetime.date.today().month, 1) - datetime.timedelta(1)
+        if self.start_date is None:
             self.start_date = cal_date(self.end_date, 'Y', 1)
-
+        else:
+            self.start_date = datetime.datetime(start_date.year, start_date.month, start_date.day)
         self.replace_pair = dict()  # 由于数据不足半年而被替换为相同基金经理和策略的原基金和替换基金的映射
         self.no_data_fund = []  # 未在数据库中找到基金净值或者基金经理记录的基金
         self.abandon_fund_score = []  # 打分不满足要求的基金
@@ -544,15 +546,16 @@ class PortfolioDiagnose(object):
                 proposal_nav = rename_col(proposal_nav, proposal)
 
                 # 按最大周期进行重采样,计算新建组合的相关性
-                prod = pd.merge(prod, proposal_nav, how='outer', on='end_date').astype(float)
-                prod.sort_index(inplace=True)
-                prod.ffill(inplace=True)
-                prod = resample(prod, get_trade_cal(), min(self.freq_list))
+                prod_with_new_fund = pd.merge(prod, proposal_nav, how='outer', on='end_date').astype(float)
+                prod_with_new_fund.sort_index(inplace=True)
+                prod_with_new_fund.ffill(inplace=True)
 
-                self.new_correlation = cal_correlation(prod)
+                prod_with_new_fund = resample(prod_with_new_fund, get_trade_cal(), min(self.freq_list))
+                self.new_correlation = cal_correlation(prod_with_new_fund)
                 judge_correlation = self.new_correlation.fillna(0)
 
                 if np.all(judge_correlation < 0.8):
+                    prod = prod_with_new_fund
                     self.proposal_fund.append(proposal)
                     max_len -= 1
                     # add_strategy -= {proposal_strategy}
@@ -561,7 +564,8 @@ class PortfolioDiagnose(object):
                     if max_len == 0:
                         break
                 else:
-                    prod.drop(columns=proposal, inplace=True)
+                    # prod.drop(columns=proposal, inplace=True)
+                    self.freq_list.pop()
 
         prod.dropna(how='all', inplace=True)
         prod.fillna(method='bfill', inplace=True)
@@ -704,9 +708,9 @@ class PortfolioDiagnose(object):
 
         # 正收益基金数量
         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 = len(group_hold_data[group_hold_data["profit"] > 0]["fund_name"].unique())
         if profit_positive_num > 0:
-            profit_positive_evaluate = str(profit_positive_num) + "只基金取的正收益,"
+            profit_positive_evaluate = str(profit_positive_num) + "只基金取得正收益取得正收益,"
         else:
             profit_positive_evaluate = ""
 
@@ -733,7 +737,7 @@ class PortfolioDiagnose(object):
                 strategy_distribution_evaluate = "策略上有一定分散"
             else:
                 strategy_distribution_evaluate = "策略分散程度不高"
-        except ZeroDivisionError:
+        except:
             strategy_distribution_evaluate = "策略分散程度不高"
         # 相关性
         if len(self.abandon_fund_corr) > 0:
@@ -824,7 +828,13 @@ class PortfolioDiagnose(object):
         return_compare_df = pd.merge(index_return[["new_index_return"]], old_return_df[["cum_return_ratio"]],
                                      right_index=True,
                                      left_index=True)
+        start = return_compare_df.index.values[0]
+        if start > pd.to_datetime(self.start_date):
+            row = [0, 0]
+            return_compare_df.loc[pd.to_datetime(self.start_date)] = row
+
         return_compare_df["date"] = return_compare_df.index
+        return_compare_df.sort_values(by="date", inplace=True)
         return_compare_df["date"] = return_compare_df["date"].apply(lambda x: x.strftime("%Y-%m-%d"))
         return_compare_df.iloc[1:-1, :]["date"] = ""
         old_return_compare_result = {
@@ -944,7 +954,12 @@ class PortfolioDiagnose(object):
             # 新组合夏普比率
             sim = simple_return(propose_fund_return_limit_data["new_return"]+1)
             exc = excess_return(sim, BANK_RATE, n_freq)
-            new_sharpe = sharpe_ratio(exc, sim, n_freq)
+            try:
+                new_sharpe = sharpe_ratio(exc, sim, n_freq)
+                if new_sharpe is None or math.isnan(new_sharpe):
+                    new_sharpe = 0
+            except:
+                new_sharpe = 0
 
             # 指数收益
             index_return = index_return[index_return.index >= group_order_start_date]
@@ -956,7 +971,12 @@ class PortfolioDiagnose(object):
             index_drawdown = max_drawdown(index_return["new_index_return"]+1)
             index_sim = simple_return(index_return["new_index_return"]+1)
             index_exc = excess_return(index_sim, BANK_RATE, n_freq)
-            index_sharpe = sharpe_ratio(index_exc, index_sim, n_freq)
+            try:
+                index_sharpe = sharpe_ratio(index_exc, index_sim, n_freq)
+                if index_sharpe is None or math.isnan(index_sharpe):
+                    index_sharpe = 0.0
+            except:
+                index_sharpe = 0.0
 
             # 收益对比数据
             return_compare_df = pd.merge(index_return[["new_index_return"]], old_return_df[["cum_return_ratio"]], right_index=True,
diff --git a/app/templates/v2/monthReportV2.1.html b/app/templates/v2/monthReportV2.1.html
index 0d103f6..779654e 100644
--- a/app/templates/v2/monthReportV2.1.html
+++ b/app/templates/v2/monthReportV2.1.html
@@ -1041,28 +1041,28 @@
           <table class="tss1_table">
             <tr>
               <td>
-                {%if month_rise>=0%}
+                {%if (month_rise|float)>=0%}
                 本月涨幅:<span class="red">{{month_rise}}%</span>
                 {%else%}
                 本月涨幅:<span class="green">{{month_rise}}%</span>
                 {%endif%}
               </td>
               <td>
-                {%if now_month_income>=0%}
+                {%if (now_month_income| float) >=0%}
                 本月收益:<span class="red">{{now_month_income}}元</span>
                 {%else%}
                 本月收益:<span class="green">{{now_month_income}}元</span>
                 {%endif%}
               </td>
               <td>
-                {%if year_totoal_rate_of_return>=0%}
+                {%if (year_totoal_rate_of_return|float)>=0%}
                 今年累计收益率:<span class="red">{{year_totoal_rate_of_return}}%</span>
                 {%else%}
                 今年累计收益率:<span class="green">{{year_totoal_rate_of_return}}%</span>
                 {%endif%}
               </td>
               <td>
-                {%if now_year_income>=0%}
+                {%if (now_year_income|float)>=0%}
                 今年累计收益:<span class="red">{{now_year_income}}元</span>
                 {%else%}
                 今年累计收益:<span class="green">{{now_year_income}}元</span>
@@ -1071,21 +1071,21 @@
             </tr>
             <tr>
               <td>
-                {%if now_yield>=0%}
+                {%if (now_yield|float)>=0%}
                 成立以来累计收益率:<span class="red">{{now_yield}}%</span>
                 {%else%}
                 成立以来累计收益率:<span class="green">{{now_yield}}%</span>
                 {%endif%}
               </td>
               <td>
-                {%if now_annualised_return>=0%}
+                {%if (now_annualised_return|float)>=0%}
                 年化收益率:<span class="red">{{now_annualised_return}}%</span>
                 {%else%}
                 年化收益率:<span class="green">{{now_annualised_return}}%</span>
                 {%endif%}
               </td>
               <td>
-                {%if now_withdrawal>=0%}
+                {%if (now_withdrawal|float)>=0%}
                 最大回撤:<span class="red">{{now_withdrawal}}%</span>
                 {%else%}
                 最大回撤:<span class="green">{{now_withdrawal}}%</span>
@@ -1117,7 +1117,7 @@
               </td>
               <td>
 
-                {%if total_profit>=0%}
+                {%if (total_profit|float)>=0%}
                 累计盈利:<span class="red">{{total_profit}}元</span>
                 {%else%}
                 累计盈利:<span class="green">{{total_profit}}元</span>
diff --git a/app/utils/fund_rank.py b/app/utils/fund_rank.py
index a5f6059..488a563 100644
--- a/app/utils/fund_rank.py
+++ b/app/utils/fund_rank.py
@@ -80,7 +80,10 @@ def get_frequency(df):
     # freq_series = index_series - index_series.shift(1)
     freq_series = index_series.diff(1)
     logging.log(logging.DEBUG, freq_series.describe())
-    f = freq_series.mode()[0].days
+    try:
+        f = freq_series.mode()[0].days
+    except:
+        return 250
     if f in range(0, 3):
         return 250
     elif f in range(6, 9):
@@ -92,7 +95,7 @@ def get_frequency(df):
     elif f in range(110, 133):
         return 3
     else:
-        raise ValueError
+        return 250
 
 
 def get_trade_cal():
diff --git a/app/utils/jinjia2html_v2.py b/app/utils/jinjia2html_v2.py
index d953a0b..a3382db 100644
--- a/app/utils/jinjia2html_v2.py
+++ b/app/utils/jinjia2html_v2.py
@@ -78,7 +78,8 @@ class DataIntegrate:
             self.all_folio_result[group_name] = cur_group_portfolio_result
 
     def get_portfolio_diagnose(self, portfolio, client_type=1, invest_amount=10000000):
-        portfolio_diagnose = PortfolioDiagnose(client_type=client_type, portfolio=portfolio, invest_amount=invest_amount)
+        portfolio_diagnose = PortfolioDiagnose(client_type=client_type, portfolio=portfolio, invest_amount=invest_amount,
+                                               start_date=self.user_customer.start_date)
         portfolio_diagnose.optimize()
         return portfolio_diagnose
 
@@ -246,7 +247,7 @@ class DataIntegrate:
                 'team': template_folder + '/v2/img/default-user.png',
                 # 全局数据
                 'customer_name': self.customer_name,
-                'year_month': self.user_customer.month_start_date.strftime("%Y-%m"),
+                'year_month': self.user_customer.month_start_date.strftime("%Y{}%m{}").format("年", "月"),
                 'month': self.user_customer.month_start_date.strftime("%m"),
                 'start_date': self.user_customer.start_date.strftime("%Y-%m-%d"),
                 'latest_worth_day': self.user_customer.last_nav_date,
@@ -254,11 +255,11 @@ class DataIntegrate:
                 'customer_old': 42,
                 'customer_level': '平衡型',
                 # 综述数据
-                'now_allocation_amount': self.total_cost, 'now_yield': self.now_yield, 'index_yield': self.index_yield,
+                'now_allocation_amount': '{:,}'.format(self.total_cost), 'now_yield': self.now_yield, 'index_yield': self.index_yield,
                 'now_annualised_return': self.now_annualised_return,
                 'now_withdrawal': self.now_withdrawal, 'index_withdrawal': self.index_withdrawal, 'expected_withdrawal': 20,
-                'now_year_income': self.now_year_income, 'now_month_income': self.now_month_income,
-                'final_balance': self.final_balance, 'total_profit': self.total_profit,
+                'now_year_income': '{:,}'.format(self.now_year_income), 'now_month_income': '{:,}'.format(self.now_month_income),
+                'final_balance': '{:,}'.format(self.final_balance), 'total_profit': '{:,}'.format(self.total_profit),
 
                 'monthly_return_performance_pic': self.monthly_return_performance_pic,
                 'month_rise': self.month_rise, 'year_totoal_rate_of_return': self.year_totoal_rate_of_return,
@@ -324,5 +325,6 @@ class DataIntegrate:
 
 if __name__ == '__main__':
     start = time.time()
-    DataIntegrate(ifa_id='USER_INFO15914346866762', customer_id='202009281545001')
+    dt = DataIntegrate(ifa_id='USER_INFO15917853924996', customer_id='6741679287251775488')
+    dt.render_data()
     print('耗时{}秒'.format(round(time.time()-start, 2)))
diff --git a/app/utils/week_evaluation.py b/app/utils/week_evaluation.py
index d8a3875..b472c57 100644
--- a/app/utils/week_evaluation.py
+++ b/app/utils/week_evaluation.py
@@ -49,7 +49,12 @@ def sharpe_ratio(excess_return, simple_return, n):
     n: 数据类型, 周(52), 月(12), 日(250)
     """
     import math
-    d = math.sqrt(n) * excess_return / simple_return.std(ddof=1)
+    try:
+        d = math.sqrt(n) * excess_return / simple_return.std(ddof=1)
+        if d == float("inf") or d == float("-inf"):
+            return 0.0
+    except:
+        return 0.0
     return d
 
 
@@ -294,6 +299,8 @@ def resample(df, trading_cal, freq):
         [DataFrame]: [重采样后剔除不在交易日历中的净值表和交易日历以净值日期为索引的合表]
     """
     freq_dict = {1: 'B', 2: 'W-FRI', 3: 'M', 4: 'SM', 5: 'Q'}
+    if math.isnan(freq):
+        freq = 2
     resample_freq = freq_dict[freq]
     # 按采样频率进行重采样并进行净值的前向填充
     df = df.resample(rule=resample_freq).ffill()
-- 
2.18.1