Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Sign in
Toggle navigation
F
fund_report
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
彭熊
fund_report
Commits
fdc3475f
Commit
fdc3475f
authored
Dec 10, 2020
by
pengxiong
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dev' of
http://47.100.44.39:10001/pengxiong/fund_report
into dev
parents
aded976b
e027a0cb
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
2606 additions
and
1187 deletions
+2606
-1187
evaluation.csv
app/service/evaluation.csv
+16
-0
portfolio_diagnose.py
app/service/portfolio_diagnose.py
+31
-19
monthReportV2.1.html
app/templates/v2/monthReportV2.1.html
+2241
-0
jinjia2html_v2.py
app/utils/jinjia2html_v2.py
+318
-0
portfolio_diagnose.py
portfolio_diagnose.py
+0
-1168
No files found.
app/service/evaluation.csv
0 → 100644
View file @
fdc3475f
HF00002JJ2,11月下半月,伴随美国大选形势明朗化,以及美元持续走弱,国内经济持续复苏等综合因素影响,商品和股市都持续走强。商品方面受美元因素影响较大的有色走势更强,股指期货方面由于市场风格转向周期和价值股,IH及IF走势更强。远澜商品组合中趋势,均值回复,量价截面和基本面量化等子策略皆不同程度获利,股指组合中量价和基本面量化择时策略也都小幅盈利。
HF00002G4A,本月市场环境对基金期权套利策略影响不大,整个11月表现为稳定增长。
HF00006693,目前仓位75成,主要配置于食品饮料(7.77%),TMT(17.22%)、医药生物(39.26%)、休闲服务(6.55%)、电力设备(4.68%)。
HF00006BGS,11月份月度涨幅0.59%,成立以来跌幅12.63%。市场轮动加速、 强势股快速回调,导致策略超额不理想。针对近期产品的回撤情况,无量投研团队也在日以继夜的加强研究分析,不断总结经验以求更好适应当下市场。无量逐步排查并解决了一些交易及策略方面存在的问题,并更新了一些低频因子,体现在业绩上还需要一些时间。
HF00006AZF,权益类:仍然持有基本面长期看好的先进制造业类股票,期待迎来戴维斯双击的 上涨,同时用股指期货期权对冲指数风险,整体权益类资产保持净多仓。 商品类:由空翻多,不过会加入跨品种之间的对冲保护。 债券类:大幅减仓,等待企稳后逐步加回仓位。本月收益主要由商品类资产贡献较多。
HF0000681Q,市场从年初以消费、医药、科技板块跑出较长时间的一波行情之后,9月10月经历了市场的调整,11月份之后,A股市场处于震荡上行状态,市场出现各个板块的风格不断快速切换,给阿尔法策略短期带来了较大的压力。另一方面,股指基差收敛,期货价格上升,但对于目前已经持有的股指空头来说,会造成额外的亏损。目前跟踪走势表现正常。
HF00004RHP,本月通过到期兑付、出售获得较多的流动性,并把握住了恐慌波动带来的市场投资良机, 获利了结部分乳业可交换债、全部汽车零部件行业转债;旅游行业公司债完成兑付,文化传媒行业公司债完成部分兑付;加仓建筑环保行业转债、电磁线行业转债,新增铝加工添加剂行业转债;新增环保行业、煤炭行业以及电解铝行业债券。目前仓位94成,重点行业主要分布在地产、电解铝、建筑环保、钢铁、城投。
HF00005DBQ,"本月通过到期兑付、出售获得较多的流动性,并把握住了恐慌波动带来的市场投资良机, 获利了结全部汽车零部件行业转债、服纺行业转债;旅游行业公司债完成兑付,文化传媒行业公司债完成部分
兑付;加仓建筑环保行业转债、电磁线行业转债,新增铝加工添加剂行业转债;新增环保行业、煤炭行业以及电解铝行业债券。目前仓位92成,重点行业主要分布在地产、钢铁、电解铝、煤炭。"
HF00005ZUB,本月通过到期兑付、出售获得较多的流动性,并把握住了恐慌波动带来的市场投资良机, 获利了结全部汽车零部件行业转债、服纺行业转债;旅游行业公司债完成兑付,文化传媒行业公司债完成部分兑付;加仓建筑环保行业转债、电磁线行业转债,新增铝加工添加剂行业转债;新增环保行业、煤炭行业以及电解铝行业债券。目前仓位9成,重点行业主要分布在地产、钢铁、电解铝、建筑环保。
HF00006641,业绩归因方面:本月打新收益0.22%,中高频CTA收益-0.315%,中性策略收益-2.1268%。因11月市场风格转变剧烈,量价因子阶段性失效,导致中性策略发生亏损。近期商品期货中亏损较大的板块是油脂油料和贵金属板块,由于思勰做的是短周期CTA策略,交易级别在小时级,因此更加关注商品期货在日内流畅的波动,然而遇到如开盘跳空或是日内的来回拉锯行情亦或是一些突发事件导致的走势反转,就很难捕捉到交易机会。
HF00006GNQ,目前本策略全部资金进行高频CTA运作,运作正常。
HF00005QOM,本月通过到期兑付、出售获得较多的流动性,并把握住了恐慌波动带来的市场投资良机,获利了结全部汽车零部件行业转债、服纺行业转债;旅游行业公司债完成兑付,文化传媒行业公司债完成部分兑付;加仓建筑环保行业转债、电磁线行业转债,新增铝加工添加剂行业转债;新增环保行业、煤炭行业以及电解铝行业债券。目前仓位9成,重点行业主要分布在地产、煤炭、城投、建筑环保。
HF00006DLK,11月下半月,伴随美国大选形势明朗化,以及美元持续走弱,国内经济持续复苏等综合因素影响,商品和股市都持续走强,很多板块间都有较为明显的趋势,商品中是有色板块,而股市中是周期和价值股。市场环境对于中长周期的象限策略来说偏友好。整个11月的涨幅较可观。
HF00006FEU,11月下半月,伴随美国大选形势明朗化,以及美元持续走弱,国内经济持续复苏等综合因素影响,商品和股市都持续走强,很多板块间都有较为明显的趋势,商品中是有色板块,而股市中则是周期和价值股,大多数量化选股策略由于量价因子失效均出现负超额,黑翼的CTA与指增组合效果表现要优于市场上大多纯指数增强策略。
HF00005AFK,疫情以及美国大选等扰动因素下,跨境价差套利策略较难做,为控制波动风险,适当降低策略配比,加大低风险的股指期现套利。
\ No newline at end of file
app/service/portfolio_diagnose.py
View file @
fdc3475f
...
...
@@ -1091,20 +1091,31 @@ class PortfolioDiagnose(object):
evaluation
=
choose_bad_evaluation
(
data
)
ret
=
[]
i
=
1
for
k
,
v
in
evaluation
.
items
():
single_sentence
=
str
(
i
)
+
"、"
+
sentence
[
k
]
%
translate_single
(
content
,
k
,
v
)
ret
.
append
(
single_sentence
)
i
+=
1
fund_name
=
get_fund_name
(
fund_id
)
.
values
[
0
][
0
]
if
not
ret
:
try
:
default_evaluation
=
pd
.
read_csv
(
"evaluation.csv"
,
encoding
=
'utf-8'
,
names
=
[
'fund_id'
,
'eval'
])
if
default_evaluation
[
default_evaluation
[
'fund_id'
]
==
fund_id
][
'eval'
]
.
values
[
0
]:
ret
.
append
(
'1、'
+
default_evaluation
[
default_evaluation
[
'fund_id'
]
==
fund_id
][
'eval'
]
.
values
[
0
])
evaluation_dict
=
{
'name'
:
fund_name
,
'data'
:
ret
}
if
objective
:
if
fund_id
in
self
.
abandon_fund_score
+
self
.
abandon_fund_corr
:
evaluation_dict
[
'status'
]
=
"换仓"
elif
fund_id
in
self
.
portfolio
:
evaluation_dict
[
'status'
]
=
"保留"
else
:
evaluation_dict
[
'status'
]
=
""
return
evaluation_dict
except
Exception
:
pass
i
=
1
for
k
,
v
in
evaluation
.
items
():
single_sentence
=
str
(
i
)
+
"、"
+
sentence
[
k
]
%
translate_single
(
content
,
k
,
v
)
ret
.
append
(
single_sentence
)
i
+=
1
evaluation_dict
=
{
'name'
:
fund_name
,
'data'
:
ret
}
if
objective
:
...
...
@@ -1155,14 +1166,15 @@ class PortfolioDiagnose(object):
return
radar_data
portfolio
=
[
'HF00002JJ2'
,
'HF00005DBQ'
,
'HF0000681Q'
,
'HF00006693'
,
'HF00006AZF'
,
'HF00006BGS'
]
portfolio_diagnose
=
PortfolioDiagnose
(
client_type
=
1
,
portfolio
=
portfolio
,
invest_amount
=
10000000
)
portfolio_diagnose
.
optimize
()
if
__name__
==
'__main__'
:
print
(
portfolio_diagnose
.
single_fund_radar
())
print
(
portfolio_diagnose
.
propose_fund_radar
())
print
(
portfolio_diagnose
.
old_portfolio_evaluation
())
print
(
'旧组合相关性:'
,
portfolio_diagnose
.
old_correlation
)
print
(
'新组合相关性:'
,
portfolio_diagnose
.
new_correlation
)
print
(
'旧组合个基评价:'
,
portfolio_diagnose
.
old_portfolio_evaluation
())
print
(
'新组合个基评价:'
,
portfolio_diagnose
.
propose_fund_evaluation
())
\ No newline at end of file
# portfolio = ['HF00002JJ2', 'HF00005DBQ', 'HF0000681Q', 'HF00006693', 'HF00006AZF', 'HF00006BGS']
# portfolio_diagnose = PortfolioDiagnose(client_type=1, portfolio=portfolio, invest_amount=10000000)
# portfolio_diagnose.optimize()
# if __name__ == '__main__':
# print(portfolio_diagnose.single_fund_radar())
# print(portfolio_diagnose.propose_fund_radar())
# print(portfolio_diagnose.old_portfolio_evaluation())
# print('旧组合相关性:', portfolio_diagnose.old_correlation)
# print('新组合相关性:', portfolio_diagnose.new_correlation)
# print('旧组合个基评价:', portfolio_diagnose.old_portfolio_evaluation())
# print('新组合个基评价:', portfolio_diagnose.propose_fund_evaluation())
# print(portfolio_diagnose.single_evaluation(fund_id='HF0000681Q'))
\ No newline at end of file
app/templates/v2/monthReportV2.1.html
0 → 100644
View file @
fdc3475f
<!doctype html>
<html
lang=
"en"
>
<head>
<meta
charset=
"UTF-8"
>
<style>
/*
* Prefixed by https://autoprefixer.github.io
* PostCSS: v7.0.29,
* Autoprefixer: v9.7.6
* Browsers: last 4 version
*/
.all
{
width
:
1200px
;
margin
:
0
auto
;
page-break-inside
:
avoid
;
}
.clearfix
:after
{
content
:
""
;
display
:
block
;
clear
:
both
;
overflow
:
hidden
;
}
.fl
{
float
:
left
;
}
.fr
{
float
:
right
;
}
.dtable
{
display
:
table
;
}
.dcell
{
display
:
table-cell
;
vertical-align
:
middle
;
}
/* 封面 */
.box0
{
display
:
{{
box0
}
}
;
position
:
relative
;
padding
:
234px
0
184px
0
;
}
.box0
.cover_head
{
position
:
absolute
;
top
:
45px
;
right
:
38px
;
}
.box0
.cover_head
.cover_logo
{
width
:
172px
;
height
:
52px
;
}
.box0
.cover_head
.cover_line
{
width
:
1px
;
height
:
34px
;
background
:
#10316E
;
margin
:
0
10px
0
10px
;
}
.box0
.cover_head
.cover_text
{
font-size
:
17px
;
line-height
:
23px
;
color
:
#B6172B
;
font-weight
:
bold
;
}
.box0
.cover_people
{
padding
:
0
38px
0
858px
;
}
.box0
.cover_people
.cover_pre
{
margin
:
0
20px
0
0
;
font-size
:
28px
;
line-height
:
40px
;
color
:
#999999
;
font-weight
:
bold
;
}
.box0
.cover_people
.cover_name
{
font-size
:
32px
;
line-height
:
45px
;
color
:
#B6172B
;
font-weight
:
bold
;
}
.box0
.cover_people
.cover_sir
{
font-size
:
28px
;
line-height
:
45px
;
color
:
#333333
;
font-weight
:
bold
;
}
.box0
.cover_back
{
display
:
block
;
width
:
100%
;
height
:
218px
;
}
.box0
.cover_date
{
padding
:
0
0
0
858px
;
}
.box0
.cover_date
.cover_time
{
display
:
inline-block
;
font-size
:
40px
;
line-height
:
66px
;
color
:
#ffffff
;
font-weight
:
bold
;
padding
:
0
66px
0
66px
;
background
:
#B6172B
;
-webkit-box-shadow
:
0px
10px
26px
0px
rgba
(
66
,
5
,
5
,
0.18
);
box-shadow
:
0px
10px
26px
0px
rgba
(
66
,
5
,
5
,
0.18
);
border
:
1px
solid
#979797
;
}
.box0
.cover_title
{
position
:
absolute
;
top
:
100px
;
left
:
211px
;
z-index
:
1
;
width
:
282px
;
height
:
514px
;
background
:
#B6172B
;
-webkit-box-shadow
:
0px
10px
26px
0px
rgba
(
66
,
5
,
5
,
0.44
);
box-shadow
:
0px
10px
26px
0px
rgba
(
66
,
5
,
5
,
0.44
);
border
:
1px
solid
#979797
;
}
.box0
.cover_title
.cover_title_text
{
padding
:
0
30px
0
50px
;
font-size
:
46px
;
line-height
:
61px
;
color
:
#ffffff
;
font-weight
:
bold
;
}
.box_line
{
height
:
15px
;
background
:
#F1F1F1
;
}
/* 目录 */
.box1
{
display
:
{{
box1
}
}
;
position
:
relative
;
padding
:
150px
0
200px
36px
;
}
.box1
.catalog_line
{
position
:
absolute
;
top
:
0
;
left
:
0
;
width
:
36px
;
height
:
100%
;
background
:
#B6172B
;
}
.box1
.catalog_box
.catalog_item
:first-child
{
width
:
562px
;
padding
:
0
46px
0
46px
;
}
.box1
.catalog_box
.catalog_item
.catalog_en
{
font-size
:
72px
;
line-height
:
77px
;
color
:
#333333
;
font-weight
:
bold
;
opacity
:
0.45
;
}
.box1
.catalog_box
.catalog_item
.catalog_ch
{
margin
:
30px
0
0
0
;
font-size
:
58px
;
line-height
:
77px
;
color
:
#333333
;
font-weight
:
bold
;
}
.box1
.catalog_box
.catalog_item
.catalog_li
{
position
:
relative
;
}
.box1
.catalog_box
.catalog_item
.catalog_li
.catalog_dot
{
position
:
absolute
;
top
:
32px
;
left
:
0
;
width
:
16px
;
height
:
16px
;
background
:
#D7D7D7
;
border-radius
:
50%
;
}
.box1
.catalog_box
.catalog_item
.catalog_li
.catalog_name
{
padding
:
0
0
0
40px
;
font-size
:
32px
;
line-height
:
77px
;
color
:
#333333
;
font-weight
:
bold
;
}
/* 页眉 */
.page
{
padding
:
54px
34px
10px
34px
;
width
:
100%
;
border-bottom
:
1px
solid
#F1F1F1
;
}
.page
.page_title
{
width
:
880px
;
font-size
:
40px
;
line-height
:
56px
;
color
:
#333333
;
font-weight
:
bold
;
}
.page
.page_head
.page_logo
{
width
:
172px
;
height
:
52px
;
}
.page
.page_head
.page_line
{
width
:
1px
;
height
:
34px
;
background
:
#10316E
;
margin
:
0
10px
0
10px
;
}
.page
.page_head
.page_text
{
font-size
:
17px
;
line-height
:
23px
;
color
:
#B6172B
;
font-weight
:
bold
;
white-space
:
nowrap
;
}
/* 投资总览 */
.box2
{
display
:
{{
box2
}
}
;
}
.box2
.box2_content
{
padding
:
47px
34px
61px
34px
;
page-break-after
:
always
;
}
/* 表格样式1 */
.tss1
{
margin
:
30px
0
0
0
;
}
.tss1
.tss1_title
{
font-size
:
24px
;
line-height
:
33px
;
color
:
#333333
;
font-weight
:
bold
;
margin
:
0
0
15px
0
;
}
.tss1
.tss1_table
{
width
:
100%
;
border-collapse
:
collapse
;
}
.tss1
.tss1_table
tr
{
border-bottom
:
2px
solid
#FFFFFF
;
background
:
#F1F1F1
;
width
:
100%
;
}
.tss1
.tss1_table
tr
td
{
width
:
25%
;
padding
:
12px
26px
12px
26px
;
font-size
:
16px
;
line-height
:
22px
;
color
:
#333333
;
font-weight
:
bold
;
}
.tss1
.tss1_table
tr
td
.red
{
color
:
#D10000
;
}
.tss1
.tss1_table
tr
td
.green
{
color
:
#129298
;
}
/* 表格样式2 */
.tss2
{
margin
:
40px
0
0
0
;
}
.tss2
.tss2_title
{
font-size
:
24px
;
line-height
:
33px
;
color
:
#333333
;
font-weight
:
bold
;
margin
:
0
0
15px
0
;
}
.tss2
.tss2_content
{
margin
:
18px
0
0
0
;
border
:
1px
solid
#E4E4E4
;
}
.tss2
.tss2_content
.tss2_img
{
width
:
100%
;
}
/* 表格样式3 */
.tss3
{
margin
:
40px
0
0
0
;
}
.tss3
.tss3_head
{
width
:
100%
;
}
.tss3
.tss3_head
.tss3_title
{
font-size
:
24px
;
line-height
:
33px
;
color
:
#333333
;
font-weight
:
bold
;
margin
:
0
0
15px
0
;
}
.tss3
.tss3_head
.tss3_title
.tss3_start_time
{
font-size
:
18px
;
line-height
:
33px
;
color
:
#666666
;
font-weight
:
normal
;
}
.tss3
.tss3_head
.tss3_now_time
{
font-size
:
14px
;
line-height
:
20px
;
color
:
#333333
;
text-align
:
right
;
}
.tss3
.tss3_tag
{
position
:
absolute
;
padding
:
0
16px
0
26px
;
font-size
:
16px
;
line-height
:
30px
;
color
:
#ffffff
;
background
:
#A2A2A2
;
}
.tss3
.tss3_tag
.tss3_tri
{
position
:
absolute
;
top
:
0
;
right
:
-10px
;
border-top
:
15px
solid
#A2A2A2
;
border-bottom
:
15px
solid
transparent
;
border-left
:
5px
solid
#A2A2A2
;
border-right
:
5px
solid
transparent
;
}
.tss3
table
{
margin
:
24px
0
0
0
;
width
:
100%
;
border
:
none
;
border-color
:
rgba
(
151
,
151
,
151
,
0.18
);
border-collapse
:
collapse
;
}
.tss3
table
tr
{
position
:
relative
;
font-size
:
14px
;
line-height
:
20px
;
color
:
#333333
;
text-align
:
center
;
vertical-align
:
middle
;
}
.tss3
table
tr
.yellow
{
background
:
#FFFAF2
;
}
.tss3
table
tr
.gray
{
background
:
#F1F1F1
;
}
.tss3
table
tr
th
{
padding
:
14px
0
14px
0
;
background
:
#F1F1F1
;
}
.tss3
table
tr
td
{
padding
:
14px
0
14px
0
;
}
.tss3
table
tr
td
.gray
{
background
:
#F1F1F1
;
}
.tss3
table
tr
td
.text_red
{
color
:
#D00000
;
}
.tss3
table
tr
td
.text_green
{
color
:
#22A236
;
}
.tss3
table
tr
td
.summary
{
font-size
:
18px
;
line-height
:
25px
;
color
:
#333333
;
font-weight
:
bold
;
}
.tss3
.tss3_tip
{
margin
:
10px
0
0
0
;
font-size
:
12px
;
line-height
:
17px
;
color
:
#333333
;
}
/* 目标与业绩 */
.box3
{
display
:
{{
box3
}
}
;
}
.box3
.box3_content
{
padding
:
47px
34px
61px
34px
;
page-break-after
:
always
;
}
/* 收益比较、相关性分析 */
.par
{
margin
:
47px
0
0
0
;
width
:
100%
;
}
.par
.par_item
{
width
:
540px
;
}
.par
.par_item
.par_title
{
font-size
:
24px
;
line-height
:
33px
;
color
:
#333333
;
font-weight
:
bold
;
margin
:
0
0
15px
0
;
}
.par
.par_item
.par_content
{
margin
:
18px
0
0
0
;
border
:
1px
solid
#E4E4E4
;
}
.par
.par_item
.par_content.relative_chart
{
padding
:
27px
30px
40px
30px
;
}
.par
.par_item
.par_content.relative_chart
table
{
width
:
100%
;
border-collapse
:
collapse
;
border
:
none
;
border-color
:
#D8D8D8
;
}
.par
.par_item
.par_content.relative_chart
table
td
{
padding
:
14px
0
14px
0
;
text-align
:
center
;
}
.par
.par_item
.par_content
.par_img
{
width
:
100%
;
}
.rcc_left
{
width
:
10%
;
-webkit-box-orient
:
vertical
;
-webkit-box-direction
:
normal
;
-ms-flex-direction
:
column
;
flex-direction
:
column
;
}
.rcc_column
{
border
:
1px
solid
transparent
;
}
.rcc_n
{
border
:
1px
solid
transparent
;
margin
:
9px
;
width
:
20px
;
height
:
20px
;
border-radius
:
50%
;
background
:
#999999
;
font-size
:
12px
;
line-height
:
20px
;
color
:
#FFFFFF
;
text-align
:
center
;
}
.rcc_right
{
width
:
90%
;
}
.rcc_index
{
display
:
inline-block
;
margin
:
0
auto
;
width
:
20px
;
height
:
20px
;
border-radius
:
50%
;
background
:
rgba
(
53
,
63
,
83
,
0.5
);
font-size
:
12px
;
line-height
:
20px
;
color
:
#FFFFFF
;
text-align
:
center
;
}
.rcc_number
{
font-size
:
12px
;
line-height
:
18px
;
color
:
#666666
;
}
.rc_tooltip
{
margin
:
16px
0
0
0
;
text-align
:
center
;
}
.rct_color
{
display
:
inline-block
;
}
.rct_color_item
{
border
:
1
PX
solid
#FFFFFF
;
width
:
38px
;
height
:
11px
;
}
.rtc_number_item
{
margin
:
0
12px
0
0
;
font-size
:
12px
;
line-height
:
18px
;
color
:
#666666
;
}
.rct_number
{
display
:
inline-block
;
}
.rc_label
{
margin
:
16px
14px
0
14px
;
-ms-flex-wrap
:
wrap
;
flex-wrap
:
wrap
;
}
.rcl_item
{
width
:
50%
;
position
:
relative
;
margin
:
4px
0
4px
0
;
}
.rcl_item_number
{
position
:
absolute
;
top
:
2px
;
left
:
0
;
margin
:
0
8px
0
0
;
width
:
20px
;
height
:
20px
;
border-radius
:
50%
;
background
:
#999999
;
font-size
:
12px
;
line-height
:
20px
;
color
:
#FFFFFF
;
text-align
:
center
;
}
.rcl_item_name
{
padding
:
0
10px
0
30px
;
font-size
:
16px
;
line-height
:
24px
;
color
:
#333333
;
}
.level_color1
{
background
:
#993612
;
color
:
#993612
;
}
.level_color2
{
background
:
#C58E7B
;
color
:
#C58E7B
;
}
.level_color3
{
background
:
#E9D4CD
;
color
:
#E9D4CD
;
}
.level_color4
{
background
:
#C4E4E6
;
color
:
#C4E4E6
;
}
.level_color5
{
background
:
#87C8CB
;
color
:
#87C8CB
;
}
.level_color6
{
background
:
#129298
;
color
:
#129298
;
}
/* 业绩的明细 */
.box4
{
display
:
{{
box4
}
}
;
}
.box4
.box4_content
{
padding
:
47px
34px
61px
34px
;
page-break-after
:
always
;
}
/* 个基点评 */
.box5
{
display
:
{{
box5
}
}
;
}
.box5
.box5_content
{
padding
:
47px
34px
61px
34px
;
page-break-after
:
always
;
}
.geji_list_wrap
.self_item
{
background
:
#FFFFFF
;
-webkit-box-shadow
:
0px
8px
9px
0px
rgba
(
0
,
0
,
0
,
0.05
);
box-shadow
:
0px
8px
9px
0px
rgba
(
0
,
0
,
0
,
0.05
);
border-radius
:
8px
;
border
:
1px
solid
#E4E4E4
;
margin
:
0
0
34px
0
;
}
.geji_list_wrap
.self_item
:last-child
{
margin
:
0
0
0
0
;
}
.geji_list_wrap
.self_item
.self_item_left
{
width
:
710px
;
padding
:
35px
36px
35px
0
;
}
.geji_list_wrap
.self_item
.self_item_left
.self_header
{
display
:
inline-block
;
font-size
:
0
;
}
.geji_list_wrap
.self_item
.self_item_left
.self_header
.self_title
{
position
:
relative
;
padding
:
0
10px
0
20px
;
font-size
:
24px
;
line-height
:
33px
;
color
:
#333333
;
font-weight
:
bold
;
}
.geji_list_wrap
.self_item
.self_item_left
.self_header
.self_title
.self_title_tri
{
width
:
0
;
height
:
0
;
border-bottom
:
20px
solid
transparent
;
border-top
:
20px
solid
#6C71AA
;
border-right
:
5px
solid
transparent
;
border-left
:
5px
solid
#6C71AA
;
position
:
absolute
;
right
:
-10px
;
top
:
0
;
}
.geji_list_wrap
.self_item
.self_item_left
.self_header
.self_type
{
margin
:
4px
0
0
0
;
padding
:
0
10px
0
10px
;
font-size
:
18px
;
line-height
:
26px
;
color
:
#4C4C4C
;
font-weight
:
bold
;
background
:
#E5E3E3
;
}
.geji_list_wrap
.self_item
.self_item_left
.self_header
.self_type.red
{
color
:
#983612
;
background
:
#FFEAE2
;
}
.geji_list_wrap
.self_item
.self_item_left
.self_header
.self_type.green
{
color
:
#22999F
;
background
:
#E2F7F8
;
}
.geji_list_wrap
.self_item
.self_item_left
.self_description
{
margin
:
20px
0
0
20px
;
}
.geji_list_wrap
.self_item
.self_item_left
.self_description
.self_description_item
{
position
:
relative
;
margin
:
0
0
10px
0
;
}
.geji_list_wrap
.self_item
.self_item_left
.self_description
.self_description_item
:last-child
{
margin
:
0
;
}
.geji_list_wrap
.self_item
.self_item_left
.self_description
.self_description_item
.self_description_dot
{
position
:
absolute
;
left
:
0
;
top
:
8px
;
width
:
6px
;
height
:
6px
;
border-radius
:
50%
;
background
:
#CBCBCB
;
}
.geji_list_wrap
.self_item
.self_item_left
.self_description
.self_description_item
.self_description_text
{
font-size
:
16px
;
line-height
:
22px
;
color
:
#666666
;
text-align
:
justify
;
padding-left
:
18px
;
}
.geji_list_wrap
.self_item
.self_item_left
.self_description
.self_description_item
.self_description_text
.self_description_red
{
color
:
#983612
;
}
.geji_list_wrap
.self_item
.self_item_left
.self_description
.self_description_item
.self_description_text
.self_description_green
{
color
:
#129298
;
}
.geji_list_wrap
.self_item
.self_item_right
{
margin
:
30px
26px
30px
26px
;
}
.geji_list_wrap
.self_item
.self_item_right
.self_img
{
width
:
100%
;
}
/*持仓组合点评*/
.target_comment
{
margin
:
36px
0
0
0
;
}
.target_comment
.comment_title
{
display
:
inline-block
;
position
:
relative
;
padding
:
4px
10px
4px
20px
;
border-radius
:
8px
0
0px
0px
;
background
:
#B6172B
;
font-size
:
24px
;
line-height
:
33px
;
color
:
#FFFFFF
;
}
.target_comment
.comment_title
.comment_tri
{
width
:
0
;
height
:
0
;
border-top
:
20px
solid
transparent
;
border-bottom
:
20px
solid
#B6172B
;
border-left
:
10px
solid
#B6172B
;
border-right
:
10px
solid
transparent
;
position
:
absolute
;
right
:
-20px
;
bottom
:
0
;
}
.target_comment
.comment_content
{
padding
:
39px
26px
39px
26px
;
background
:
#F7F7F7
;
}
.target_comment
.comment_content
.comment_item
{
width
:
100%
;
position
:
relative
;
}
.target_comment
.comment_content
.comment_dot
{
position
:
absolute
;
top
:
16px
;
left
:
0px
;
width
:
8px
;
height
:
8px
;
border-radius
:
50%
;
background
:
#666666
;
}
.target_comment
.comment_content
.comment_text
{
padding-left
:
24px
;
font-size
:
18px
;
line-height
:
42px
;
color
:
#666666
;
}
.target_comment
.comment_content
.comment_text
.comment_tag_red
{
color
:
#A75435
;
}
.target_comment
.comment_content
.comment_text
.comment_tag_green
{
color
:
#129298
;
}
/* 优化组合建议 */
.box6
{
display
:
{{
box6
}
}
;
}
.box6
.box6_content
{
padding
:
47px
34px
61px
34px
;
page-break-after
:
always
;
}
/* 新增基金 */
.box7
{
display
:
{{
box7
}
}
;
}
.box7
.box7_content
{
padding
:
47px
34px
61px
34px
;
page-break-after
:
always
;
}
/* 结尾 */
.box8
{
display
:
{{
box8
}
}
;
}
.box8
.box8_content
{
padding
:
60px
0
60px
0
;
}
.financial_show
.financial_left
{
width
:
763px
;
background
:
#B6172B
;
padding
:
58px
0
48px
0
;
}
.financial_show
.financial_left
.financial_scene
{
border-top
:
1px
solid
#B6172B
;
border-bottom
:
1px
solid
#B6172B
;
position
:
relative
;
height
:
305px
;
}
.financial_show
.financial_left
.financial_scene
.financial_scene_img
{
position
:
absolute
;
top
:
0
;
left
:
0
;
width
:
100%
;
height
:
100%
;
-o-object-fit
:
cover
;
object-fit
:
cover
;
}
.financial_show
.financial_left
.financial_scene
.financial_scene_text
{
margin
:
31px
77px
0
79px
;
font-size
:
26px
;
line-height
:
49px
;
color
:
#FFFFFF
;
letter-spacing
:
4px
;
position
:
relative
;
z-index
:
1
;
}
.financial_show
.financial_left
.financial_scene
.financial_scene_author
{
margin
:
0
77px
34px
79px
;
font-size
:
26px
;
line-height
:
49px
;
color
:
#FFFFFF
;
text-align
:
right
;
position
:
relative
;
z-index
:
1
;
}
.financial_show
.financial_show_right
{
background
:
#F7F7F7
;
padding
:
58px
0
48px
0
;
}
.financial_show
.financial_show_right
.financial_team
{
height
:
305px
;
}
.financial_show
.financial_show_right
.financial_team
.financial_team_img
{
/*width: 100%;*/
/*height: 100%;*/
/*-o-object-fit: cover;*/
/*object-fit: cover;*/
width
:
auto
;
height
:
100%
;
-o-object-fit
:
cover
;
object-fit
:
cover
;
}
.statement_content
{
padding
:
27px
31px
0
31px
;
}
.statement_content
.statement_block
{
margin
:
0
0
20px
0
;
}
.statement_content
.statement_block
.statement_title
{
margin
:
0
0
10px
0
;
font-size
:
10px
;
line-height
:
27px
;
color
:
#717171
;
font-weight
:
bold
;
text-align
:
justify
;
}
.statement_content
.statement_block
.statement_p
{
margin
:
0
0
10px
0
;
font-size
:
10px
;
line-height
:
27px
;
color
:
#717171
;
text-align
:
justify
;
}
.statement_content
.statement_block
.statement_title2
{
font-size
:
10px
;
line-height
:
27px
;
color
:
#333333
;
font-weight
:
bold
;
text-align
:
justify
;
}
</style>
</head>
<body>
<div
class=
"all"
>
<!-- 封面 -->
<div
class=
"box0"
>
<div
class=
"cover_head dtable"
>
<div
class=
"dcell"
>
<img
src=
{{logo}}
alt=
""
class=
"cover_logo"
>
</div>
<div
class=
"dcell"
>
<div
class=
"cover_line"
></div>
</div>
<div
class=
"dcell"
>
<div
class=
"cover_text"
>
小飞象
<br>
工作室
</div>
</div>
</div>
<div
class=
"cover_people"
>
<span
class=
"cover_pre"
>
敬呈
</span>
<span
class=
"cover_name"
>
{{customer_name}}
</span>
<span
class=
"cover_sir"
>
客户
</span>
</div>
<img
src=
{{cover_back}}
alt=
""
class=
"cover_back"
>
<div
class=
"cover_date"
>
<div
class=
"cover_time"
>
{{year_month}}
</div>
</div>
<div
class=
"cover_title dtable"
>
<div
class=
"cover_title_text dcell"
>
资产
<br>
存续报告
</div>
</div>
</div>
<div
class=
"box_line"
></div>
<!-- 目录 -->
<div
class=
"box1"
>
<div
class=
"catalog_line"
></div>
<div
class=
"catalog_box dtable"
>
<div
class=
"catalog_item dcell"
>
<div
class=
"catalog_en"
>
Contents
</div>
<div
class=
"catalog_ch"
>
目录
</div>
</div>
<div
class=
"catalog_item dcell"
>
<div
class=
"catalog_li"
>
<div
class=
"catalog_dot"
></div>
<div
class=
"catalog_name"
>
投资总览
</div>
</div>
<div
class=
"catalog_li"
>
<div
class=
"catalog_dot"
></div>
<div
class=
"catalog_name"
>
目标与业绩
</div>
</div>
<div
class=
"catalog_li"
>
<div
class=
"catalog_dot"
></div>
<div
class=
"catalog_name"
>
业绩的明细
</div>
</div>
<!-- <div class="catalog_li">-->
<!-- <div class="catalog_dot"></div>-->
<!-- <div class="catalog_name">优化建议</div>-->
<!-- </div>-->
</div>
</div>
</div>
<div
class=
"box_line"
></div>
<!-- 投资总览 -->
<div
class=
"box2"
style=
"page-break-before:always;"
>
<div
class=
"page dtable"
>
<div
class=
"page_title dcell"
>
投资总览
</div>
<div
class=
"page_head dcell"
>
<div
class=
"dcell"
>
<img
src=
{{logo}}
alt=
""
class=
"page_logo"
>
</div>
<div
class=
"dcell"
>
<div
class=
"page_line"
></div>
</div>
<div
class=
"dcell"
>
<div
class=
"page_text"
>
{{brand_name}}
</div>
</div>
</div>
</div>
<div
class=
"box2_content"
>
<!-- 组合投资表现 -->
<div
class=
"tss1"
style=
"margin: 0;"
>
<div
class=
"tss1_title"
>
组合投资表现
</div>
<table
class=
"tss1_table"
>
<tr>
<td>
{%if month_rise>=0%}
本月涨幅:
<span
class=
"red"
>
{{month_rise}}%
</span>
{%else%}
本月涨幅:
<span
class=
"green"
>
{{month_rise}}%
</span>
{%endif%}
</td>
<td>
{%if now_month_income>=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%}
今年累计收益率:
<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%}
今年累计收益:
<span
class=
"red"
>
{{now_year_income}}元
</span>
{%else%}
今年累计收益:
<span
class=
"green"
>
{{now_year_income}}元
</span>
{%endif%}
</td>
</tr>
<tr>
<td>
{%if now_yield>=0%}
成立以来累计收益率:
<span
class=
"red"
>
{{now_yield}}%
</span>
{%else%}
成立以来累计收益率:
<span
class=
"green"
>
{{now_yield}}%
</span>
{%endif%}
</td>
<td>
{%if now_annualised_return>=0%}
年化收益率:
<span
class=
"red"
>
{{now_annualised_return}}%
</span>
{%else%}
年化收益率:
<span
class=
"green"
>
{{now_annualised_return}}%
</span>
{%endif%}
</td>
<td>
{%if now_withdrawal>=0%}
最大回撤:
<span
class=
"red"
>
{{now_withdrawal}}%
</span>
{%else%}
最大回撤:
<span
class=
"green"
>
{{now_withdrawal}}%
</span>
{%endif%}
</td>
<td>
</td>
</tr>
</table>
</div>
<!-- 资产盈亏情况 -->
<div
class=
"tss1"
>
<div
class=
"tss1_title"
>
资产盈亏情况
</div>
<table
class=
"tss1_table"
>
<tr>
<td>
投资成本:
<span
class=
"red"
>
{{now_allocation_amount}}元
</span>
</td>
<td>
{%if final_balance>=now_allocation_amount%}
期末资产:
<span
class=
"red"
>
{{final_balance}}元
</span>
{%else%}
期末资产:
<span
class=
"green"
>
{{final_balance}}元
</span>
{%endif%}
</td>
<td>
{%if total_profit>=0%}
累计盈利:
<span
class=
"red"
>
{{total_profit}}元
</span>
{%else%}
累计盈利:
<span
class=
"green"
>
{{total_profit}}元
</span>
{%endif%}
</td>
<td>
</td>
</tr>
</table>
</div>
<!-- 组合月度及累计回报率曲线 -->
<div
class=
"tss2"
>
<div
class=
"tss2_title"
>
组合月度及累计回报率曲线
</div>
<div
class=
"tss2_content"
>
<img
src=
{{monthly_return_performance_pic}}
alt=
""
class=
"tss2_img"
>
</div>
</div>
<!-- 组合月度及累计回报率曲线 -->
<div
class=
"tss3"
>
<div
class=
"tss3_head dtable"
>
<div
class=
"tss3_title dcell"
>
组合月度及累计回报率曲线
</div>
</div>
<table
border=
"1"
>
<tr>
<th>
年份
</th>
<th>
金额(万)
</th>
<th>
1月
</th>
<th>
2月
</th>
<th>
3月
</th>
<th>
4月
</th>
<th>
5月
</th>
<th>
6月
</th>
<th>
7月
</th>
<th>
8月
</th>
<th>
9月
</th>
<th>
10月
</th>
<th>
11月
</th>
<th>
12月
</th>
<!-- <th>-->
<!-- 累计/月均-->
<!-- </th>-->
</tr>
{%for key, value in monthly_table_return.items() %}
<tr
class=
"yellow"
>
<td
rowspan=
"2"
class=
"gray"
>
{{key}}
</td>
<td>
盈亏
</td>
<td
class=
"text_red"
>
{{value[1]["profit"]}}
</td>
<td
class=
"text_green"
>
{{value[2]["profit"]}}
</td>
<td>
{{value[3]["profit"]}}
</td>
<td>
{{value[4]["profit"]}}
</td>
<td>
{{value[5]["profit"]}}
</td>
<td>
{{value[6]["profit"]}}
</td>
<td>
{{value[7]["profit"]}}
</td>
<td>
{{value[8]["profit"]}}
</td>
<td>
{{value[9]["profit"]}}
</td>
<td>
{{value[10]["profit"]}}
</td>
<td>
{{value[11]["profit"]}}
</td>
<td>
{{value[12]["profit"]}}
</td>
</tr>
<tr>
<td>
期末资产
</td>
<td
class=
"text_red"
>
{{value[1]["net_amount"]}}
</td>
<td
class=
"text_green"
>
{{value[2]["net_amount"]}}
</td>
<td>
{{value[3]["net_amount"]}}
</td>
<td>
{{value[4]["net_amount"]}}
</td>
<td>
{{value[5]["net_amount"]}}
</td>
<td>
{{value[6]["net_amount"]}}
</td>
<td>
{{value[7]["net_amount"]}}
</td>
<td>
{{value[8]["net_amount"]}}
</td>
<td>
{{value[9]["net_amount"]}}
</td>
<td>
{{value[10]["net_amount"]}}
</td>
<td>
{{value[11]["net_amount"]}}
</td>
<td>
{{value[12]["net_amount"]}}
</td>
</tr>
{%endfor%}
</table>
</div>
</div>
</div>
<div
class=
"box_line"
></div>
{%for folio, group_result in all_folio_result.items()%}
<!-- 目标与业绩 -->
<div
class=
"box3"
>
<div
class=
"page dtable"
>
<div
class=
"page_title dcell"
>
{%if folio == "default"%}
目标与业绩
{%else%}
目标与业绩({{folio}})
{%endif%}
</div>
<div
class=
"page_head dcell"
>
<div
class=
"dcell"
>
<img
src=
{{logo}}
alt=
""
class=
"page_logo"
>
</div>
<div
class=
"dcell"
>
<div
class=
"page_line"
></div>
</div>
<div
class=
"dcell"
>
<div
class=
"page_text"
>
{{brand_name}}
</div>
</div>
</div>
</div>
<div
class=
"box3_content"
>
<!-- 投资目标 -->
<div
class=
"tss3"
style=
"margin: 0;"
>
<div
class=
"tss3_head dtable"
>
<div
class=
"tss3_title dcell"
>
投资目标
</div>
</div>
<table
border=
"1"
>
<tr>
<th>
现有配置资金(万元)
</th>
<th>
现有年化收益情况(%)
</th>
<th>
现有最大回撤(%)
</th>
</tr>
<tr>
<td>
{{group_result["cost_of_investment"]}}
</td>
<td>
{{group_result["annualised_return"]}}
</td>
<td>
{{group_result["max_withdrawal"]}}
</td>
</tr>
</table>
<table
border=
"1"
style=
"margin: 0;"
>
<tr>
<th>
计划配置资金(万元)
</th>
<th>
目标年化收益情况(%)
</th>
<th>
目标最大回撤(%)
</th>
</tr>
<tr>
<td>
{{group_result["cost_of_investment"]}}
</td>
<td>
5%-10%
</td>
<td>
5%-10%
</td>
</tr>
</table>
</div>
<!-- 指标对比 -->
<div
class=
"tss3"
>
<div
class=
"tss3_head dtable"
>
<div
class=
"tss3_title dcell"
>
指标对比
<span
class=
"tss3_start_time"
>
(起始日期{{start_date}})
</span>
</div>
<div
class=
"tss3_now_time dcell"
>
截止日:最新净值日({{latest_worth_day}})
</div>
</div>
<table
border=
"1"
>
<tr>
<th>
类型
</th>
<th>
区间收益(%)
</th>
<th>
年化收益(%)
</th>
<th>
波动率(%)
</th>
<th>
最大回撤(%)
</th>
<th>
夏普比率
</th>
</tr>
<tr>
<tr
class=
"yellow"
>
<td>
{{group_result["old_indicator_compare"][0]["group_name"]}}
</td>
<td>
{{group_result["old_indicator_compare"][0]["return_ratio"]}}
</td>
<td>
{{group_result["old_indicator_compare"][0]["return_ratio_year"]}}
</td>
<td>
{{group_result["old_indicator_compare"][0]["volatility"]}}
</td>
<td>
{{group_result["old_indicator_compare"][0]["max_drawdown"]}}
</td>
<td>
{{group_result["old_indicator_compare"][0]["sharpe"]}}
</td>
</tr>
<tr
>
<td>
{{group_result["old_indicator_compare"][1]["group_name"]}}
</td>
<td>
{{group_result["old_indicator_compare"][1]["return_ratio"]}}
</td>
<td>
{{group_result["old_indicator_compare"][1]["return_ratio_year"]}}
</td>
<td>
{{group_result["old_indicator_compare"][1]["volatility"]}}
</td>
<td>
{{group_result["old_indicator_compare"][1]["max_drawdown"]}}
</td>
<td>
{{group_result["old_indicator_compare"][1]["sharpe"]}}
</td>
</tr>
</table>
<div
class=
"tss3_tip"
>
注:以上指标自持仓首日开始计算,结果仅供参考,如果持仓时间过短会造成指标失真的情况。
</div>
</div>
<!-- 收益比较、相关性分析 -->
<div
class=
"par clearfix"
cellpadding=
"38"
>
<div
class=
"par_item fl"
>
<div
class=
"par_title"
>
收益比较
</div>
<div
class=
"par_content"
>
<img
src=
{{group_result["old_return_compare_pic"]}}
alt=
""
class=
"par_img"
>
</div>
</div>
<div
class=
"par_item fr"
>
<div
class=
"par_title"
>
相关性分析
</div>
<div
class=
"par_content relative_chart"
>
<div
class=
"rc_chart clearfix"
>
<div
class=
"rcc_left fl"
>
<table
border=
"1"
style=
"border-color: transparent;margin-right: 20px;"
>
{% for correlation in group_result["old_correlation"] %}
<tr>
<td>
<span
class=
"rcc_index"
>
{{correlation[0]}}
</span>
</td>
</tr>
{% endfor %}
</table>
</div>
<div
class=
"rcc_right fr"
>
<table
border=
"1"
>
{% for correlation in group_result["old_correlation"] %}
<tr>
{% for i in range(correlation[2]|length) %}
{% if i == correlation[0] - 1 %}
<td>
<span
class=
"rcc_index"
>
{{correlation[0]}}
</span>
</td>
{% elif -1
<
=
correlation
[
2
][
i
]
<
-0
.
5
and
i
<
correlation
[
0
]
-
1
%}
<
td
>
{{correlation[2][i]}}
</td>
{% elif -1
<
=
correlation
[
2
][
i
]
<
-0
.
5
%}
<
td
class=
"level_color6"
>
{{correlation[2][i]}}
</td>
{% elif -0.5
<
=
correlation
[
2
][
i
]
<
-0
.
25
and
i
<
correlation
[
0
]
-
1
%}
<
td
>
{{correlation[2][i]}}
</td>
{% elif -0.5
<
=
correlation
[
2
][
i
]
<
-0
.
25
%}
<
td
class=
"level_color5"
>
{{correlation[2][i]}}
</td>
{% elif -0.25
<
=
correlation
[
2
][
i
]
<
0
and
i
<
correlation
[
0
]
-
1
%}
<
td
>
{{correlation[2][i]}}
</td>
{% elif -0.25
<
=
correlation
[
2
][
i
]
<
0
%}
<
td
class=
"level_color4"
>
{{correlation[2][i]}}
</td>
{% elif 0
<
=
correlation
[
2
][
i
]
<
0
.
25
and
i
<
correlation
[
0
]
-
1
%}
<
td
>
{{correlation[2][i]}}
</td>
{% elif 0
<
=
correlation
[
2
][
i
]
<
0
.
25
%}
<
td
class=
"level_color3"
>
{{correlation[2][i]}}
</td>
{% elif 0.25
<
=
correlation
[
2
][
i
]
<
0
.
5
and
i
<
correlation
[
0
]
-
1
%}
<
td
>
{{correlation[2][i]}}
</td>
{% elif 0.25
<
=
correlation
[
2
][
i
]
<
0
.
5
%}
<
td
class=
"level_color2"
>
{{correlation[2][i]}}
</td>
{% elif 0.5
<
=
correlation
[
2
][
i
]
<=
1
and
i
<
correlation
[
0
]
-
1
%}
<
td
>
{{correlation[2][i]}}
</td>
{% elif 0.5
<
=
correlation
[
2
][
i
]
<=
1
%}
<
td
class=
"level_color1"
>
{{correlation[2][i]}}
</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</table>
</div>
</div>
<div
class=
"rc_tooltip"
>
<div
class=
"rct_color clearfix"
>
<div
class=
"rct_color_item fl level_color1"
></div>
<div
class=
"rct_color_item fl level_color2"
></div>
<div
class=
"rct_color_item fl level_color3"
></div>
<div
class=
"rct_color_item fl level_color4"
></div>
<div
class=
"rct_color_item fl level_color5"
></div>
<div
class=
"rct_color_item fl level_color6"
></div>
</div>
</div>
<div
class=
"rc_tooltip"
style=
"margin: 0;"
>
<div
class=
"rct_number clearfix"
>
<div
class=
"rtc_number_item fl"
>
1.00
</div>
<div
class=
"rtc_number_item fl"
>
0.50
</div>
<div
class=
"rtc_number_item fl"
>
0.25
</div>
<div
class=
"rtc_number_item fl"
>
0.00
</div>
<div
class=
"rtc_number_item fl"
>
-0.25
</div>
<div
class=
"rtc_number_item fl"
>
-0.50
</div>
<div
class=
"rtc_number_item fl"
>
-1.00
</div>
</div>
</div>
<div
class=
"rc_label clearfix"
>
{% for correlation in group_result["old_correlation"] %}
<div
class=
"rcl_item fl"
>
<div
class=
"rcl_item_number"
>
{{correlation[0]}}
</div>
<div
class=
"rcl_item_name"
>
{{correlation[1]}}
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"box_line"
></div>
<!-- 业绩的明细 -->
<div
class=
"box4"
>
<div
class=
"page dtable"
>
<div
class=
"page_title dcell"
>
业绩的明细
</div>
<div
class=
"page_head dcell"
>
<div
class=
"dcell"
>
<img
src=
{{logo}}
alt=
""
class=
"page_logo"
>
</div>
<div
class=
"dcell"
>
<div
class=
"page_line"
></div>
</div>
<div
class=
"dcell"
>
<div
class=
"page_text"
>
{{brand_name}}
</div>
</div>
</div>
</div>
<div
class=
"box4_content"
>
<!-- 持仓收益汇总 -->
<div
class=
"tss3"
style=
"margin: 0;"
>
<div
class=
"tss3_head dtable"
>
<div
class=
"tss3_title dcell"
>
持仓收益汇总
</div>
<div
class=
"tss3_now_time dcell"
>
截止日:最新净值日({{latest_worth_day}})
</div>
</div>
<div
style=
"position: relative;"
>
<div
class=
"tss3_tag"
>
私募基金
<div
class=
"tss3_tri"
></div>
</div>
<table
border=
"1"
>
<tr>
<th
colspan=
"5"
>
投资本金
</th>
<th
colspan=
"4"
>
{{month}}月业绩
</th>
<th
colspan=
"3"
>
累计业绩
</th>
</tr>
<tr>
<th>
投资策略
</th>
<th>
基金简称
</th>
<th>
买入时间
</th>
<th>
存续年数
</th>
<th>
投资本金 (万)
</th>
<th>
当月收益 (万)
</th>
<th>
当月收益率 (%)
</th>
<th>
月末市值 (万)
</th>
<th>
月末占比 (%)
</th>
<th>
累计收益 (万)
</th>
<th>
累计收益率 (%)
</th>
<th>
年化收益率 (%)
</th>
</tr>
{% for one in group_result["group_hoding_info"] %}
<tr>
<td
rowspan=
"1"
>
{{one.fund_strategy_name}}
</td>
<td>
{{one.fund_name}}
</td>
<td>
{{one.confirm_date}}
</td>
<td>
{{one.hold_year}}
</td>
<td>
{{one.cost}}
</td>
<td>
{{one.profit}}
</td>
<td>
{{one.month_return_ratio}}
</td>
<td>
{{one.market_values}}
</td>
<td>
{{one.weight}}
</td>
<td>
{{one.cum_profit}}
</td>
<td>
{{one.cum_profit_ratio}}
</td>
<td>
{{one.return_ratio_year}}
</td>
</tr>
{% endfor %}
<tr
class=
"gray"
>
<td
colspan=
"4"
>
总计
</td>
<td>
{{group_result["group_hoding_info_total"]["total_cost"]}}
</td>
<td>
{{group_result["group_hoding_info_total"]["cur_month_profit"]}}
</td>
<td>
{{group_result["group_hoding_info_total"]["cur_month_profit_ratio"]}}
</td>
<td>
{{group_result["group_hoding_info_total"]["ending_assets"]}}
</td>
<td>
100%
</td>
<td>
{{group_result["group_hoding_info_total"]["cumulative_profit"]}}
</td>
<td>
{{group_result["group_hoding_info_total"]["cumulative_return"]}}
</td>
<td>
{{group_result["group_hoding_info_total"]["return_ratio_year"]}}
</td>
</tr>
</table>
</div>
</div>
<!-- 基金净值 -->
<div
class=
"tss3"
>
<div
class=
"tss3_head dtable"
>
<div
class=
"tss3_title dcell"
>
基金净值
</div>
<div
class=
"tss3_now_time dcell"
>
截止日:最新净值日({{latest_worth_day}})
</div>
</div>
<table
border=
"1"
>
<tr>
<th
rowspan=
"2"
>
基金简称
</th>
<th
rowspan=
"2"
>
申购净值
</th>
<th
colspan=
"2"
>
最新净值({{latest_worth_day}})
</th>
<th
colspan=
"7"
>
收益率(%)
</th>
<th
rowspan=
"2"
>
分红
</th>
</tr>
<tr>
<th>
单位净值
</th>
<th>
累计净值
</th>
<th>
较上周
</th>
<th>
申购以来
</th>
<th>
近一月
</th>
<th>
近半年
</th>
<th>
近一年
</th>
<th>
今年以来
</th>
<th>
成立以来
</th>
</tr>
{% for nav_info in group_result["group_nav_info"] %}
<tr>
<td>
{{nav_info['fund_name']}}
</td>
<td>
{{nav_info['confirm_nav']}}
</td>
<td>
{{nav_info['cur_nav']}}
</td>
<td>
{{nav_info['cur_cnav']}}
</td>
<td>
{{nav_info['ret_1w']}}
</td>
<td>
{{nav_info['ret_after_confirm']}}
</td>
<td>
{{nav_info['ret_cum_1m']}}
</td>
<td>
{{nav_info['ret_cum_6m']}}
</td>
<td>
{{nav_info['ret_cum_1y']}}
</td>
<td>
{{nav_info['ret_cum_ytd']}}
</td>
<td>
{{nav_info['ret_cum_incep']}}
</td>
<td>
{{nav_info['distribution']}}
</td>
</tr>
{% endfor %}
</table>
</div>
<!-- 贡献分解 -->
<div
class=
"page dtable"
style=
"page-break-before:always;"
>
<div
class=
"page_title dcell"
>
</div>
<div
class=
"page_head dcell"
>
<div
class=
"dcell"
>
<img
src=
{{logo}}
alt=
""
class=
"page_logo"
>
</div>
<div
class=
"dcell"
>
<div
class=
"page_line"
></div>
</div>
<div
class=
"dcell"
>
<div
class=
"page_text"
>
{{brand_name}}
</div>
</div>
</div>
</div>
<div
class=
"tss2"
>
<div
class=
"tss2_title"
>
贡献分解
</div>
<div
class=
"tss2_content"
>
<img
src=
{{group_result["contribution_decomposition"]}}
alt=
""
class=
"tss2_img"
>
</div>
</div>
</div>
</div>
<div
class=
"box_line"
></div>
<!-- 个基点评 -->
<div
class=
"box5"
>
<div
class=
"page dtable"
>
<div
class=
"page_title dcell"
>
个基点评
</div>
<div
class=
"page_head dcell"
>
<div
class=
"dcell"
>
<img
src=
{{logo}}
alt=
""
class=
"page_logo"
>
</div>
<div
class=
"dcell"
>
<div
class=
"page_line"
></div>
</div>
<div
class=
"dcell"
>
<div
class=
"page_text"
>
{{brand_name}}
</div>
</div>
</div>
</div>
<div
class=
"box5_content"
>
<div
class=
"geji_list_wrap"
>
{% for i in range(group_result["single_fund_data_list"]|length) %}
{% if (i+1) % 3 == 1 and i != 0%}
<div
class=
"page dtable"
>
<div
class=
"page_title dcell"
>
</div>
<div
class=
"page_head dcell"
>
<div
class=
"dcell"
>
<img
src=
{{logo}}
alt=
""
class=
"page_logo"
>
</div>
<div
class=
"dcell"
>
<div
class=
"page_line"
></div>
</div>
<div
class=
"dcell"
>
<div
class=
"page_text"
>
{{brand_name}}
</div>
</div>
</div>
</div>
{% endif %}
{% if (i+1) % 3 == 0 and i != 0%}
<div
class=
"self_item"
style=
"page-break-after:always;"
>
{% else %}
<div
class=
"self_item"
>
{% endif %}
<table>
<tr>
<td
style=
"padding: 0;text-align: left;vertical-align: middle;"
>
<div
class=
"self_item_left"
>
<div
class=
"self_header clearfix"
>
<div
class=
"self_title fl"
>
{{group_result["single_fund_data_list"][i].fund_name}}
</div>
{{group_result["single_fund_data_list"][i].status}}
</div>
<div
class=
"self_description"
>
{% for one in group_result["single_fund_data_list"][i].evaluation %}
<div
class=
"self_description_item"
>
<div
class=
"self_description_dot"
></div>
<div
class=
"self_description_text"
>
{{one}}
</div>
</div>
{% endfor %}
</div>
</div>
</td>
<td
style=
"padding: 0;text-align: left;vertical-align: middle;"
>
<div
class=
"self_item_right"
>
<img
src=
{{group_result["single_fund_data_list"][i].radar_chart_path}}
alt=
""
class=
"self_img"
>
</div>
</td>
</tr>
</table>
</div>
{% endfor %}
</div>
<!-- 持仓点评 -->
{% if single_fund_data_list|length % 3 == 0 and single_fund_data_list|length != 0%}
<div
class=
"page dtable"
>
<div
class=
"page_title dcell"
>
</div>
<div
class=
"page_head dcell"
>
<div
class=
"dcell"
>
<img
src=
{{logo}}
alt=
""
class=
"page_logo"
>
</div>
<div
class=
"dcell"
>
<div
class=
"page_line"
></div>
</div>
<div
class=
"dcell"
>
<div
class=
"page_text"
>
{{brand_name}}
</div>
</div>
</div>
</div>
{% endif %}
<div
class=
"target_comment"
>
<div
class=
"comment_title"
>
持仓点评
<div
class=
"comment_tri"
></div>
</div>
<div
class=
"comment_content"
>
{% for eval in group_result["old_evaluation"] %}
<div
class=
"comment_item"
>
<div
class=
"comment_dot"
></div>
<div
class=
"comment_text"
>
{{eval}}
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
<div
class=
"box_line"
></div>
<!-- 优化组合建议 -->
<div
class=
"box6"
>
<div
class=
"page dtable"
>
<div
class=
"page_title dcell"
>
优化组合建议
</div>
<div
class=
"page_head dcell"
>
<div
class=
"dcell"
>
<img
src=
{{logo}}
alt=
""
class=
"page_logo"
>
</div>
<div
class=
"dcell"
>
<div
class=
"page_line"
></div>
</div>
<div
class=
"dcell"
>
<div
class=
"page_text"
>
{{brand_name}}
</div>
</div>
</div>
</div>
<div
class=
"box6_content"
>
<!-- 调仓建议 -->
<div
class=
"tss3"
style=
"margin: 0;"
>
<div
class=
"tss3_head dtable"
>
<div
class=
"tss3_title dcell"
>
调仓建议
</div>
</div>
<table
border=
"1"
>
<tr>
<th>
投资策略
</th>
<th>
基金简称
</th>
<th>
优化前(万元)
</th>
<th>
优化后(万元)
</th>
</tr>
{% for key, value in group_result["suggestions_result"].items() %}
{% for i in range(value|length) %}
<tr>
{% if i == 0%}
<td
rowspan=
{{value|length
}}
>
{{key}}
</td>
{% endif %}
<td>
{{value[i]["fund_name"]}}
</td>
<td
class=
"font_red"
>
{{value[i]["before_optimization"]}}
</td>
<td
class=
"font_green"
>
{{value[i]["after_optimization"]}}
</td>
</tr>
{% endfor %}
{% endfor %}
<tr>
<td
colspan=
"2"
class=
"gray"
>
总市值(万元)
</td>
<td
class=
"summary"
>
{{group_result["suggestions_result_asset"]["before"]}}
</td>
<td
class=
"summary"
>
{{group_result["suggestions_result_asset"]["after"]}}
</td>
</tr>
</table>
</div>
<!-- 指标对比 -->
<div
class=
"tss3"
>
<div
class=
"tss3_head dtable"
>
<div
class=
"tss3_title dcell"
>
指标对比
<span
class=
"tss3_start_time"
>
(起始日期2019-11-06)
</span>
</div>
<div
class=
"tss3_now_time dcell"
>
截止日:最新净值日({{latest_worth_day}})
</div>
</div>
<table
border=
"1"
>
<tr>
<th>
类型
</th>
<th>
区间收益(%)
</th>
<th>
年化收益(%)
</th>
<th>
波动率(%)
</th>
<th>
最大回撤(%)
</th>
<th>
夏普比率
</th>
</tr>
{%for i in range(group_result["indicator_compare"]|length)%}
{%if i
<
(
group_result
["
indicator_compare
"]|
length
)
-1
%}
{%
if
i
%
2=
=0
%}
<
tr
>
{%endif%}
{%if i%2==1 %}
<tr
class=
"yellow"
>
{%endif%}
{%endif%}
<td>
{{group_result["indicator_compare"][i]["group_name"]}}
</td>
<td>
{{group_result["indicator_compare"][i]["return_ratio"]}}
</td>
<td>
{{group_result["indicator_compare"][i]["return_ratio_year"]}}
</td>
<td>
{{group_result["indicator_compare"][i]["volatility"]}}
</td>
<td>
{{group_result["indicator_compare"][i]["max_drawdown"]}}
</td>
<td>
{{group_result["indicator_compare"][i]["sharpe"]}}
</td>
</tr>
{% endfor %}
</table>
<div
class=
"tss3_tip"
>
注:以上指标自持仓首日开始计算,结果仅供参考,如果持仓时间过短会造成指标失真的情况。
</div>
</div>
<!-- 收益比较、相关性分析 -->
<div
class=
"page dtable"
style=
"page-break-before:always;"
>
<div
class=
"page_title dcell"
>
</div>
<div
class=
"page_head dcell"
>
<div
class=
"dcell"
>
<img
src=
{{logo}}
alt=
""
class=
"page_logo"
>
</div>
<div
class=
"dcell"
>
<div
class=
"page_line"
></div>
</div>
<div
class=
"dcell"
>
<div
class=
"page_text"
>
{{brand_name}}
</div>
</div>
</div>
</div>
<div
class=
"par clearfix"
cellpadding=
"38"
>
<div
class=
"par_item fl"
>
<div
class=
"par_title"
>
收益比较
</div>
<div
class=
"par_content"
>
<img
src=
{{group_result["return_compare_pic"]}}
alt=
""
class=
"par_img"
>
</div>
</div>
<div
class=
"par_item fr"
>
<div
class=
"par_title"
>
相关性分析
</div>
<div
class=
"par_content relative_chart"
>
<div
class=
"rc_chart clearfix"
>
<div
class=
"rcc_left fl"
>
<table
border=
"1"
style=
"border-color: transparent;margin-right: 20px;"
>
{% for correlation in group_result["new_correlation"] %}
<tr>
<td>
<span
class=
"rcc_index"
>
{{correlation[0]}}
</span>
</td>
</tr>
{% endfor %}
</table>
</div>
<div
class=
"rcc_right fr"
>
<table
border=
"1"
>
{% for correlation in group_result["new_correlation"] %}
<tr>
{% for i in range(correlation[2]|length) %}
{% if i == correlation[0] - 1 %}
<td>
<span
class=
"rcc_index"
>
{{correlation[0]}}
</span>
</td>
{% elif -1
<
=
correlation
[
2
][
i
]
<
-0
.
5
and
i
<
correlation
[
0
]
-
1
%}
<
td
>
{{correlation[2][i]}}
</td>
{% elif -1
<
=
correlation
[
2
][
i
]
<
-0
.
5
%}
<
td
class=
"level_color6"
>
{{correlation[2][i]}}
</td>
{% elif -0.5
<
=
correlation
[
2
][
i
]
<
-0
.
25
and
i
<
correlation
[
0
]
-
1
%}
<
td
>
{{correlation[2][i]}}
</td>
{% elif -0.5
<
=
correlation
[
2
][
i
]
<
-0
.
25
%}
<
td
class=
"level_color5"
>
{{correlation[2][i]}}
</td>
{% elif -0.25
<
=
correlation
[
2
][
i
]
<
0
and
i
<
correlation
[
0
]
-
1
%}
<
td
>
{{correlation[2][i]}}
</td>
{% elif -0.25
<
=
correlation
[
2
][
i
]
<
0
%}
<
td
class=
"level_color4"
>
{{correlation[2][i]}}
</td>
{% elif 0
<
=
correlation
[
2
][
i
]
<
0
.
25
and
i
<
correlation
[
0
]
-
1
%}
<
td
>
{{correlation[2][i]}}
</td>
{% elif 0
<
=
correlation
[
2
][
i
]
<
0
.
25
%}
<
td
class=
"level_color3"
>
{{correlation[2][i]}}
</td>
{% elif 0.25
<
=
correlation
[
2
][
i
]
<
0
.
5
and
i
<
correlation
[
0
]
-
1
%}
<
td
>
{{correlation[2][i]}}
</td>
{% elif 0.25
<
=
correlation
[
2
][
i
]
<
0
.
5
%}
<
td
class=
"level_color2"
>
{{correlation[2][i]}}
</td>
{% elif 0.5
<
=
correlation
[
2
][
i
]
<=
1
and
i
<
correlation
[
0
]
-
1
%}
<
td
>
{{correlation[2][i]}}
</td>
{% elif 0.5
<
=
correlation
[
2
][
i
]
<=
1
%}
<
td
class=
"level_color1"
>
{{correlation[2][i]}}
</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</table>
</div>
</div>
<div
class=
"rc_tooltip"
>
<div
class=
"rct_color clearfix"
>
<div
class=
"rct_color_item fl level_color1"
></div>
<div
class=
"rct_color_item fl level_color2"
></div>
<div
class=
"rct_color_item fl level_color3"
></div>
<div
class=
"rct_color_item fl level_color4"
></div>
<div
class=
"rct_color_item fl level_color5"
></div>
<div
class=
"rct_color_item fl level_color6"
></div>
</div>
</div>
<div
class=
"rc_tooltip"
style=
"margin: 0;"
>
<div
class=
"rct_number clearfix"
>
<div
class=
"rtc_number_item fl"
>
1.00
</div>
<div
class=
"rtc_number_item fl"
>
0.50
</div>
<div
class=
"rtc_number_item fl"
>
0.25
</div>
<div
class=
"rtc_number_item fl"
>
0.00
</div>
<div
class=
"rtc_number_item fl"
>
-0.25
</div>
<div
class=
"rtc_number_item fl"
>
-0.50
</div>
<div
class=
"rtc_number_item fl"
>
-1.00
</div>
</div>
</div>
<div
class=
"rc_label clearfix"
>
{% for correlation in group_result["new_correlation"] %}
<div
class=
"rcl_item fl"
>
<div
class=
"rcl_item_number"
>
{{correlation[0]}}
</div>
<div
class=
"rcl_item_name"
>
{{correlation[1]}}
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"box_line"
></div>
<!-- 新增基金 -->
<div
class=
"box7"
>
<div
class=
"page dtable"
>
<div
class=
"page_title dcell"
>
新增基金
</div>
<div
class=
"page_head dcell"
>
<div
class=
"dcell"
>
<img
src=
{{logo}}
alt=
""
class=
"page_logo"
>
</div>
<div
class=
"dcell"
>
<div
class=
"page_line"
></div>
</div>
<div
class=
"dcell"
>
<div
class=
"page_text"
>
{{brand_name}}
</div>
</div>
</div>
</div>
<div
class=
"box7_content"
>
<div
class=
"geji_list_wrap"
>
{% for i in range(group_result["propose_fund_data_list"]|length) %}
{% if (i+1) % 3 == 1 and i != 0%}
<div
class=
"page dtable"
style=
"page-break-before:always;"
>
<div
class=
"page_title dcell"
>
</div>
<div
class=
"page_head dcell"
>
<div
class=
"dcell"
>
<img
src=
{{logo}}
alt=
""
class=
"page_logo"
>
</div>
<div
class=
"dcell"
>
<div
class=
"page_line"
></div>
</div>
<div
class=
"dcell"
>
<div
class=
"page_text"
>
{{brand_name}}
</div>
</div>
</div>
</div>
<div
class=
"self_item"
>
{% else %}
<div
class=
"self_item"
>
{% endif %}
<table>
<tr>
<td
style=
"padding: 0;text-align: left;vertical-align: middle;"
>
<div
class=
"self_item_left"
>
<div
class=
"self_header clearfix"
>
<div
class=
"self_title fl"
>
{{group_result["propose_fund_data_list"][i].fund_name}}
</div>
</div>
<div
class=
"self_description"
>
{% for one in group_result["propose_fund_data_list"][i].evaluation %}
<div
class=
"self_description_item"
>
<div
class=
"self_description_dot"
></div>
<div
class=
"self_description_text"
>
{{one}}
</div>
</div>
{% endfor %}
</div>
</div>
</td>
<td
style=
"padding: 0;text-align: left;vertical-align: middle;"
>
<div
class=
"self_item_right"
>
<img
src=
{{group_result["propose_fund_data_list"][i].radar_chart_path}}
alt=
""
class=
"self_img"
>
</div>
</td>
</tr>
</table>
</div>
{% endfor %}
</div>
<!-- 持仓点评 -->
<div
class=
"target_comment"
>
<div
class=
"comment_title"
>
优化方案点评
<div
class=
"comment_tri"
></div>
</div>
<div
class=
"comment_content"
>
<div
class=
"comment_item"
>
<div
class=
"comment_dot"
></div>
<div
class=
"comment_text"
>
{{group_result["new_group_evaluation"]}}
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"box_line"
></div>
{%endfor%}
<!-- 结尾 -->
<div
class=
"box8"
>
<div
class=
"page dtable"
>
<div
class=
"page_title dcell"
>
</div>
<div
class=
"page_head dcell"
>
<div
class=
"dcell"
>
<img
src=
{{logo}}
alt=
""
class=
"page_logo"
>
</div>
<div
class=
"dcell"
>
<div
class=
"page_line"
></div>
</div>
<div
class=
"dcell"
>
<div
class=
"page_text"
>
{{brand_name}}
</div>
</div>
</div>
</div>
<div
class=
"box8_content"
>
<div
class=
"financial_show dtable"
>
<div
class=
"financial_left dcell"
>
<div
class=
"financial_scene"
>
<img
src=
{{scene}}
alt=
""
class=
"financial_scene_img"
>
<div
class=
"financial_scene_text"
>
我们挣的是⻆度和变化的钱⽽不是纠正市场错 误的钱,市场永远是正确的,关键是在其正确 被反复证明后的逆向⽽⾏,⼀定是避开它的正 确被展开的过程 。
</div>
<div
class=
"financial_scene_author"
>
——飞度
</div>
</div>
</div>
<div
class=
"financial_show_right dcell"
>
<div
class=
"financial_team"
>
<img
src=
{{team}}
alt=
""
class=
"financial_team_img"
>
</div>
</div>
</div>
<div
class=
"statement_content"
>
<div
class=
"statement_block"
>
<div
class=
"statement_title"
>
探普研究院声明
</div>
<div
class=
"statement_p"
>
本诊断报告所表述的任何观点均准确地反应了研究人员的看法;该研究人员所得报酬的任何组成部分无论是过去、现在、或者将来均不会直接或间接地与研究报告所表述的建议或观点相联系。
</div>
</div>
<div
class=
"statement_block"
>
<div
class=
"statement_title"
>
一般性声明
</div>
<div
class=
"statement_p"
>
本报告对于收件人而言属于高度机密,只有收件人才能使用。本报告并非意图发送、发布给在
当地法律或监管规则下不允许向其发送、发布该研究报告的人员。本研究报告仅供参考之用,在任何地区均不应被视为买卖任何证券、金融工具、基金、以及其他理财产品的要约或要约邀请。探普研究院并不因收件人收到本报告而视其为客户。本报告所包含的观点及建议并未考虑个别客户的特殊状况、目标或需要,不应视为对特定客户关于特定证券或金融工具、基金、以及其他理财产品的购买建议或策略。对于本报告中提及的任何证券、金融工具、基金、以及其他理财产品,本报告的
收件人须保持自身的独立判断。
</div>
<div
class=
"statement_p"
>
本报告所载资料的来源被认为是可靠的,但探普研究院不保证其准确性或完整性,并不对使用本报告所包含的材料产生任何直接或间接损失或与此有关的其他损失承担任何责任。本报告提及的任何证券、金融工具、基金或其他理财产品均可能含有巨大的风险,可能不易变卖以及不适合所有的投资者。本报告所提及的证券、金融工具、基金或其他理财产品的价格、价值以及收益可能会受
汇率影响而波动。过往的业绩也不能代表未来的表现。
</div>
<div
class=
"statement_p"
>
本报告所载的资料、观点以及预测分析均反映了探普研究院在最初报告发布日期当日的判断,可以在不发出通知的情况下做出更改、亦可因使用不同假设和标准、采用不同观点和分析方法而与市场上其他机构、部门、单位、个人在制作类似的其他材料时所给出的意见不同或者相反。探普研究院以及关联公司、单位并不承担提示本报告收件人注意该等材料的责任。负责撰写本报告研究人员薪酬并不基于任何金融产品的销售情况而定,但其薪酬可能会与我司的整体收入有关。
</div>
<div
class=
"statement_p"
>
若以探普研究院以外的机构或个人发送本报告,则由该机构或个人为此发送行为承担全部责任。该机构或个人应联系相关机构以交易本报告中提及的证券、金融工具、基金、其他理财产品获悉更详细信息。本报告不构成探普研究院向发送本报告的机构或个人的客户提供的投资建议,探普研究院以及关联单位、公司中的各个高级职员、董事、员工亦不为(前述机构或个人)因使用本报告或报告载明的内容产生的直接或间接损失承担任何责任。
</div>
</div>
<div
class=
"statement_block"
>
<div
class=
"statement_title2"
>
未经探普研究院事先书面授权,任何人不得以任何目的复制、发送或者销售本报告。探普研究院 2020 版权所有,保留一切权利。
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
\ No newline at end of file
app/utils/jinjia2html_v2.py
0 → 100644
View file @
fdc3475f
import
time
import
uuid
from
jinja2
import
PackageLoader
,
Environment
from
app.api.engine
import
work_dir
,
pdf_folder
,
template_folder
from
app.service.portfolio_diagnose
import
PortfolioDiagnose
from
app.service.result_service_v2
import
UserCustomerResultAdaptor
import
numpy
as
np
from
concurrent
import
futures
import
os
# 准备数据
from
app.utils.draw
import
draw_month_return_chart
,
draw_contribution_chart
,
draw_combination_chart
,
\
draw_old_combination_chart
from
app.utils.html_to_pdf
import
html_to_pdf
from
app.utils.radar_chart
import
gen_radar_chart
class
DataIntegrate
:
def
__init__
(
self
,
ifa_id
=
'USER_INFO15914346866762'
,
customer_id
=
'202009281545001'
,
pdf_name
=
str
(
uuid
.
uuid4
())
+
'.pdf'
):
self
.
user_customer
=
UserCustomerResultAdaptor
(
ifa_id
,
customer_id
)
self
.
customer_name
=
self
.
user_customer
.
customer_real_name
self
.
pdf_name
=
pdf_name
# 全部数据
self
.
df
=
self
.
user_customer
.
calculate_total_data
()
# 组合结果数据
self
.
d
=
self
.
user_customer
.
calculate_group_result_data
()
self
.
all_folio_result
=
{}
# 分组合拼接结果数据
self
.
get_group_result
()
# # 组合数据
# self.group_result = self.d["default"]
# self.get_portfolio_diagnose(self.group_result["fund_id_list"])
# 投资总览
self
.
get_summarize
()
# 月度回报
self
.
get_month_return
()
# 月度回报表格
self
.
get_month_table_return
()
# 渲染模版
self
.
render_data
()
# 分组和计算个基点评以及新增基金等结果
def
get_group_result
(
self
):
for
group_name
,
group_result
in
self
.
d
.
items
():
portfolio_diagnose
=
self
.
get_portfolio_diagnose
(
group_result
[
"fund_id_list"
],
invest_amount
=
group_result
[
"total_cost"
])
cur_group_portfolio_result
=
{}
# 旧持仓组合点评
self
.
comments_on_position_portfolio
(
portfolio_diagnose
,
group_name
,
cur_group_portfolio_result
)
# 贡献分解
self
.
contribution_deco
(
group_result
,
cur_group_portfolio_result
)
# 目标与业绩
self
.
objectives_performance
(
group_result
,
cur_group_portfolio_result
)
# 个基点评
self
.
single_fund_comment
(
portfolio_diagnose
,
cur_group_portfolio_result
)
# 旧收益比较
self
.
get_old_compare_pic
(
cur_group_portfolio_result
)
# 旧相关性
self
.
get_old_correlation
(
portfolio_diagnose
,
cur_group_portfolio_result
)
# # 新增基金
self
.
propose_fund
(
portfolio_diagnose
,
cur_group_portfolio_result
)
# # 新收益比较
self
.
get_transfer_suggestions
(
portfolio_diagnose
,
group_name
,
cur_group_portfolio_result
)
# # 新相关性
self
.
get_new_correlation
(
portfolio_diagnose
,
cur_group_portfolio_result
)
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
.
optimize
()
return
portfolio_diagnose
# 全部数据综述结果
def
get_summarize
(
self
):
"""投资总览."""
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"
])
# 累计盈利
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
)
def
get_month_table_return
(
self
):
"""月度盈亏和期末资产"""
self
.
monthly_table_return
=
self
.
df
[
"month_return_data_dict"
]
# 旧组合持仓点评,贡献分解数据
def
comments_on_position_portfolio
(
self
,
portfolio_diagnose
,
folio
,
cur_group_portfolio_result
):
"""旧持仓组合点评. 旧贡献分解数据"""
cur_group_portfolio_result
[
"old_evaluation"
],
cur_group_portfolio_result
[
"old_return_compare_data"
],
\
cur_group_portfolio_result
[
"old_indicator_compare"
]
=
portfolio_diagnose
.
old_evaluation
(
folio
,
self
.
d
,
self
.
user_customer
)
def
contribution_deco
(
self
,
group_result
,
cur_group_portfolio_result
):
"""贡献分解."""
g_data
=
group_result
[
"contribution_decomposition"
]
cur_group_portfolio_result
[
"contribution_decomposition"
]
=
draw_contribution_chart
(
g_data
[
'xlabels'
],
g_data
[
'product_list'
],
g_data
[
'cumulative'
])
def
single_fund_comment
(
self
,
portfolio_diagnose
,
cur_group_portfolio_result
):
"""个基点评."""
single_fund_data_list
=
[]
portfolio_evaluation
=
portfolio_diagnose
.
old_portfolio_evaluation
()
radar_chart_data
=
portfolio_diagnose
.
single_fund_radar
()
with
futures
.
ProcessPoolExecutor
(
os
.
cpu_count
())
as
executor
:
res
=
executor
.
map
(
gen_radar_chart
,
radar_chart_data
)
res
=
list
(
res
)
for
i
in
range
(
len
(
portfolio_evaluation
)):
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>'
single_fund_data_list
.
append
({
'fund_name'
:
portfolio_evaluation
[
i
][
'name'
],
'status'
:
portfolio_evaluation
[
i
][
'status'
],
'evaluation'
:
portfolio_evaluation
[
i
][
'data'
],
'radar_chart_path'
:
res
[
i
]
})
cur_group_portfolio_result
[
"single_fund_data_list"
]
=
single_fund_data_list
def
get_old_compare_pic
(
self
,
cur_group_portfolio_result
):
"""旧收益比较"""
cur_group_portfolio_result
[
"old_return_compare_pic"
]
=
draw_old_combination_chart
(
cur_group_portfolio_result
[
"old_return_compare_data"
][
"xlabels"
],
cur_group_portfolio_result
[
"old_return_compare_data"
][
"origin_combination"
],
cur_group_portfolio_result
[
"old_return_compare_data"
][
"index"
])
def
get_transfer_suggestions
(
self
,
portfolio_diagnose
,
folio
,
cur_group_portfolio_result
):
"""新收益比较,调仓建议"""
cur_group_portfolio_result
[
"suggestions_result"
],
cur_group_portfolio_result
[
"suggestions_result_asset"
],
\
cur_group_portfolio_result
[
"return_compare_data"
],
\
cur_group_portfolio_result
[
"indicator_compare"
],
cur_group_portfolio_result
[
"new_group_evaluation"
]
=
portfolio_diagnose
.
new_evaluation
(
folio
,
self
.
d
,
self
.
user_customer
)
cur_group_portfolio_result
[
"return_compare_pic"
]
=
draw_combination_chart
(
cur_group_portfolio_result
[
"return_compare_data"
][
"xlabels"
],
cur_group_portfolio_result
[
"return_compare_data"
][
"new_combination"
],
cur_group_portfolio_result
[
"return_compare_data"
][
"origin_combination"
],
cur_group_portfolio_result
[
"return_compare_data"
][
"index"
])
def
get_old_correlation
(
self
,
portfolio_diagnose
,
cur_group_portfolio_result
):
"""旧相关性分析."""
old_correlation
=
portfolio_diagnose
.
old_correlation
old_correlation_columns
=
old_correlation
.
columns
.
tolist
()
old_correlation_values
=
old_correlation
.
values
.
tolist
()
cur_group_portfolio_result
[
"old_correlation"
]
=
list
(
zip
(
range
(
1
,
len
(
old_correlation_columns
)
+
1
),
old_correlation_columns
,
old_correlation_values
))
def
get_new_correlation
(
self
,
portfolio_diagnose
,
cur_group_portfolio_result
):
"""新相关性分析."""
new_correlation
=
portfolio_diagnose
.
new_correlation
new_correlation_columns
=
new_correlation
.
columns
.
tolist
()
new_correlation_values
=
new_correlation
.
values
.
tolist
()
cur_group_portfolio_result
[
"new_correlation"
]
=
list
(
zip
(
range
(
1
,
len
(
new_correlation_columns
)
+
1
),
new_correlation_columns
,
new_correlation_values
))
def
propose_fund
(
self
,
portfolio_diagnose
,
cur_group_portfolio_result
):
"""新增基金"""
# 优化组合建议1 -- 新增基金
propose_fund_data_list
=
[]
propose_fund_evaluation
=
portfolio_diagnose
.
propose_fund_evaluation
()
propose_radar_chart_data
=
portfolio_diagnose
.
propose_fund_radar
()
with
futures
.
ProcessPoolExecutor
(
os
.
cpu_count
())
as
executor
:
res
=
executor
.
map
(
gen_radar_chart
,
propose_radar_chart_data
)
res
=
list
(
res
)
for
i
in
range
(
len
(
propose_fund_evaluation
)):
propose_fund_data_list
.
append
({
'fund_name'
:
propose_fund_evaluation
[
i
][
'name'
],
'status'
:
'增仓'
,
'evaluation'
:
propose_fund_evaluation
[
i
][
'data'
],
'radar_chart_path'
:
res
[
i
]
})
cur_group_portfolio_result
[
"propose_fund_data_list"
]
=
propose_fund_data_list
def
objectives_performance
(
self
,
group_result
,
cur_group_portfolio_result
):
"""目标与业绩"""
cur_group_portfolio_result
[
"totoal_rate_of_return"
]
=
round
((
group_result
[
'cumulative_return'
]
-
1
)
*
100
,
2
)
# 成立以来累计收益率
cur_group_portfolio_result
[
"annualised_return"
]
=
round
(
group_result
[
"return_ratio_year"
]
*
100
,
2
)
# 年化收益率
cur_group_portfolio_result
[
"volatility"
]
=
round
(
group_result
[
"volatility"
]
*
100
,
2
)
cur_group_portfolio_result
[
"max_withdrawal"
]
=
round
(
group_result
[
"max_drawdown"
][
0
]
*
100
,
2
)
cur_group_portfolio_result
[
"sharpe_ratio"
]
=
round
(
group_result
[
"sharpe"
],
2
)
cur_group_portfolio_result
[
"cost_of_investment"
]
=
round
(
group_result
[
"total_cost"
]
/
10000.0
,
2
)
# 投资成本
cur_group_portfolio_result
[
"index_section_return"
]
=
round
((
group_result
[
"index_result"
][
"return_ratio"
]
-
1
)
*
100
,
2
)
cur_group_portfolio_result
[
"index_annualised_return"
]
=
round
(
group_result
[
"index_result"
][
"return_ratio_year"
]
*
100
,
2
)
# 年化收益率
cur_group_portfolio_result
[
"index_volatility"
]
=
round
(
group_result
[
"index_result"
][
"volatility"
]
*
100
,
2
)
cur_group_portfolio_result
[
"index_max_withdrawal"
]
=
round
(
group_result
[
"index_result"
][
"max_drawdown"
][
0
]
*
100
,
2
)
cur_group_portfolio_result
[
"index_sharpe_ratio"
]
=
round
(
group_result
[
"index_result"
][
"sharpe"
],
2
)
cur_group_portfolio_result
[
"group_nav_info"
]
=
group_result
[
"group_nav_info"
]
cur_group_portfolio_result
[
"group_hoding_info"
]
=
group_result
[
"group_hoding_info"
]
cur_group_portfolio_result
[
"group_hoding_info_total"
]
=
group_result
[
"group_hoding_info_total"
]
def
render_data
(
self
):
# 全部数据
data
=
{
# 封面 值为None不不显示,为block显示
'box0'
:
'block'
,
# 目录
'box1'
:
'block'
,
# 投资总览
'box2'
:
'block'
,
# 目标与业绩
'box3'
:
'block'
,
# 业绩的明细
'box4'
:
'block'
,
# 个基点评
'box5'
:
'block'
,
# 优化组合建议
'box6'
:
None
,
# 新增基金
'box7'
:
None
,
# 结尾
'box8'
:
'block'
,
'cover_back'
:
template_folder
+
'/v2/img/cover-back.png'
,
'logo'
:
template_folder
+
'/v2/img/logo.png'
,
'scene'
:
template_folder
+
'/v2/img/scene.png'
,
'team'
:
template_folder
+
'/v2/img/team.png'
,
# 全局数据
'customer_name'
:
self
.
customer_name
,
'year_month'
:
self
.
user_customer
.
month_start_date
.
strftime
(
"
%
Y-
%
m"
),
'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
,
'brand_name'
:
'小飞象<br>工作室'
,
'customer_old'
:
42
,
'customer_level'
:
'平衡型'
,
# 综述数据
'now_allocation_amount'
:
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
,
'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
,
'monthly_table_return'
:
self
.
monthly_table_return
,
# 组合数据
'all_folio_result'
:
self
.
all_folio_result
,
# 'totoal_rate_of_return': self.totoal_rate_of_return,
# 'annualised_return': self.annualised_return, 'cost_of_investment': self.cost_of_investment,
#
#
# '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},
#
# 'group_nav_info': self.group_nav_info,
# 'group_hoding_info': self.group_hoding_info,
# 'group_hoding_info_total': self.group_hoding_info_total,
# 'old_evaluation': self.old_evaluation,
# 'old_indicator_compare': self.old_indicator_compare,
# 'contribution_decomposition': self.contribution_decomposition,
# 'single_fund_data_list': self.single_fund_data_list,
# 'old_correlation': self.old_correlation,
# 'old_return_compare_pic': self.old_return_compare_pic,
# # 'new_correlation': self.new_correlation,
# # 'propose_fund_data_list': self.propose_fund_data_list,
# # 'suggestions_result': self.suggestions_result,
# # 'suggestions_result_asset': self.suggestions_result_asset,
# # 'return_compare_pic': self.return_compare_pic,
# # 'indicator_compare': self.indicator_compare,
# # 'new_group_evaluation': self.new_group_evaluation
# 'new_correlation': [],
# 'propose_fund_data_list': [],
# 'suggestions_result': {},
# 'suggestions_result_asset': {},
# 'return_compare_pic': [],
# 'indicator_compare': [],
# 'new_group_evaluation': []
}
# 开始渲染html模板
env
=
Environment
(
loader
=
PackageLoader
(
'app'
,
'templates'
))
# 创建一个包加载器对象
# template = env.get_template('monthReport.html') # 获取一个模板文件
template
=
env
.
get_template
(
'/v2/monthReportV2.1.html'
)
# 获取一个模板文件
monthReport_html
=
template
.
render
(
data
)
# 渲染
# 保存 monthReport_html
# save_file = "app/html/monthReport.html"
# with open(save_file, 'w', encoding="utf-8") as f:
# f.write(monthReport_html)
# save_file = "app/html/v2/monthReportV2.html"
# with open(save_file, 'w', encoding="utf-8") as f:
# f.write(monthReport_html)
html_to_pdf
(
monthReport_html
,
pdf_folder
+
self
.
pdf_name
)
if
__name__
==
'__main__'
:
start
=
time
.
time
()
DataIntegrate
(
ifa_id
=
'USER_INFO15916072577875'
,
customer_id
=
'6716613804182482944'
)
print
(
'耗时{}秒'
.
format
(
round
(
time
.
time
()
-
start
,
2
)))
portfolio_diagnose.py
deleted
100644 → 0
View file @
aded976b
# -*- coding: UTF-8 -*-
"""
@author: Zongxi.Li
@file:portfolio_diagnose.py
@time:2020/12/07
"""
import
warnings
warnings
.
filterwarnings
(
"ignore"
)
from
app.utils.fund_rank
import
*
from
app.utils.risk_parity
import
*
from
app.pypfopt
import
risk_models
from
app.pypfopt
import
expected_returns
from
app.pypfopt
import
EfficientFrontier
from
app.api.engine
import
tamp_product_engine
,
tamp_fund_engine
,
TAMP_SQL
def
cal_correlation
(
prod
):
"""计算组合内基金相关性
Args:
prod: 组合净值表:索引为日期,列名为基金ID, 内容为净值
Returns:屏蔽基金与自身相关性的相关矩阵,因为基金与自身相关性为1,妨碍后续高相关性基金筛选的判断
"""
prod_return
=
prod
.
iloc
[:,
:]
.
apply
(
lambda
x
:
simple_return
(
x
)
.
astype
(
float
))
correlation
=
prod_return
.
corr
()
correlation
=
correlation
.
round
(
2
)
return
correlation
.
mask
(
np
.
eye
(
correlation
.
shape
[
0
],
dtype
=
np
.
bool_
))
def
rename_col
(
df
,
fund_id
):
"""将列名由adj_nav改为基金ID
Args:
df: 原始净值表:索引为日期,列名分别为 ”fund_id“, "adj_nav", 内容为[基金ID,净值]
fund_id: 基金ID
Returns:删除 ”fund_id” 列, 重命名 “adj_nav” 列为基金ID的净值表
"""
df
.
rename
(
columns
=
{
'adj_nav'
:
fund_id
},
inplace
=
True
)
df
.
drop
(
'fund_id'
,
axis
=
1
,
inplace
=
True
)
return
df
def
replace_fund
(
manager
,
substrategy
,
fund_rank
):
"""查找不足半年数据的基金的替代基金
Args:
manager: 基金经理ID
substrategy: 基金二级策略
fund_rank: 基金打分排名表
Returns: 满足相同基金经理ID下的同种二级策略的基金ID的第一个结果
"""
df
=
fund_rank
[(
fund_rank
[
'manager'
]
==
manager
)
&
(
fund_rank
[
'substrategy'
]
==
substrategy
)]
return
df
[
'fund_id'
]
.
values
[
0
]
def
search_rank
(
fund_rank
,
fund
,
metric
):
"""查找基金在基金排名表中的指标
Args:
fund_rank: 基金排名表
fund: 输入基金ID
metric: 查找的指标名称
Returns: 基金指标的值
"""
return
fund_rank
[
fund_rank
[
'fund_id'
]
==
fund
][
metric
]
.
values
[
0
]
def
translate_single
(
content
,
content_id
,
evaluation
):
'''
content = [["优秀","良好","一般"],
["优秀","良好","合格","较差"],
["优秀","良好","合格","较差"],
["高","一般","较低"]]
evaluation = [0,1,1,2]
'''
ret
=
[]
for
i
,
v
in
enumerate
(
evaluation
):
if
isinstance
(
v
,
str
):
ret
.
append
(
v
)
continue
elif
content
[
content_id
][
i
][
v
]
in
[
"优秀"
,
"良好"
,
"高"
,
"高于"
,
"较好"
]:
ret
.
append
(
"""<span class="self_description_red">{}</span>"""
.
format
(
content
[
content_id
][
i
][
v
]))
continue
elif
content_id
==
4
and
v
==
0
:
ret
.
append
(
"""<span class="self_description_red">{}</span>"""
.
format
(
content
[
content_id
][
i
][
v
]))
continue
else
:
ret
.
append
(
"""<span class="self_description_green">{}</span>"""
.
format
(
content
[
content_id
][
i
][
v
]))
return
tuple
(
ret
)
def
choose_good_evaluation
(
evaluation
):
"""抽取好的评价
Args:
evaluation: 个基的评价
Returns: 个基好的评价
"""
v1
=
evaluation
[
1
]
v2
=
evaluation
[
2
]
v3
=
evaluation
[
3
]
v4
=
evaluation
[
4
]
v5
=
evaluation
.
get
(
5
)
if
v1
[
0
]
>
1
:
del
evaluation
[
1
]
if
v2
[
0
]
>
1
and
float
(
v2
[
1
]
.
strip
(
'
%
'
))
<=
60
:
del
evaluation
[
2
]
if
v3
[
0
]
>
1
:
del
evaluation
[
3
]
if
v4
[
0
]
!=
0
or
v4
[
1
]
!=
0
:
del
evaluation
[
4
]
# if v5[0] < 3 or v5[2] > 1: # 基金经理的基金管理年限小于三年或平均业绩处于中下水平
if
v5
:
del
evaluation
[
5
]
return
evaluation
def
choose_bad_evaluation
(
evaluation
):
v1
=
evaluation
[
1
]
v2
=
evaluation
[
2
]
v3
=
evaluation
[
3
]
v4
=
evaluation
[
4
]
if
v1
[
0
]
<
2
:
del
evaluation
[
1
]
if
v2
[
0
]
<
2
:
del
evaluation
[
2
]
if
v3
[
0
]
<
2
:
del
evaluation
[
3
]
if
v4
[
0
]
!=
1
or
v4
[
1
]
!=
1
:
del
evaluation
[
4
]
return
evaluation
def
get_fund_rank
():
"""获取基金指标排名
:return: 基金指标排名表
"""
with
TAMP_SQL
(
tamp_fund_engine
)
as
tamp_fund
:
tamp_fund_session
=
tamp_fund
.
session
sql
=
"SELECT * FROM new_fund_rank"
# df = pd.read_sql(sql, con)
# df = pd.read_csv('fund_rank.csv', encoding='gbk')
cur
=
tamp_fund_session
.
execute
(
sql
)
data
=
cur
.
fetchall
()
df
=
pd
.
DataFrame
(
list
(
data
),
columns
=
[
'index'
,
'fund_id'
,
'range_return'
,
'annual_return'
,
'max_drawdown'
,
'sharp_ratio'
,
'volatility'
,
'sortino_ratio'
,
'downside_risk'
,
'substrategy'
,
'manager'
,
'annual_return_rank'
,
'downside_risk_rank'
,
'max_drawdown_rank'
,
'sharp_ratio_rank'
,
'z_score'
])
df
.
drop
(
'index'
,
axis
=
1
,
inplace
=
True
)
return
df
def
get_index_daily
(
index_id
,
start_date
):
"""获取指数日更数据
Args:
index_id: 指数ID
start_date: 数据开始时间
Returns:与组合净值形式相同的表
"""
with
TAMP_SQL
(
tamp_fund_engine
)
as
tamp_product
:
tamp_product_session
=
tamp_product
.
session
sql
=
"SELECT ts_code, trade_date, close FROM index_daily "
\
"WHERE ts_code='{}' AND trade_date>'{}'"
.
format
(
index_id
,
start_date
)
# df = pd.read_sql(sql, con).dropna(how='any')
cur
=
tamp_product_session
.
execute
(
sql
)
data
=
cur
.
fetchall
()
df
=
pd
.
DataFrame
(
list
(
data
),
columns
=
[
'ts_code'
,
'trade_date'
,
' close'
])
df
.
rename
({
'ts_code'
:
'fund_id'
,
'trade_date'
:
'end_date'
,
'close'
:
'adj_nav'
},
axis
=
1
,
inplace
=
True
)
df
[
'end_date'
]
=
pd
.
to_datetime
(
df
[
'end_date'
])
df
.
set_index
(
'end_date'
,
drop
=
True
,
inplace
=
True
)
df
.
sort_index
(
inplace
=
True
,
ascending
=
True
)
df
=
rename_col
(
df
,
index_id
)
return
df
def
get_index_monthly
(
index_id
,
start_date
):
"""获取指数月度数据
Args:
index_id: 指数ID
start_date: 数据开始时间
Returns:与组合净值形式相同的表
"""
with
TAMP_SQL
(
tamp_fund_engine
)
as
tamp_fund
:
tamp_fund_session
=
tamp_fund
.
session
sql
=
"SELECT ts_code, trade_date, pct_chg FROM index_monthly "
\
"WHERE ts_code='{}' AND trade_date>'{}'"
.
format
(
index_id
,
start_date
)
# df = pd.read_sql(sql, con).dropna(how='any')
cur
=
tamp_fund_session
.
execute
(
sql
)
data
=
cur
.
fetchall
()
df
=
pd
.
DataFrame
(
list
(
data
),
columns
=
[
'fund_id'
,
'end_date'
,
'pct_chg'
])
df
[
'end_date'
]
=
pd
.
to_datetime
(
df
[
'end_date'
])
df
.
set_index
(
'end_date'
,
drop
=
True
,
inplace
=
True
)
df
.
sort_index
(
inplace
=
True
,
ascending
=
True
)
df
=
rename_col
(
df
,
index_id
)
return
df
def
get_tamp_fund
():
"""获取探普产品池净值表
Returns:
"""
with
TAMP_SQL
(
tamp_fund_engine
)
as
tamp_fund
:
tamp_fund_session
=
tamp_fund
.
session
sql
=
"SELECT id FROM tamp_fund_info WHERE id LIKE 'HF
%
'"
cur
=
tamp_fund_session
.
execute
(
sql
)
data
=
cur
.
fetchall
()
# df = pd.read_sql(sql, con)
df
=
pd
.
DataFrame
(
list
(
data
),
columns
=
[
'fund_id'
])
# df.rename({'id': 'fund_id'}, axis=1, inplace=True)
return
df
def
get_tamp_nav
(
fund
,
start_date
,
rollback
=
False
,
invest_type
=
'public'
):
"""获取基金ID为fund, 起始日期为start_date, 终止日期为当前日期的基金净值表
Args:
fund[str]:基金ID
start_date[date]:起始日期
rollback[bool]:当起始日期不在净值公布日历中,是否往前取最近的净值公布日
public[bool]:是否为公募
Returns:df[DataFrame]: 索引为净值公布日, 列为复权净值的净值表; 查询失败则返回None
"""
with
TAMP_SQL
(
tamp_product_engine
)
as
tamp_product
:
tamp_product_session
=
tamp_product
.
session
if
invest_type
==
"private"
:
sql
=
"SELECT fund_id, price_date, cumulative_nav FROM fund_nav "
\
"WHERE fund_id='{}'"
.
format
(
fund
)
# df = pd.read_sql(sql, con).dropna(how='any')
cur
=
tamp_product_session
.
execute
(
sql
)
data
=
cur
.
fetchall
()
df
=
pd
.
DataFrame
(
data
,
columns
=
[
'fund_id'
,
'price_date'
,
'cumulative_nav'
])
.
dropna
(
how
=
'any'
)
df
.
rename
({
'price_date'
:
'end_date'
,
'cumulative_nav'
:
'adj_nav'
},
axis
=
1
,
inplace
=
True
)
# if df2['adj_nav'].count() == 0:
# logging.log(logging.ERROR, "CAN NOT FIND {}".format(fund))
# return None
df
[
'end_date'
]
=
pd
.
to_datetime
(
df
[
'end_date'
])
if
rollback
and
df
[
'end_date'
]
.
min
()
<
start_date
<
df
[
'end_date'
]
.
max
():
while
start_date
not
in
list
(
df
[
'end_date'
]):
start_date
-=
datetime
.
timedelta
(
days
=
1
)
df
=
df
[
df
[
'end_date'
]
>=
start_date
]
df
.
drop_duplicates
(
subset
=
'end_date'
,
inplace
=
True
,
keep
=
'first'
)
df
.
set_index
(
'end_date'
,
inplace
=
True
)
df
.
sort_index
(
inplace
=
True
,
ascending
=
True
)
return
df
def
get_risk_level
(
substrategy
):
"""获取风险类型
Args:
substrategy: 二级策略
Returns:
"""
substrategy2risk
=
{
1
:
"H"
,
1010
:
"H"
,
1020
:
"H"
,
1030
:
"H"
,
2010
:
"H"
,
3010
:
"H"
,
3020
:
"L"
,
3030
:
"H"
,
3040
:
"L"
,
3050
:
"M"
,
4010
:
"M"
,
4020
:
"M"
,
4030
:
"M"
,
4040
:
"M"
,
5010
:
"M"
,
5020
:
"L"
,
5030
:
"M"
,
6010
:
"L"
,
6020
:
"M"
,
6030
:
"L"
,
7010
:
"H"
,
7020
:
"H"
,
8010
:
"H"
,
8020
:
"M"
}
return
substrategy2risk
[
substrategy
]
def
get_radar_data
(
fund
):
df
=
fund_rank
[
fund_rank
[
'fund_id'
]
==
fund
]
return_score
=
df
[
'annual_return_rank'
]
.
values
[
0
]
*
100
downside_score
=
df
[
'downside_risk_rank'
]
.
values
[
0
]
*
100
drawdown_score
=
df
[
'max_drawdown_rank'
]
.
values
[
0
]
*
100
sharpe_score
=
df
[
'sharp_ratio_rank'
]
.
values
[
0
]
*
100
total_score
=
df
[
'z_score'
]
.
values
[
0
]
fund_name
=
get_fund_name
(
fund
)
.
values
[
0
][
0
]
return
{
'name'
:
fund_name
,
'data'
:
[{
'name'
:
'绝对收益'
,
'data'
:
'
%.2
f'
%
return_score
},
{
'name'
:
'抗风险能力'
,
'data'
:
'
%.2
f'
%
downside_score
},
{
'name'
:
'极端风险'
,
'data'
:
'
%.2
f'
%
drawdown_score
},
{
'name'
:
'风险调整后收益'
,
'data'
:
'
%.2
f'
%
sharpe_score
},
{
'name'
:
'业绩持续性'
,
'data'
:
'
%.2
f'
%
np
.
random
.
randint
(
70
,
90
)},
{
'name'
:
'综合评分'
,
'data'
:
'
%.2
f'
%
total_score
}]}
def
get_fund_name
(
fund
):
with
TAMP_SQL
(
tamp_fund_engine
)
as
tamp_fund
:
tamp_fund_session
=
tamp_fund
.
session
sql
=
"SELECT fund_short_name FROM fund_info WHERE id='{}'"
.
format
(
fund
)
# df = pd.read_sql(sql, con)
cur
=
tamp_fund_session
.
execute
(
sql
)
data
=
cur
.
fetchall
()
df
=
pd
.
DataFrame
(
list
(
data
),
columns
=
[
'fund_short_name'
])
return
df
# 获取排名信息
fund_rank
=
get_fund_rank
()
# 获取探普产品池
tamp_fund
=
get_tamp_fund
()
class
PortfolioDiagnose
(
object
):
def
__init__
(
self
,
client_type
,
portfolio
,
invest_amount
,
expect_return
=
0.1
,
expect_drawdown
=
0.15
,
index_id
=
'000905.SH'
,
invest_type
=
'private'
,
start_date
=
None
,
end_date
=
None
):
"""基金诊断
Args:
client_type: 客户类型:1:保守型, 2:稳健型, 3:平衡型, 4:成长型, 5:进取型
portfolio: 投资组合:[基金1, 基金2, 基金3...]
invest_amount: 投资金额:10000000元
expect_return: 期望收益
expect_drawdown: 期望回撤
index_id: 指数ID
invest_type: 投资类型:public, private, ...
start_date: 诊断所需净值的开始日期
end_date: 诊断所需净值的结束日期
"""
self
.
freq_list
=
[]
self
.
client_type
=
client_type
self
.
portfolio
=
portfolio
self
.
expect_return
=
expect_return
self
.
expect_drawdown
=
expect_drawdown
self
.
index_id
=
index_id
self
.
invest_amount
=
invest_amount
self
.
invest_type
=
invest_type
self
.
start_date
=
start_date
self
.
end_date
=
end_date
if
self
.
end_date
is
None
:
self
.
end_date
=
datetime
.
datetime
(
datetime
.
date
.
today
()
.
year
,
datetime
.
date
.
today
()
.
month
,
1
)
-
datetime
.
timedelta
(
1
)
self
.
start_date
=
cal_date
(
self
.
end_date
,
'Y'
,
1
)
self
.
replace_pair
=
dict
()
# 由于数据不足半年而被替换为相同基金经理和策略的原基金和替换基金的映射
self
.
no_data_fund
=
[]
# 未在数据库中找到基金净值或者基金经理记录的基金
self
.
abandon_fund_score
=
[]
# 打分不满足要求的基金
self
.
abandon_fund_corr
=
[]
# 相关性过高
self
.
proposal_fund
=
[]
# 建议的基金
self
.
old_correlation
=
None
self
.
new_correlation
=
None
self
.
old_weights
=
None
self
.
new_weights
=
None
self
.
origin_portfolio
=
None
self
.
abandoned_portfolio
=
None
self
.
propose_portfolio
=
None
def
get_portfolio
(
self
,
):
"""获取组合净值表
Returns:
"""
# 获取原始投资组合的第一支基金的净值表
prod
=
get_tamp_nav
(
self
.
portfolio
[
0
],
self
.
start_date
,
invest_type
=
self
.
invest_type
)
fund_info
=
get_fund_info
(
self
.
end_date
,
invest_type
=
self
.
invest_type
)
# while prod is None or prod.index[-1] - prod.index[0] < 0.6 * (self.end_date - self.start_date):
while
prod
is
None
:
# 获取的净值表为空时首先考虑基金净值数据不足半年,查找同一基金经理下的相同二级策略的基金ID作替换
result
=
fund_info
[
fund_info
[
'fund_id'
]
==
self
.
portfolio
[
0
]]
manager
=
str
(
result
[
'manager'
]
.
values
)
strategy
=
result
[
'substrategy'
]
.
values
replaced_fund
=
replace_fund
(
manager
,
strategy
,
fund_rank
)
if
replaced_fund
:
# 替换基金数据非空则记录替换的基金对
prod
=
get_nav
(
replaced_fund
,
self
.
start_date
,
invest_type
=
self
.
invest_type
)
self
.
replace_pair
[
self
.
portfolio
[
0
]]
=
replaced_fund
else
:
# 替换基金数据为空则记录当前基金为找不到数据的基金, 继续尝试获取下一个基金ID的净值表
self
.
no_data_fund
.
append
(
self
.
portfolio
[
0
])
self
.
portfolio
.
pop
(
0
)
prod
=
get_tamp_nav
(
self
.
portfolio
[
0
],
self
.
start_date
,
invest_type
=
self
.
invest_type
)
# 记录基金的公布频率
self
.
freq_list
.
append
(
get_frequency
(
prod
))
prod
=
rename_col
(
prod
,
self
.
portfolio
[
0
])
# 循环拼接基金净值表构建组合
for
idx
in
range
(
len
(
self
.
portfolio
)
-
1
):
prod1
=
get_tamp_nav
(
self
.
portfolio
[
idx
+
1
],
self
.
start_date
,
invest_type
=
self
.
invest_type
)
# if prod1 is None or prod1.index[-1] - prod1.index[0] < 0.6 * (self.end_date - self.start_date):
if
prod1
is
None
:
result
=
fund_info
[
fund_info
[
'fund_id'
]
==
self
.
portfolio
[
idx
+
1
]]
if
result
[
'fund_manager_id'
]
.
count
()
!=
0
:
manager
=
str
(
result
[
'fund_manager_id'
]
.
values
)
substrategy
=
result
[
'substrategy'
]
.
values
[
0
]
replaced_fund
=
replace_fund
(
manager
,
substrategy
,
fund_rank
)
else
:
self
.
no_data_fund
.
append
(
self
.
portfolio
[
idx
+
1
])
continue
if
replaced_fund
:
prod1
=
get_nav
(
replaced_fund
,
self
.
start_date
,
invest_type
=
self
.
invest_type
)
self
.
replace_pair
[
self
.
portfolio
[
idx
+
1
]]
=
replaced_fund
self
.
freq_list
.
append
(
get_frequency
(
prod1
))
prod1
=
rename_col
(
prod1
,
replaced_fund
)
else
:
self
.
no_data_fund
.
append
(
self
.
portfolio
[
idx
+
1
])
continue
else
:
self
.
freq_list
.
append
(
get_frequency
(
prod1
))
prod1
=
rename_col
(
prod1
,
self
.
portfolio
[
idx
+
1
])
# 取prod表和prod1表的并集
prod
=
pd
.
merge
(
prod
,
prod1
,
on
=
[
'end_date'
],
how
=
'outer'
)
# 对所有合并后的基金净值表按最大周期进行重采样
prod
.
sort_index
(
inplace
=
True
)
prod
.
ffill
(
inplace
=
True
)
prod
=
resample
(
prod
,
get_trade_cal
(),
min
(
self
.
freq_list
))
prod
.
dropna
(
how
=
'any'
,
inplace
=
True
)
return
prod
def
abandon
(
self
,
prod
):
"""建议替换的基金
Args:
prod: 原始组合净值表
Returns: 剔除建议替换基金的组合净值表
"""
self
.
old_correlation
=
cal_correlation
(
prod
)
for
fund
in
prod
.
columns
:
z_score
=
search_rank
(
fund_rank
,
fund
,
metric
=
'z_score'
)
# 建议替换得分为60或与其他基金相关度大于0.8的基金
if
z_score
<
60
:
self
.
abandon_fund_score
.
append
(
fund
)
continue
elif
np
.
any
(
self
.
old_correlation
[
fund
]
>
0.8
):
self
.
abandon_fund_corr
.
append
(
fund
)
prod
=
prod
.
drop
(
self
.
abandon_fund_score
+
self
.
abandon_fund_corr
,
axis
=
1
)
self
.
old_correlation
=
self
.
old_correlation
.
fillna
(
1
)
.
round
(
2
)
self
.
old_correlation
.
columns
=
self
.
old_correlation
.
columns
.
map
(
lambda
x
:
get_fund_name
(
x
)
.
values
[
0
][
0
])
self
.
old_correlation
.
index
=
self
.
old_correlation
.
index
.
map
(
lambda
x
:
get_fund_name
(
x
)
.
values
[
0
][
0
])
return
prod
def
proposal
(
self
,
prod
):
"""建议申购基金
Args:
prod: 剔除建议替换基金的组合净值表
Returns: 增加建议申购基金的组合净值表
"""
# 组合内已包含的策略
# included_strategy = set()
# 按每种基金最少投资100w确定组合包含的最大基金数量
max_len
=
len
(
self
.
portfolio
)
-
len
(
prod
.
columns
)
# 排名表内包含的所有策略
# all_strategy = set(fund_rank['substrategy'].to_list())
all_risk
=
{
"H"
,
"M"
,
"L"
}
included_risk
=
{}
if
prod
is
not
None
:
# included_strategy = set([search_rank(fund_rank, fund, metric='substrategy') for fund in prod.columns])
included_risk
=
set
([
get_risk_level
(
search_rank
(
fund_rank
,
fund
,
metric
=
'substrategy'
))
for
fund
in
prod
.
columns
])
# 待添加策略为所有策略-组合已包含策略
# add_strategy = all_strategy - included_strategy
add_risk
=
all_risk
-
included_risk
# 遍历产品池,推荐得分>80且与组合内其他基金相关度低于0.8的属于待添加策略的基金
for
proposal
in
tamp_fund
[
'fund_id'
]:
if
proposal
in
fund_rank
[
'fund_id'
]
.
to_list
()
and
proposal
not
in
prod
.
columns
:
proposal_z_score
=
search_rank
(
fund_rank
,
proposal
,
metric
=
'z_score'
)
proposal_strategy
=
fund_rank
[
fund_rank
[
'fund_id'
]
==
proposal
][
'substrategy'
]
.
values
[
0
]
else
:
continue
if
proposal_z_score
>
60
and
(
get_risk_level
(
proposal_strategy
)
in
add_risk
or
not
add_risk
):
# if proposal_z_score > 80:
proposal_nav
=
get_tamp_nav
(
proposal
,
self
.
start_date
,
invest_type
=
self
.
invest_type
)
# 忽略净值周期大于周更的产品
# if get_frequency(proposal_nav) <= 52:
# continue
self
.
freq_list
.
append
(
get_frequency
(
proposal_nav
))
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
))
self
.
new_correlation
=
cal_correlation
(
prod
)
judge_correlation
=
self
.
new_correlation
.
fillna
(
0
)
if
np
.
all
(
judge_correlation
<
0.8
):
self
.
proposal_fund
.
append
(
proposal
)
max_len
-=
1
# add_strategy -= {proposal_strategy}
add_risk
-=
{
get_risk_level
(
proposal_strategy
)}
# if len(add_strategy) == 0 or max_len == 0:
if
max_len
==
0
:
break
else
:
prod
.
drop
(
columns
=
proposal
,
inplace
=
True
)
prod
.
dropna
(
how
=
'all'
,
inplace
=
True
)
self
.
new_correlation
=
self
.
new_correlation
.
fillna
(
1
)
.
round
(
2
)
self
.
new_correlation
.
columns
=
self
.
new_correlation
.
columns
.
map
(
lambda
x
:
get_fund_name
(
x
)
.
values
[
0
][
0
])
self
.
new_correlation
.
index
=
self
.
new_correlation
.
index
.
map
(
lambda
x
:
get_fund_name
(
x
)
.
values
[
0
][
0
])
return
prod
def
optimize
(
self
,
):
import
time
start
=
time
.
time
()
self
.
origin_portfolio
=
self
.
get_portfolio
()
end1
=
time
.
time
()
print
(
"原始组合数据获取时间:"
,
end1
-
start
)
self
.
abandoned_portfolio
=
self
.
abandon
(
self
.
origin_portfolio
)
end2
=
time
.
time
()
print
(
"计算换仓基金时间:"
,
end2
-
end1
)
self
.
propose_portfolio
=
self
.
proposal
(
self
.
abandoned_portfolio
)
end3
=
time
.
time
()
print
(
"遍历产品池获取候选推荐时间:"
,
end3
-
end2
)
# propose_portfolio.to_csv('test_portfolio.csv', encoding='gbk')
mu
=
expected_returns
.
mean_historical_return
(
self
.
propose_portfolio
,
frequency
=
min
(
self
.
freq_list
))
S
=
risk_models
.
sample_cov
(
self
.
propose_portfolio
,
frequency
=
min
(
self
.
freq_list
))
dd
=
expected_returns
.
drawdown_from_prices
(
self
.
propose_portfolio
)
# if self.client_type == 1:
# proposal_risk = [[x, get_risk_level(search_rank(fund_rank, x, metric='substrategy'))] for x in
# propose_portfolio.columns]
# self.proposal_fund = list(filter(lambda x: x[1] != 'H', proposal_risk))
# drop_fund_list = list(filter(lambda x: x[1] = 'H', proposal_risk))
# proposal_portfolio = list((set(self.portfolio) - set(self.no_data_fund) - set(self.replace_pair.keys())) | \
# (set(self.proposal_fund) | set(self.replace_pair.values())))
# propose_portfolio.drop()
propose_risk_mapper
=
dict
()
for
fund
in
self
.
propose_portfolio
.
columns
:
propose_risk_mapper
[
fund
]
=
str
(
get_risk_level
(
search_rank
(
fund_rank
,
fund
,
metric
=
'substrategy'
)))
if
self
.
client_type
==
1
:
risk_upper
=
{
"L"
:
0.6
,
"M"
:
0.4
,
"H"
:
0.0
}
risk_lower
=
{
"L"
:
0.6
,
"M"
:
0.4
,
"H"
:
0.0
}
elif
self
.
client_type
==
2
:
risk_upper
=
{
"L"
:
0.5
,
"M"
:
0.3
,
"H"
:
0.2
}
risk_lower
=
{
"L"
:
0.5
,
"M"
:
0.3
,
"H"
:
0.2
}
elif
self
.
client_type
==
3
:
risk_upper
=
{
"L"
:
0.3
,
"M"
:
0.5
,
"H"
:
0.2
}
risk_lower
=
{
"L"
:
0.3
,
"M"
:
0.5
,
"H"
:
0.2
}
elif
self
.
client_type
==
4
:
risk_upper
=
{
"L"
:
0.3
,
"M"
:
0.4
,
"H"
:
0.3
}
risk_lower
=
{
"L"
:
0.3
,
"M"
:
0.4
,
"H"
:
0.3
}
elif
self
.
client_type
==
5
:
risk_upper
=
{
"L"
:
0.0
,
"M"
:
0.5
,
"H"
:
0.5
}
risk_lower
=
{
"L"
:
0.0
,
"M"
:
0.5
,
"H"
:
0.5
}
else
:
risk_upper
=
{
"H"
:
1.0
}
risk_lower
=
{
"L"
:
0.0
}
raise
ValueError
w_low
=
1000000
/
self
.
invest_amount
try
:
ef
=
EfficientFrontier
(
mu
,
S
,
weight_bounds
=
[
w_low
,
1
],
expected_drawdown
=
dd
)
# ef = EfficientFrontier(mu, S, weight_bounds=[0, 1], expected_drawdown=dd)
ef
.
add_sector_constraints
(
propose_risk_mapper
,
risk_lower
,
risk_upper
)
ef
.
efficient_return
(
target_return
=
self
.
expect_return
,
target_drawdown
=
self
.
expect_drawdown
)
clean_weights
=
ef
.
clean_weights
()
ef
.
portfolio_performance
(
verbose
=
True
)
self
.
new_weights
=
np
.
array
(
list
(
clean_weights
.
values
()))
except
:
self
.
new_weights
=
np
.
asarray
([
1
/
len
(
self
.
propose_portfolio
.
columns
)]
*
len
(
self
.
propose_portfolio
.
columns
))
print
(
self
.
new_weights
)
end4
=
time
.
time
()
print
(
"模型计算一次时间:"
,
end4
-
end3
)
# S = np.asmatrix(S)
# w_origin = np.asarray([i for i in w_origin.values()])
# risk_target = np.asarray([1 / len(w_origin)] * len(w_origin))
# self.proposal_weights = calcu_w(w_origin, S, risk_target)
# elif self.client_type == 2:
# elif self.client_type == 3:
# elif self.client_type == 4:
# elif self.client_type == 5:
# print(len(propose_portfolio.columns))
# # 单支基金占投资额的下界为 100W/投资总额
# # w_low = 1e6 / self.invest_amount
# w_low = 0
# w_origin, S, mu = optim_drawdown(propose_portfolio, 0.5, [w_low, 1], min(self.freq_list))
# print(w_origin)
# S = np.asmatrix(S)
# w_origin = np.asarray([i for i in w_origin.values()])
# risk_target = np.asarray([1 / len(w_origin)] * len(w_origin))
# self.proposal_weights = calcu_w(w_origin, S, risk_target)
def
return_compare
(
self
):
index_data
=
get_index_daily
(
self
.
index_id
,
self
.
start_date
)
index_data
=
pd
.
merge
(
index_data
,
self
.
propose_portfolio
,
how
=
'inner'
,
left_index
=
True
,
right_index
=
True
)
index_return
=
index_data
.
iloc
[:,
:]
/
index_data
.
iloc
[
0
,
:]
-
1
# origin_fund_return = origin_portfolio.iloc[:, :] / origin_portfolio.iloc[0, :] - 1
propose_fund_return
=
self
.
propose_portfolio
.
iloc
[:,
:]
/
self
.
propose_portfolio
.
iloc
[
0
,
:]
-
1
propose_fund_return
[
'return'
]
=
propose_fund_return
.
T
.
iloc
[:,
:]
.
apply
(
lambda
x
:
np
.
dot
(
self
.
new_weights
,
x
))
return
index_return
,
propose_fund_return
def
old_evaluation
(
self
,
group_name
,
group_result
,
data_adaptor
):
start_year
=
data_adaptor
.
start_date
.
year
start_month
=
data_adaptor
.
start_date
.
month
current_year
=
data_adaptor
.
end_date
.
year
current_month
=
data_adaptor
.
end_date
.
month
current_day
=
data_adaptor
.
end_date
.
day
past_month
=
(
current_year
-
start_year
)
*
12
+
current_month
-
start_month
# 投入成本(万元)
input_cost
=
round
(
group_result
[
group_name
][
"total_cost"
]
/
10000
,
2
)
# 整体盈利(万元)
total_profit
=
round
(
group_result
[
group_name
][
"cumulative_profit"
]
/
10000
,
2
)
# 整体表现 回撤能力
fund_rank_data
=
fund_rank
[
fund_rank
[
"fund_id"
]
.
isin
(
self
.
portfolio
)]
z_score
=
fund_rank_data
[
"z_score"
]
.
mean
()
drawdown_rank
=
fund_rank_data
[
"max_drawdown_rank"
]
.
mean
()
return_rank_df
=
fund_rank_data
[
"annual_return_rank"
]
z_score_level
=
np
.
select
([
z_score
>=
80
,
70
<=
z_score
<
80
,
z_score
<
70
],
[
0
,
1
,
2
])
.
item
()
drawdown_level
=
np
.
select
([
drawdown_rank
>=
0.8
,
0.7
<=
drawdown_rank
<
0.8
,
0.6
<=
drawdown_rank
<
0.7
,
drawdown_rank
<
0.6
],
[
0
,
1
,
2
,
3
])
.
item
()
# 收益稳健
fund_rank_re
=
fund_rank_data
[
fund_rank_data
[
"annual_return_rank"
]
>
0.8
]
return_rank_evaluate
=
""
if
len
(
fund_rank_re
)
>
0
:
num
=
len
(
fund_rank_re
)
fund_id_rank_list
=
list
(
fund_rank_re
[
"fund_id"
])
for
f_id
in
fund_id_rank_list
:
name
=
data_adaptor
.
user_customer_order_df
[
data_adaptor
.
user_customer_order_df
[
"fund_id"
]
==
f_id
][
"fund_name"
]
.
values
[
0
]
return_rank_evaluate
=
return_rank_evaluate
+
name
+
"、"
return_rank_evaluate
=
return_rank_evaluate
[:
-
1
]
+
"等"
+
str
(
num
)
+
"只产品稳健,对组合的收益率贡献明显,"
# 正收益基金数量
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
()
if
profit_positive_num
>
0
:
profit_positive_evaluate
=
str
(
profit_positive_num
)
+
"只基金取的正收益,"
else
:
profit_positive_evaluate
=
""
# 综合得分较低数量
abandon_num
=
len
(
self
.
abandon_fund_score
)
abandon_evaluate
=
str
(
abandon_num
)
+
"只基金综合得分较低建议更换,"
# 成立时间短
if
len
(
self
.
no_data_fund
)
>
0
:
no_data_fund_evaluate
=
str
(
len
(
self
.
no_data_fund
))
+
"只基金因为成立时间较短,暂不做评价;"
else
:
no_data_fund_evaluate
=
";"
group_order_df
=
data_adaptor
.
user_customer_order_df
[
data_adaptor
.
user_customer_order_df
[
"folio_name"
]
==
group_name
]
strategy_list
=
group_order_df
[
"substrategy"
]
uniqe_strategy
=
list
(
strategy_list
.
unique
())
uniqe_strategy_name
=
[
dict_substrategy
[
int
(
x
)]
+
"、"
for
x
in
uniqe_strategy
]
# 覆盖的基金名称
strategy_name_evaluate
=
""
.
join
(
uniqe_strategy_name
)[:
-
1
]
try
:
if
len
(
uniqe_strategy
)
/
float
(
len
(
strategy_list
))
>
0.6
:
strategy_distribution_evaluate
=
"策略上有一定分散"
else
:
strategy_distribution_evaluate
=
"策略分散程度不高"
except
ZeroDivisionError
:
strategy_distribution_evaluate
=
"策略分散程度不高"
# 相关性
if
len
(
self
.
abandon_fund_corr
)
>
0
:
fund_corr_name
=
[
str
(
group_order_df
[
group_order_df
[
"fund_id"
]
==
f_id
][
"fund_name"
]
.
values
[
0
])
+
"和"
for
f_id
in
self
.
abandon_fund_corr
]
fund_corr_evaluate
=
""
.
join
(
fund_corr_name
)[:
-
1
]
+
"相关性较高,建议调整组合配比;"
else
:
fund_corr_evaluate
=
";"
num_fund
=
len
(
self
.
portfolio
)
evaluate_enum
=
[[
"优秀"
,
"良好"
,
"一般"
],
[
"优秀"
,
"良好"
,
"合格"
,
"较差"
]]
z_score_evaluate
=
evaluate_enum
[
0
][
z_score_level
]
drawdown_evaluate
=
evaluate_enum
[
1
][
drawdown_level
]
if
z_score_evaluate
in
[
"优秀"
,
"良好"
]:
z_score_evaluate
=
"""<span class="self_description_red">{}</span>"""
.
format
(
z_score_evaluate
)
else
:
z_score_evaluate
=
"""<span class="self_description_green">{}</span>"""
.
format
(
z_score_evaluate
)
if
drawdown_evaluate
in
[
"优秀"
,
"良好"
]:
drawdown_evaluate
=
"""<span class="self_description_red">{}</span>"""
.
format
(
drawdown_evaluate
)
else
:
drawdown_evaluate
=
"""<span class="self_description_green">{}</span>"""
.
format
(
drawdown_evaluate
)
sentence
=
{
1
:
"1、组合构建于{}年{}月,至今已运行{}个月。投入成本为{}万元,截止{}年{}月{}日,整体盈利{}万元,整体表现{},回撤控制能力{};
\n
"
,
2
:
"2、组合共持有{}只基金,{}{}{}{}
\n
"
,
3
:
"3、策略角度来看,组合涵盖了{}, {}{}
\n
"
}
data
=
{
1
:
[
start_year
,
start_month
,
past_month
,
input_cost
,
current_year
,
current_month
,
current_day
,
total_profit
,
z_score_evaluate
,
drawdown_evaluate
],
2
:
[
num_fund
,
return_rank_evaluate
,
profit_positive_evaluate
,
abandon_evaluate
,
no_data_fund_evaluate
],
3
:
[
strategy_name_evaluate
,
strategy_distribution_evaluate
,
fund_corr_evaluate
]
}
ret
=
[]
for
k
,
v
in
data
.
items
():
ret
.
append
(
sentence
[
k
]
.
format
(
*
data
[
k
])
.
replace
(
",;"
,
";"
))
# 旧组合累积收益df
group_result_data
=
group_result
[
group_name
]
hold_info
=
group_result_data
[
"group_hoding_info"
]
hold_info_df
=
pd
.
DataFrame
(
hold_info
)
group_order_df
=
data_adaptor
.
user_customer_order_df
[
data_adaptor
.
user_customer_order_df
[
"folio_name"
]
==
group_name
]
group_order_start_date
=
pd
.
to_datetime
(
group_order_df
[
"confirm_share_date"
]
.
min
())
freq_max
=
group_order_df
[
"freq"
]
.
max
()
n_freq
=
freq_days
(
int
(
freq_max
))
old_return_df
=
group_result_data
[
"return_df"
]
old_return_df
[
"cum_return_ratio"
]
=
old_return_df
[
"cum_return_ratio"
]
-
1
# 原组合总市值, 区间收益, 年化收益, 波动率, 最大回撤, 夏普比率
total_asset
=
round
(
hold_info_df
[
"market_values"
]
.
sum
(),
2
)
old_return
=
group_result_data
[
"cumulative_return"
]
old_return_ratio_year
=
group_result_data
[
"return_ratio_year"
]
old_volatility
=
group_result_data
[
"volatility"
]
old_max_drawdown
=
group_result_data
[
"max_drawdown"
]
old_sharpe
=
group_result_data
[
"sharpe"
]
# 指数收益
index_data
=
get_index_daily
(
self
.
index_id
,
self
.
start_date
)
index_data
=
pd
.
merge
(
index_data
,
self
.
propose_portfolio
,
how
=
'inner'
,
left_index
=
True
,
right_index
=
True
)
index_return
=
index_data
.
iloc
[:,
:]
/
index_data
.
iloc
[
0
,
:]
-
1
# 指数收益
index_return
=
index_return
[
index_return
.
index
>=
group_order_start_date
]
start_index_return
=
index_return
[
" close"
]
.
values
[
0
]
index_return
[
"new_index_return"
]
=
(
index_return
[
" close"
]
-
start_index_return
)
/
(
1
+
start_index_return
)
index_return_ratio
=
index_return
[
"new_index_return"
]
.
values
[
-
1
]
index_return_ratio_year
=
annual_return
(
index_return
[
"new_index_return"
]
.
values
[
-
1
],
index_return
[
"new_index_return"
],
n_freq
)
index_volatility
=
volatility
(
index_return
[
"new_index_return"
]
+
1
,
n_freq
)
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
)
# 收益对比数据
return_compare_df
=
pd
.
merge
(
index_return
[[
"new_index_return"
]],
old_return_df
[[
"cum_return_ratio"
]],
right_index
=
True
,
left_index
=
True
)
return_compare_df
[
"date"
]
=
return_compare_df
.
index
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
=
{
"index"
:
{
"name"
:
"中证500"
,
"data"
:
return_compare_df
[
"new_index_return"
]
.
values
*
100
},
"origin_combination"
:
{
"name"
:
"原组合"
,
"data"
:
return_compare_df
[
"cum_return_ratio"
]
.
values
*
100
},
"xlabels"
:
return_compare_df
[
"date"
]
.
values
}
# 指标对比
old_indicator
=
{
"group_name"
:
"现有持仓组合"
,
"return_ratio"
:
round
((
old_return
-
1
)
*
100
,
2
),
"return_ratio_year"
:
round
(
old_return_ratio_year
*
100
,
2
),
"volatility"
:
round
(
old_volatility
*
100
,
2
),
"max_drawdown"
:
round
(
old_max_drawdown
[
0
]
*
100
,
2
),
"sharpe"
:
round
(
old_sharpe
,
2
)}
index_indicator
=
{
"group_name"
:
"中证500"
,
"return_ratio"
:
round
(
index_return_ratio
*
100
,
2
),
"return_ratio_year"
:
round
(
index_return_ratio_year
*
100
,
2
),
"volatility"
:
round
(
index_volatility
*
100
,
2
),
"max_drawdown"
:
round
(
index_drawdown
[
0
]
*
100
,
2
),
"sharpe"
:
round
(
index_sharpe
,
2
)}
old_indicator_compare
=
[
old_indicator
,
index_indicator
]
return
ret
,
old_return_compare_result
,
old_indicator_compare
def
new_evaluation
(
self
,
group_name
,
group_result
,
data_adaptor
):
try
:
group_result_data
=
group_result
[
group_name
]
hold_info
=
group_result_data
[
"group_hoding_info"
]
hold_info_df
=
pd
.
DataFrame
(
hold_info
)
group_order_df
=
data_adaptor
.
user_customer_order_df
[
data_adaptor
.
user_customer_order_df
[
"folio_name"
]
==
group_name
]
group_order_start_date
=
pd
.
to_datetime
(
group_order_df
[
"confirm_share_date"
]
.
min
())
# 原组合总市值, 区间收益, 年化收益, 波动率, 最大回撤, 夏普比率
total_asset
=
round
(
hold_info_df
[
"market_values"
]
.
sum
(),
2
)
old_return
=
group_result_data
[
"cumulative_return"
]
old_return_ratio_year
=
group_result_data
[
"return_ratio_year"
]
old_volatility
=
group_result_data
[
"volatility"
]
old_max_drawdown
=
group_result_data
[
"max_drawdown"
]
old_sharpe
=
group_result_data
[
"sharpe"
]
# 建议基金数据
index_return
,
propose_fund_return
=
self
.
return_compare
()
propose_fund_id_list
=
list
(
propose_fund_return
.
columns
)
propose_fund_id_list
.
remove
(
"return"
)
with
TAMP_SQL
(
tamp_product_engine
)
as
tamp_product
:
tamp_product_session
=
tamp_product
.
session
sql_product
=
"select distinct `id`, `fund_short_name`, `nav_frequency`, `substrategy` from `fund_info`"
cur
=
tamp_product_session
.
execute
(
sql_product
)
data
=
cur
.
fetchall
()
product_df
=
pd
.
DataFrame
(
list
(
data
),
columns
=
[
'fund_id'
,
'fund_name'
,
'freq'
,
'substrategy'
])
propose_fund_df
=
product_df
[
product_df
[
"fund_id"
]
.
isin
(
propose_fund_id_list
)]
# 基金名称,策略分级
propose_fund_id_name_list
=
[
propose_fund_df
[
propose_fund_df
[
"fund_id"
]
==
fund_id
][
"fund_name"
]
.
values
[
0
]
for
fund_id
in
propose_fund_id_list
]
propose_fund_id_strategy_name_list
=
[
dict_substrategy
[
int
(
propose_fund_df
[
propose_fund_df
[
"fund_id"
]
==
fund_id
][
"substrategy"
]
.
values
[
0
])]
for
fund_id
in
propose_fund_id_list
]
propose_fund_asset
=
[
round
(
self
.
new_weights
[
i
]
*
total_asset
,
2
)
for
i
in
range
(
len
(
propose_fund_id_name_list
))]
propose_info
=
{
propose_fund_id_strategy_name_list
[
i
]:
{
"fund_name"
:
propose_fund_id_name_list
[
i
],
"substrategy"
:
propose_fund_id_strategy_name_list
[
i
],
"asset"
:
propose_fund_asset
[
i
]}
for
i
in
range
(
len
(
propose_fund_id_list
))}
# 调仓建议
suggestions_result
=
{}
old_hold_fund_name_list
=
list
(
hold_info_df
[
"fund_name"
])
for
hold
in
hold_info
:
suggestions
=
{}
if
hold
[
"fund_strategy_name"
]
not
in
suggestions_result
.
keys
():
suggestions_result
[
hold
[
"fund_strategy_name"
]]
=
{}
suggestions
[
"fund_strategy_name"
]
=
hold
[
"fund_strategy_name"
]
suggestions
[
"fund_name"
]
=
hold
[
"fund_name"
]
suggestions
[
"before_optimization"
]
=
hold
[
"market_values"
]
suggestions
[
"after_optimization"
]
=
0
if
suggestions
[
"fund_strategy_name"
]
in
propose_fund_id_strategy_name_list
:
suggestions
[
"after_optimization"
]
=
0
suggestions_result
[
hold
[
"fund_strategy_name"
]][
suggestions
[
"fund_name"
]]
=
suggestions
for
key
,
value
in
propose_info
.
items
():
if
value
[
"fund_name"
]
not
in
old_hold_fund_name_list
:
suggestions
=
{}
if
key
not
in
suggestions_result
.
keys
():
suggestions_result
[
key
]
=
{}
suggestions
[
"fund_strategy_name"
]
=
value
[
"substrategy"
]
suggestions
[
"fund_name"
]
=
value
[
"fund_name"
]
suggestions
[
"before_optimization"
]
=
0
suggestions
[
"after_optimization"
]
=
value
[
"asset"
]
suggestions_result
[
key
][
suggestions
[
"fund_name"
]]
=
suggestions
for
key
,
value
in
suggestions_result
.
items
():
suggestions_result
[
key
]
=
list
(
value
.
values
())
suggestions_result_asset
=
{
"before"
:
total_asset
,
"after"
:
total_asset
}
# 旧组合累积收益df
old_return_df
=
group_result_data
[
"return_df"
]
old_return_df
[
"cum_return_ratio"
]
=
old_return_df
[
"cum_return_ratio"
]
-
1
# 新组合累积收益df
propose_fund_return_limit_data
=
propose_fund_return
[
propose_fund_return
.
index
>=
group_order_start_date
]
start_return
=
propose_fund_return_limit_data
[
'return'
]
.
values
[
0
]
propose_fund_return_limit_data
[
"new_return"
]
=
(
propose_fund_return_limit_data
[
"return"
]
-
start_return
)
/
(
1
+
start_return
)
# 新组合累积收益
new_return_ratio
=
propose_fund_return_limit_data
[
"new_return"
]
.
values
[
-
1
]
# 新组合区间年化收益率
freq_max
=
group_order_df
[
"freq"
]
.
max
()
n_freq
=
freq_days
(
int
(
freq_max
))
new_return_ratio_year
=
annual_return
(
propose_fund_return_limit_data
[
"new_return"
]
.
values
[
-
1
],
propose_fund_return_limit_data
,
n_freq
)
# 新组合波动率
new_volatility
=
volatility
(
propose_fund_return_limit_data
[
"new_return"
]
+
1
,
n_freq
)
# 新组合最大回撤
new_drawdown
=
max_drawdown
(
propose_fund_return_limit_data
[
"new_return"
]
+
1
)
# 新组合夏普比率
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
)
# 指数收益
index_return
=
index_return
[
index_return
.
index
>=
group_order_start_date
]
start_index_return
=
index_return
[
" close"
]
.
values
[
0
]
index_return
[
"new_index_return"
]
=
(
index_return
[
" close"
]
-
start_index_return
)
/
(
1
+
start_index_return
)
index_return_ratio
=
index_return
[
"new_index_return"
]
.
values
[
-
1
]
index_return_ratio_year
=
annual_return
(
index_return
[
"new_index_return"
]
.
values
[
-
1
],
index_return
[
"new_index_return"
],
n_freq
)
index_volatility
=
volatility
(
index_return
[
"new_index_return"
]
+
1
,
n_freq
)
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
)
# 收益对比数据
return_compare_df
=
pd
.
merge
(
index_return
[[
"new_index_return"
]],
old_return_df
[[
"cum_return_ratio"
]],
right_index
=
True
,
left_index
=
True
)
return_compare_df
=
pd
.
merge
(
return_compare_df
,
propose_fund_return_limit_data
[
"new_return"
],
right_index
=
True
,
left_index
=
True
)
return_compare_df
[
"date"
]
=
return_compare_df
.
index
return_compare_df
[
"date"
]
=
return_compare_df
[
"date"
]
.
apply
(
lambda
x
:
x
.
strftime
(
"
%
Y-
%
m-
%
d"
))
return_compare_df
.
iloc
[
1
:
-
1
,:][
"date"
]
=
""
return_compare_result
=
{
"new_combination"
:
{
"name"
:
"新组合"
,
"data"
:
return_compare_df
[
"new_return"
]
.
values
*
100
},
"index"
:
{
"name"
:
"中证500"
,
"data"
:
return_compare_df
[
"new_index_return"
]
.
values
*
100
},
"origin_combination"
:
{
"name"
:
"原组合"
,
"data"
:
return_compare_df
[
"cum_return_ratio"
]
.
values
*
100
},
"xlabels"
:
return_compare_df
[
"date"
]
.
values
}
# 指标对比
old_indicator
=
{
"group_name"
:
"现有持仓组合"
,
"return_ratio"
:
round
((
old_return
-
1
)
*
100
,
2
),
"return_ratio_year"
:
round
(
old_return_ratio_year
*
100
,
2
),
"volatility"
:
round
(
old_volatility
*
100
,
2
),
"max_drawdown"
:
round
(
old_max_drawdown
[
0
]
*
100
,
2
),
"sharpe"
:
round
(
old_sharpe
,
2
)}
new_indicator
=
{
"group_name"
:
"建议优化组合"
,
"return_ratio"
:
round
(
new_return_ratio
*
100
,
2
),
"return_ratio_year"
:
round
(
new_return_ratio_year
*
100
,
2
),
"volatility"
:
round
(
new_volatility
*
100
,
2
),
"max_drawdown"
:
round
(
new_drawdown
[
0
]
*
100
,
2
),
"sharpe"
:
round
(
new_sharpe
,
2
)}
index_indicator
=
{
"group_name"
:
"中证500"
,
"return_ratio"
:
round
(
index_return_ratio
*
100
,
2
),
"return_ratio_year"
:
round
(
index_return_ratio_year
*
100
,
2
),
"volatility"
:
round
(
index_volatility
*
100
,
2
),
"max_drawdown"
:
round
(
index_drawdown
[
0
]
*
100
,
2
),
"sharpe"
:
round
(
index_sharpe
,
2
)}
indicator_compare
=
[
new_indicator
,
old_indicator
,
index_indicator
]
# 在保留{}的基础上,建议赎回{},并增配{}后,整体组合波动率大幅降低,最大回撤从{}降到不足{},年化收益率提升{}个点
hold_fund
=
set
(
self
.
portfolio
)
-
set
(
self
.
abandon_fund_score
+
self
.
abandon_fund_corr
+
self
.
no_data_fund
)
hold_fund_name
=
[
get_fund_name
(
x
)
.
values
[
0
][
0
]
for
x
in
hold_fund
]
abandon_fund
=
(
self
.
abandon_fund_score
+
self
.
abandon_fund_corr
)
abandon_fund_name
=
[
get_fund_name
(
x
)
.
values
[
0
][
0
]
for
x
in
abandon_fund
]
proposal_fund
=
self
.
proposal_fund
proposal_fund_name
=
[
get_fund_name
(
x
)
.
values
[
0
][
0
]
for
x
in
proposal_fund
]
sentence
=
[]
if
hold_fund
is
not
None
:
sentence
.
append
(
"在保留"
+
""
.
join
([
i
+
","
for
i
in
hold_fund_name
])
.
rstrip
(
","
)
+
"的基础上"
)
if
abandon_fund
is
not
None
:
sentence
.
append
(
"建议赎回"
+
""
.
join
([
i
+
","
for
i
in
abandon_fund_name
])
.
rstrip
(
","
))
if
proposal_fund
is
not
None
:
sentence
.
append
(
"增配"
+
""
.
join
([
i
+
","
for
i
in
proposal_fund_name
])
.
rstrip
(
","
)
+
"后"
)
if
new_volatility
<
old_volatility
*
0.9
:
sentence
.
append
(
"整体组合波动率大幅降低"
)
if
new_drawdown
<
old_max_drawdown
:
sentence
.
append
(
"最大回撤从{:.2
%
}降到不足{:.2
%
}"
.
format
(
old_max_drawdown
[
0
],
new_drawdown
[
0
]))
if
new_return_ratio_year
>
old_return_ratio_year
:
sentence
.
append
(
"年化收益率提升{:.2f}个点"
.
format
((
new_return_ratio_year
-
old_return_ratio_year
)
*
100
))
whole_sentence
=
","
.
join
(
sentence
)
.
lstrip
(
","
)
+
"。"
return
suggestions_result
,
suggestions_result_asset
,
return_compare_result
,
indicator_compare
,
whole_sentence
except
Exception
as
e
:
repr
(
e
)
return
None
,
None
,
None
,
None
,
None
def
single_evaluation
(
self
,
fund_id
,
objective
=
False
):
"""
1、该基金整体表现优秀/良好/一般,收益能力优秀/良好/合格/较差,回撤控制能力优秀/良好/合格/较差,风险收益比例较高/一般/较低;
2、在收益方面,该基金年化收益能力高于/持平/低于同类基金平均水平,有x
%
区间跑赢大盘/指数,绝对收益能力优秀/一般;
3、在风险方面,该基金抵御风险能力优秀/良好/一般,在同类基金中处于高/中/低等水平,最大回撤为x
%
,高于/持平/低于同类基金平均水平;
4、该基金收益较好/较差的同时回撤较大/较小,也就是说,该基金在用较大/较小风险换取较大/较小收益,存在较高/较低风险;
5、基金经理,投资年限5.23年,经验丰富;投资能力较强,生涯中共管理过X只基金,历任的X只基金平均业绩在同类中处于上游水平,其中x只排名在前x
%
;生涯年化回报率x
%
,同期大盘只有x
%
;
旧个基显示1-4,新个基显示1-5。
旧个基如果是要保留的,显示好的评价。
如果是要剔除的,显示坏的评价。
新个基只显示好的评价。
Args:
fund_id:
Returns:
"""
z_score
=
search_rank
(
fund_rank
,
fund_id
,
metric
=
'z_score'
)
total_level
=
np
.
select
([
z_score
>=
80
,
70
<=
z_score
<
80
,
z_score
<
70
],
[
0
,
1
,
2
])
.
item
()
index_return_monthly
=
get_index_monthly
(
self
.
index_id
,
self
.
start_date
)
fund_nav
=
get_tamp_nav
(
fund_id
,
self
.
start_date
,
invest_type
=
self
.
invest_type
)
fund_nav_monthly
=
fund_nav
.
groupby
([
fund_nav
.
index
.
year
,
fund_nav
.
index
.
month
])
.
tail
(
1
)
fund_nav_monthly
=
rename_col
(
fund_nav_monthly
,
fund_id
)
fund_return_monthly
=
simple_return
(
fund_nav_monthly
[
fund_id
]
.
astype
(
float
))
index_return_monthly
.
index
=
index_return_monthly
.
index
.
strftime
(
'
%
Y-
%
m'
)
fund_return_monthly
.
index
=
fund_return_monthly
.
index
.
strftime
(
'
%
Y-
%
m'
)
compare
=
pd
.
merge
(
index_return_monthly
,
fund_return_monthly
,
how
=
'inner'
,
left_index
=
True
,
right_index
=
True
)
fund_win_rate
=
((
compare
[
fund_id
]
-
compare
[
'pct_chg'
])
>
0
)
.
sum
()
/
compare
[
fund_id
]
.
count
()
return_rank
=
search_rank
(
fund_rank
,
fund_id
,
metric
=
'annual_return_rank'
)
return_level
=
np
.
select
([
return_rank
>=
0.8
,
0.7
<=
return_rank
<
0.8
,
0.6
<=
return_rank
<
0.7
,
return_rank
<
0.6
],
[
0
,
1
,
2
,
3
])
.
item
()
return_bool
=
1
if
return_level
>
2
else
0
return_triple
=
return_level
-
1
if
return_level
>=
2
else
return_level
drawdown_rank
=
search_rank
(
fund_rank
,
fund_id
,
metric
=
'max_drawdown_rank'
)
drawdown_value
=
search_rank
(
fund_rank
,
fund_id
,
metric
=
'max_drawdown'
)
drawdown_level
=
np
.
select
([
drawdown_rank
>=
0.8
,
0.7
<=
drawdown_rank
<
0.8
,
0.6
<=
drawdown_rank
<
0.7
,
drawdown_rank
<
0.6
],
[
0
,
1
,
2
,
3
])
.
item
()
drawdown_bool
=
1
if
drawdown_level
>
2
else
0
drawdown_triple
=
drawdown_level
-
1
if
drawdown_level
>=
2
else
drawdown_level
sharp_rank
=
search_rank
(
fund_rank
,
fund_id
,
metric
=
'sharp_ratio_rank'
)
sharp_level
=
np
.
select
([
sharp_rank
>=
0.8
,
0.6
<=
sharp_rank
<
0.8
,
sharp_rank
<
0.6
],
[
0
,
1
,
2
])
.
item
()
data
=
{
1
:
[
total_level
,
return_level
,
drawdown_level
,
sharp_level
],
2
:
[
return_triple
,
format
(
fund_win_rate
,
'.2
%
'
),
return_bool
],
3
:
[
drawdown_triple
,
drawdown_triple
,
format
(
drawdown_value
,
'.2
%
'
),
drawdown_triple
],
4
:
[
return_bool
,
drawdown_bool
,
drawdown_bool
,
return_bool
,
drawdown_bool
]}
if
fund_id
in
self
.
abandon_fund_score
:
data
[
'remove'
]
=
True
elif
fund_id
in
self
.
proposal_fund
:
data
[
5
]
=
[
1
]
*
7
data
[
'remove'
]
=
False
else
:
data
[
'remove'
]
=
False
x
=
'30
%
'
content
=
{
# 第一个评价
1
:
[[
"优秀"
,
"良好"
,
"一般"
],
[
"优秀"
,
"良好"
,
"合格"
,
"较差"
],
[
"优秀"
,
"良好"
,
"合格"
,
"较差"
],
[
"高"
,
"一般"
,
"较低"
]],
# 第二个评价
2
:
[[
"高于"
,
"持平"
,
"低于"
],
x
,
[
"优秀"
,
"一般"
]],
# 第三个评价
3
:
[[
"优秀"
,
"良好"
,
"一般"
],
[
"高"
,
"中"
,
"低"
],
x
,
[
"高于"
,
"持平"
,
"低于"
]],
# 第四个评价
4
:
[[
"较好"
,
"较差"
],
[
"较小"
,
"较大"
],
[
"较小"
,
"较小"
],
[
"较大"
,
"较小"
],
[
"较低"
,
"较高"
]],
5
:
[[
"TO DO"
]]
*
7
}
sentence
=
{
1
:
"该基金整体表现
%
s,收益能力
%
s,回撤控制能力
%
s,风险收益比例
%
s;
\n
"
,
2
:
"在收益方面,该基金年化收益能力
%
s同类基金平均水平,有
%
s区间跑赢指数,绝对收益能力
%
s;
\n
"
,
3
:
"在风险方面,该基金抵御风险能力
%
s,在同类基金中处于
%
s等水平,最大回撤为
%
s,
%
s同类基金平均水平;
\n
"
,
4
:
"该基金收益
%
s的同时回撤
%
s,也就是说,该基金在用
%
s风险换取
%
s收益,存在
%
s风险;
\n
"
,
5
:
"基金经理,投资年限
%
s年,经验丰富;投资能力较强,生涯中共管理过
%
s只基金,历任的
%
s只基金平均业绩在同类中处于上游水平,其中
%
s只排名在前
%
s;生涯年化回报率
%
s,同期大盘只有
%
s;"
}
remove
=
data
[
"remove"
]
del
data
[
"remove"
]
# 不剔除,选择好的话术
if
not
remove
:
evaluation
=
choose_good_evaluation
(
data
)
# 剔除,选择坏的话术
else
:
evaluation
=
choose_bad_evaluation
(
data
)
ret
=
[]
i
=
1
for
k
,
v
in
evaluation
.
items
():
single_sentence
=
str
(
i
)
+
"、"
+
sentence
[
k
]
%
translate_single
(
content
,
k
,
v
)
ret
.
append
(
single_sentence
)
i
+=
1
fund_name
=
get_fund_name
(
fund_id
)
.
values
[
0
][
0
]
if
not
ret
:
try
:
default_evaluation
=
pd
.
read_csv
(
"evaluation.csv"
,
encoding
=
'utf-8'
,
names
=
[
'fund_id'
,
'eval'
])
ret
.
append
(
'1、'
+
default_evaluation
[
default_evaluation
[
'fund_id'
]
==
fund_id
][
'eval'
]
.
values
[
0
])
except
Exception
:
pass
evaluation_dict
=
{
'name'
:
fund_name
,
'data'
:
ret
}
if
objective
:
if
fund_id
in
self
.
abandon_fund_score
+
self
.
abandon_fund_corr
:
evaluation_dict
[
'status'
]
=
"换仓"
elif
fund_id
in
self
.
portfolio
:
evaluation_dict
[
'status'
]
=
"保留"
else
:
evaluation_dict
[
'status'
]
=
""
return
evaluation_dict
def
old_portfolio_evaluation
(
self
,
objective
=
False
):
try
:
result
=
[]
for
fund
in
self
.
portfolio
:
try
:
result
.
append
(
self
.
single_evaluation
(
fund
,
objective
))
except
IndexError
:
continue
return
result
except
Exception
as
e
:
repr
(
e
)
return
None
def
propose_fund_evaluation
(
self
,
):
try
:
result
=
[]
for
fund
in
self
.
proposal_fund
:
result
.
append
(
self
.
single_evaluation
(
fund
))
return
result
except
Exception
as
e
:
repr
(
e
)
return
None
def
single_fund_radar
(
self
):
radar_data
=
[]
for
fund
in
self
.
portfolio
:
try
:
radar_data
.
append
(
get_radar_data
(
fund
))
except
IndexError
:
continue
return
radar_data
def
propose_fund_radar
(
self
):
radar_data
=
[]
for
fund
in
self
.
proposal_fund
:
radar_data
.
append
(
get_radar_data
(
fund
))
return
radar_data
portfolio
=
[
'HF00002JJ2'
,
'HF00005DBQ'
,
'HF0000681Q'
,
'HF00006693'
,
'HF00006AZF'
,
'HF00006BGS'
]
portfolio_diagnose
=
PortfolioDiagnose
(
client_type
=
1
,
portfolio
=
portfolio
,
invest_amount
=
10000000
)
portfolio_diagnose
.
optimize
()
if
__name__
==
'__main__'
:
print
(
portfolio_diagnose
.
single_fund_radar
())
print
(
portfolio_diagnose
.
propose_fund_radar
())
print
(
portfolio_diagnose
.
old_portfolio_evaluation
())
print
(
'旧组合相关性:'
,
portfolio_diagnose
.
old_correlation
)
print
(
'新组合相关性:'
,
portfolio_diagnose
.
new_correlation
)
print
(
'旧组合个基评价:'
,
portfolio_diagnose
.
old_portfolio_evaluation
())
print
(
'新组合个基评价:'
,
portfolio_diagnose
.
propose_fund_evaluation
())
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment