jinjia2html.py 14.7 KB
Newer Older
1
import time
2
import uuid
3 4 5

from jinja2 import PackageLoader, Environment

pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
6
from app.api.engine import work_dir, pdf_folder, template_folder
赵杰's avatar
赵杰 committed
7
from app.service.portfolio_diagnose import PortfolioDiagnose
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
8
from app.service.result_service_v2 import UserCustomerResultAdaptor
9
import numpy as np
10 11
from concurrent import futures
import os
12 13

# 准备数据
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
14 15
from app.utils.draw import draw_month_return_chart, draw_contribution_chart, draw_combination_chart, \
    draw_old_combination_chart
16
from app.utils.html_to_pdf import html_to_pdf
17 18 19 20
from app.utils.radar_chart import gen_radar_chart


class DataIntegrate:
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
21
    def __init__(self, ifa_id='USER_INFO15914346866762', customer_id='202009281545001', pdf_name=str(uuid.uuid4()) + '.pdf'):
22
        self.user_customer = UserCustomerResultAdaptor(ifa_id, customer_id)
赵杰's avatar
赵杰 committed
23
        self.customer_name = self.user_customer.customer_real_name
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
24
        self.pdf_name = pdf_name
25 26 27 28
        self.df = self.user_customer.calculate_total_data()
        self.d = self.user_customer.calculate_group_result_data()
        # 组合数据
        self.group_result = self.d["default"]
赵杰's avatar
赵杰 committed
29
        self.get_portfolio_diagnose(self.group_result["fund_id_list"])
30
        # 投资总览
31 32 33
        self.get_summarize()
        # 月度回报
        self.get_month_return()
34 35
        # 月度回报表格
        self.get_month_table_return()
36 37 38 39 40 41
        # 旧持仓组合点评
        self.comments_on_position_portfolio()
        # 贡献分解
        self.contribution_deco()
        # 个基点评
        self.single_fund_comment()
pengxiong's avatar
pengxiong committed
42 43
        # 旧收益比较
        self.get_old_compare_pic()
44 45
        # 旧相关性
        self.get_old_correlation()
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
46 47
        # 新相关性
        self.get_new_correlation()
48 49 50 51
        # 新增基金
        self.propose_fund()
        # 目标与业绩
        self.objectives_performance(self.group_result)
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
52
        # 新收益比较
赵杰's avatar
赵杰 committed
53
        self.get_transfer_suggestions()
54 55 56
        # 渲染模版
        self.render_data()

赵杰's avatar
赵杰 committed
57 58 59
    def get_portfolio_diagnose(self, portfolio, client_type=1, invest_amount=10000000):
        self.portfolio_diagnose = PortfolioDiagnose(client_type=client_type, portfolio=portfolio, invest_amount=invest_amount)
        self.portfolio_diagnose.optimize()
赵杰's avatar
赵杰 committed
60

61
    def get_summarize(self):
62 63 64 65 66 67 68 69 70 71 72 73 74
        """投资总览."""
        self.total_cost = round(self.df["total_cost"], 2)   # 投资成本
        self.now_yield = round((self.df['cumulative_return']-1)*100, 2)     # 成立以来累计收益率
        self.now_annualised_return = round(self.df["return_ratio_year"] * 100, 2)  # 年化收益率
        self.index_yield = round((self.df["index_result"]["return_ratio"]-1)*100, 2)    # 指数收益率
        self.now_withdrawal = round(self.df["max_drawdown"][0]*100, 2)  # 最大回撤
        self.index_withdrawal = round(self.df["index_result"]["max_drawdown"][0]*100, 2)    # 指数最大回撤
        self.now_month_income = int(self.df["cur_month_profit"])  # 本月收益
        self.month_rise = round(self.df["cur_month_profit_ratio"] * 100, 2)  # 本月涨幅
        self.year_totoal_rate_of_return = round(self.df["cur_year_profit_ratio"] * 100, 2)  # 今年累计收益率
        self.now_year_income = int(self.df["cur_year_profit"])  # 今年累计收益
        self.final_balance = int(self.df["total_cost"] + self.df["cumulative_profit"])  # 期末资产
        self.total_profit = int(self.df["cumulative_profit"])  # 累计盈利
75 76 77 78 79 80

    def get_month_return(self):
        """月度回报."""
        xlabels, product_list, cumulative = self.user_customer.get_month_return_chart()
        self.monthly_return_performance_pic = draw_month_return_chart(xlabels, product_list, cumulative)

81 82 83
    def get_month_table_return(self):
        self.monthly_table_return = self.df["month_return_data_dict"]

84 85
    def comments_on_position_portfolio(self):
        """旧持仓组合点评."""
赵杰's avatar
赵杰 committed
86
        self.old_evaluation = self.portfolio_diagnose.old_evaluation('default', self.d, self.user_customer)
87 88 89 90 91 92 93 94 95

    def contribution_deco(self):
        """贡献分解."""
        g_data = self.group_result["contribution_decomposition"]
        self.contribution_decomposition = draw_contribution_chart(g_data['xlabels'], g_data['product_list'], g_data['cumulative'])

    def single_fund_comment(self):
        """个基点评."""
        self.single_fund_data_list = []
赵杰's avatar
赵杰 committed
96 97
        portfolio_evaluation = self.portfolio_diagnose.old_portfolio_evaluation()
        radar_chart_data = self.portfolio_diagnose.single_fund_radar()
98 99 100
        with futures.ProcessPoolExecutor(os.cpu_count()) as executor:
            res = executor.map(gen_radar_chart, radar_chart_data)
        res = list(res)
101
        for i in range(len(portfolio_evaluation)):
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
102 103 104 105 106 107 108 109
            if portfolio_evaluation[i]['status'] == '保留':
                portfolio_evaluation[i]['status'] = '<div class="self_type fl">保留</div>'
            elif portfolio_evaluation[i]['status'] == '增仓':
                portfolio_evaluation[i]['status'] = '<div class="self_type fl red">增仓</div>'
            elif portfolio_evaluation[i]['status'] == '换仓':
                portfolio_evaluation[i]['status'] = '<div class="self_type fl green">换仓</div>'
            elif portfolio_evaluation[i]['status'] == '减仓':
                portfolio_evaluation[i]['status'] = '<div class="self_type fl green">减仓</div>'
110 111
            self.single_fund_data_list.append({
                'fund_name': portfolio_evaluation[i]['name'],
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
112
                'status': portfolio_evaluation[i]['status'],
113
                'evaluation': portfolio_evaluation[i]['data'],
114
                'radar_chart_path': res[i]
115 116
            })

pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
117 118 119
    def get_old_compare_pic(self):
        """旧收益比较"""
        self.suggestions_result, self.suggestions_result_asset, self.return_compare_data,\
赵杰's avatar
赵杰 committed
120
        self.indicator_compare, self.new_group_evaluation = self.portfolio_diagnose.new_evaluation("default", self.d, self.user_customer)
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
121
        self.old_return_compare_pic = draw_old_combination_chart(self.return_compare_data["xlabels"], self.return_compare_data["origin_combination"], self.return_compare_data["index"])
122

pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
123 124 125 126
    def get_transfer_suggestions(self):
        """新收益比较,调仓建议"""
        self.return_compare_pic = draw_combination_chart(self.return_compare_data["xlabels"], self.return_compare_data["new_combination"],
                                                         self.return_compare_data["origin_combination"], self.return_compare_data["index"])
127 128 129

    def get_old_correlation(self):
        """旧相关性分析."""
赵杰's avatar
赵杰 committed
130
        old_correlation = self.portfolio_diagnose.old_correlation
131 132 133 134
        old_correlation_columns = old_correlation.columns.tolist()
        old_correlation_values = old_correlation.values.tolist()
        self.old_correlation = list(zip(range(1, len(old_correlation_columns)+1), old_correlation_columns, old_correlation_values))

pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
135 136
    def get_new_correlation(self):
        """新相关性分析."""
赵杰's avatar
赵杰 committed
137
        new_correlation = self.portfolio_diagnose.new_correlation
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
138 139 140 141
        new_correlation_columns = new_correlation.columns.tolist()
        new_correlation_values = new_correlation.values.tolist()
        self.new_correlation = list(zip(range(1, len(new_correlation_columns)+1), new_correlation_columns, new_correlation_values))

142 143 144 145
    def propose_fund(self):
        """新增基金"""
        # 优化组合建议1 -- 新增基金
        self.propose_fund_data_list = []
赵杰's avatar
赵杰 committed
146 147
        propose_fund_evaluation = self.portfolio_diagnose.propose_fund_evaluation()
        propose_radar_chart_data = self.portfolio_diagnose.propose_fund_radar()
148 149 150
        with futures.ProcessPoolExecutor(os.cpu_count()) as executor:
            res = executor.map(gen_radar_chart, propose_radar_chart_data)
        res = list(res)
151 152 153
        for i in range(len(propose_fund_evaluation)):
            self.propose_fund_data_list.append({
                'fund_name': propose_fund_evaluation[i]['name'],
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
154
                'status': '增仓',
155
                'evaluation': propose_fund_evaluation[i]['data'],
156
                'radar_chart_path': res[i]
157
            })
158 159 160 161 162 163 164
        # for i in range(len(propose_fund_evaluation)):
        #     self.propose_fund_data_list.append({
        #         'fund_name': propose_fund_evaluation[i]['name'],
        #         'status': '增仓',
        #         'evaluation': propose_fund_evaluation[i]['data'],
        #         'radar_chart_path': gen_radar_chart(propose_radar_chart_data[i])
        #     })
165 166 167

    def objectives_performance(self, group_result):
        """目标与业绩"""
168

pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
169
        self.totoal_rate_of_return = round((group_result['cumulative_return']-1)*100, 2)       # 成立以来累计收益率
170 171 172 173
        self.annualised_return = round(group_result["return_ratio_year"]*100, 2)     # 年化收益率
        self.volatility = round(group_result["volatility"]*100, 2)
        self.max_withdrawal = round(group_result["max_drawdown"][0]*100, 2)
        self.sharpe_ratio = round(group_result["sharpe"], 2)
赵杰's avatar
赵杰 committed
174
        self.cost_of_investment = round(group_result["total_cost"]/10000.0, 2)    # 投资成本
175 176 177 178 179 180 181 182
        self.index_section_return = round((group_result["index_result"]["return_ratio"]-1)*100, 2)
        self.index_annualised_return = round(group_result["index_result"]["return_ratio_year"]*100, 2)     # 年化收益率
        self.index_volatility = round(group_result["index_result"]["volatility"]*100, 2)
        self.index_max_withdrawal = round(group_result["index_result"]["max_drawdown"][0]*100, 2)
        self.index_sharpe_ratio = round(group_result["index_result"]["sharpe"], 2)

        self.group_nav_info = group_result["group_nav_info"]
        self.group_hoding_info = group_result["group_hoding_info"]
赵杰's avatar
赵杰 committed
183
        self.group_hoding_info_total = group_result["group_hoding_info_total"]
184 185 186 187


    def render_data(self):
        # 全部数据
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
188
        data = {
189 190 191 192 193 194 195 196 197 198 199 200 201
                # 封面 值为None不不显示,为block显示
                'box0': 'block',
                # 目录
                'box1': 'block',
                # 投资总览
                'box2': 'block',
                # 目标与业绩
                'box3': 'block',
                # 业绩的明细
                'box4': 'block',
                # 个基点评
                'box5': 'block',
                # 优化组合建议
pengxiong's avatar
pengxiong committed
202
                'box6': None,
203
                # 新增基金
pengxiong's avatar
pengxiong committed
204
                'box7': None,
205 206
                # 结尾
                'box8': 'block',
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
207 208
                'cover_back': template_folder + '/v2/img/cover-back.png',
                'logo': template_folder + '/v2/img/logo.png',
209
                'scene': template_folder + '/v2/img/scene.png',
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
210 211 212
                'team': template_folder + '/v2/img/team.png',
                'customer_name': self.customer_name,
                'customer_gender': '女',
213
                'year_month': self.user_customer.month_start_date.strftime("%Y-%m"),
214
                'month': self.user_customer.month_start_date.strftime("%m"),
215
                'start_date': self.user_customer.start_date.strftime("%Y-%m-%d"),
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
216
                'ifa_company': '飞度工作室',
217 218
                'title': '10月综述',
                'brand_name': '小飞象<br>工作室',
219
                'customer_old': 42, 'customer_level': '平衡型',
赵杰's avatar
赵杰 committed
220
                # 'new_evaluation': self.new_evaluation,
221 222
                'position_years': '5年', 'planned_allocation_amount': 2000.00,
                'now_allocation_amount': self.total_cost, 'now_yield': self.now_yield, 'index_yield': self.index_yield,
赵杰's avatar
赵杰 committed
223
                'expected_yield': 20, 'now_annualised_return': self.now_annualised_return,
224 225 226 227 228 229
                '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,
                'totoal_rate_of_return': self.totoal_rate_of_return,
                'month_rise': self.month_rise, 'year_totoal_rate_of_return': self.year_totoal_rate_of_return,
                'annualised_return': self.annualised_return, 'cost_of_investment': self.cost_of_investment,
                'final_balance': self.final_balance, 'total_profit': self.total_profit,
230
                'latest_worth_day': self.user_customer.last_nav_date,
231 232 233 234 235 236 237 238 239

                'index_comparison': {'section_return': self.totoal_rate_of_return, 'annualized_returns': self.annualised_return,
                                     'volatility': self.volatility, 'max_withdrawal': self.max_withdrawal,
                                     'sharpe_ratio': self.sharpe_ratio},
                'index_comparison_500': {'section_return': self.index_section_return,
                                         'annualized_returns': self.index_annualised_return,
                                         'volatility': self.index_volatility, 'max_withdrawal': self.index_max_withdrawal,
                                         'sharpe_ratio': self.index_sharpe_ratio},
                'monthly_return_performance_pic': self.monthly_return_performance_pic,
240
                'monthly_table_return': self.monthly_table_return,
241 242
                'group_nav_info': self.group_nav_info,
                'group_hoding_info': self.group_hoding_info,
赵杰's avatar
赵杰 committed
243
                'group_hoding_info_total': self.group_hoding_info_total,
244 245
                'old_evaluation': self.old_evaluation,
                'contribution_decomposition': self.contribution_decomposition,
246
                'single_fund_data_list': self.single_fund_data_list,
247
                'old_correlation': self.old_correlation,
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
248
                'new_correlation': self.new_correlation,
赵杰's avatar
赵杰 committed
249 250
                'propose_fund_data_list': self.propose_fund_data_list,
                'suggestions_result': self.suggestions_result,
赵杰's avatar
赵杰 committed
251
                'suggestions_result_asset': self.suggestions_result_asset,
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
252
                'old_return_compare_pic': self.old_return_compare_pic,
253
                'return_compare_pic': self.return_compare_pic,
赵杰's avatar
赵杰 committed
254 255 256
                'indicator_compare': self.indicator_compare,
                'new_group_evaluation': self.new_group_evaluation

257 258 259
                }
        # 开始渲染html模板
        env = Environment(loader=PackageLoader('app', 'templates'))  # 创建一个包加载器对象
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
260 261
        # template = env.get_template('monthReport.html')  # 获取一个模板文件
        template = env.get_template('/v2/monthReportV2.html')  # 获取一个模板文件
262 263
        monthReport_html = template.render(data)  # 渲染
        # 保存 monthReport_html
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
264 265 266 267
        # save_file = "app/html/monthReport.html"
        # with open(save_file, 'w', encoding="utf-8") as f:
        #     f.write(monthReport_html)

pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
268 269 270
        # save_file = "app/html/v2/monthReportV2.html"
        # with open(save_file, 'w', encoding="utf-8") as f:
        #     f.write(monthReport_html)
pengxiong@wealthgrow.cn's avatar
pengxiong@wealthgrow.cn committed
271
        html_to_pdf(monthReport_html, pdf_folder + self.pdf_name)
272 273


274 275 276

if __name__ == '__main__':
    start = time.time()
277
    DataIntegrate(ifa_id='USER_INFO15916072577875', customer_id='6716613804966817792')
278
    print('耗时{}秒'.format(round(time.time()-start, 2)))