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
d488e753
Commit
d488e753
authored
Dec 04, 2020
by
李宗熹
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
新组合评价
parent
f1613008
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
43 additions
and
38 deletions
+43
-38
portfolio_diagnose.py
app/service/portfolio_diagnose.py
+42
-33
fund_rank.py
app/utils/fund_rank.py
+1
-5
No files found.
app/service/portfolio_diagnose.py
View file @
d488e753
...
...
@@ -292,6 +292,9 @@ class PortfolioDiagnose(object):
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
,
):
"""获取组合净值表
...
...
@@ -341,7 +344,7 @@ class PortfolioDiagnose(object):
if
replaced_fund
is
not
None
:
prod1
=
get_nav
(
replaced_fund
,
self
.
start_date
,
invest_type
=
self
.
invest_type
)
self
.
replace_pair
[
portfolio
[
0
]]
=
replaced_fund
self
.
replace_pair
[
portfolio
[
idx
+
1
]]
=
replaced_fund
self
.
freq_list
.
append
(
get_frequency
(
prod1
))
prod1
=
rename_col
(
prod1
,
replaced_fund
)
else
:
...
...
@@ -457,20 +460,20 @@ class PortfolioDiagnose(object):
def
optimize
(
self
,
):
import
time
start
=
time
.
time
()
origin_portfolio
=
self
.
get_portfolio
()
self
.
origin_portfolio
=
self
.
get_portfolio
()
end1
=
time
.
time
()
print
(
"原始组合数据获取时间:"
,
end1
-
start
)
abandoned_portfolio
=
self
.
abandon
(
origin_portfolio
)
self
.
abandoned_portfolio
=
self
.
abandon
(
self
.
origin_portfolio
)
end2
=
time
.
time
()
print
(
"计算换仓基金时间:"
,
end2
-
end1
)
propose_portfolio
=
self
.
proposal
(
abandoned_portfolio
)
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
(
propose_portfolio
,
frequency
=
min
(
self
.
freq_list
))
S
=
risk_models
.
sample_cov
(
propose_portfolio
,
frequency
=
min
(
self
.
freq_list
))
dd
=
expected_returns
.
drawdown_from_prices
(
propose_portfolio
)
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
...
...
@@ -483,7 +486,7 @@ class PortfolioDiagnose(object):
# propose_portfolio.drop()
propose_risk_mapper
=
dict
()
for
fund
in
propose_portfolio
.
columns
:
for
fund
in
self
.
propose_portfolio
.
columns
:
propose_risk_mapper
[
fund
]
=
str
(
get_risk_level
(
search_rank
(
fund_rank
,
fund
,
metric
=
'substrategy'
)))
# risk_upper = {"H": 0.0}
...
...
@@ -522,13 +525,10 @@ class PortfolioDiagnose(object):
def
return_compare
(
self
):
index_data
=
get_index_daily
(
self
.
index_id
)
origin_portfolio
=
self
.
get_portfolio
()
abandoned_portfolio
=
self
.
abandon
(
origin_portfolio
)
propose_portfolio
=
self
.
proposal
(
abandoned_portfolio
)
index_data
=
pd
.
merge
(
index_data
,
propose_portfolio
,
how
=
'inner'
,
left_index
=
True
,
right_index
=
True
)
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
=
propose_portfolio
.
iloc
[:,
:]
/
propose_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
...
...
@@ -541,17 +541,17 @@ class PortfolioDiagnose(object):
past_month
=
(
current_year
-
start_year
)
*
12
+
current_month
-
start_month
# 投入成本(万元)
input_cost
=
round
(
group_result
[
group_name
][
"total_cost"
]
/
10000
,
2
)
input_cost
=
round
(
group_result
[
group_name
][
"total_cost"
]
/
10000
,
2
)
# 整体盈利(万元)
total_profit
=
round
(
group_result
[
group_name
][
"cumulative_profit"
]
/
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
()
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
,
...
...
@@ -563,9 +563,10 @@ class PortfolioDiagnose(object):
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
]
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
)
+
"只产品稳健,对组合的收益率贡献明显,"
return_rank_evaluate
=
return_rank_evaluate
[:
-
1
]
+
"等"
+
str
(
num
)
+
"只产品稳健,对组合的收益率贡献明显,"
# 正收益基金数量
group_hold_data
=
pd
.
DataFrame
(
group_result
[
group_name
][
"group_hoding_info"
])
...
...
@@ -585,28 +586,29 @@ class PortfolioDiagnose(object):
else
:
no_data_fund_evaluate
=
";"
group_order_df
=
data_adaptor
.
user_customer_order_df
[
data_adaptor
.
user_customer_order_df
[
"folio_name"
]
==
group_name
]
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
]
if
len
(
uniqe_strategy
)
/
float
(
len
(
strategy_list
))
>
0.6
:
if
len
(
uniqe_strategy
)
/
float
(
len
(
strategy_list
))
>
0.6
:
strategy_distribution_evaluate
=
"策略上有一定分散"
else
:
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_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
]
...
...
@@ -759,23 +761,30 @@ class PortfolioDiagnose(object):
indicator_compare
=
[
new_indicator
,
odl_indicator
]
sentence
=
"在保留{}的基础上,建议赎回{},并增配{}后,整体组合波动率大幅降低,最大回撤从{}降到不足{},年化收益率提升{}个点"
hold_fund
=
set
(
self
.
portfolio
)
-
set
(
self
.
abandon_fund_score
+
self
.
abandon_fund_corr
)
# 在保留{}的基础上,建议赎回{},并增配{}后,整体组合波动率大幅降低,最大回撤从{}降到不足{},年化收益率提升{}个点
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
=
""
sentence
=
[]
if
hold_fund
is
not
None
:
sentence
.
join
(
"在保留"
.
join
(
hold_fund
)
+
"的基础上,
"
)
sentence
.
append
(
"在保留"
+
""
.
join
([
i
+
","
for
i
in
hold_fund_name
])
.
rstrip
(
","
)
+
"的基础上
"
)
if
abandon_fund
is
not
None
:
sentence
.
join
(
"建议赎回"
.
join
(
abandon_fund
)
+
","
)
sentence
.
append
(
"建议赎回"
+
""
.
join
([
i
+
","
for
i
in
abandon_fund_name
])
.
rstrip
(
","
)
)
if
proposal_fund
is
not
None
:
sentence
.
join
(
"增配"
.
join
(
proposal_fund
)
+
"后,"
)
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
.
join
(
"整体组合波动率大幅降低,"
)
sentence
.
append
(
"最大回撤从{:.2
%
}降到不足{:.2
%
}"
.
format
(
old_max_drawdown
[
0
],
new_drawdown
[
0
])
)
if
new_return_ratio_year
>
old_return_ratio_year
:
sentence
.
join
(
"年化收益率提升{}个点。"
.
format
(
round
(
new_return_ratio_year
-
old_return_ratio_year
,
1
)))
return
suggestions_result
,
suggestions_result_asset
,
return_compare_result
,
indicator_compare
,
sentence
sentence
.
append
(
"年化收益率提升{:.2f}个点"
.
format
((
new_return_ratio_year
-
old_return_ratio_year
)
*
100
))
whole_sentence
=
","
.
join
(
sentence
)
.
lstrip
(
","
)
+
"。"
return
suggestions_result
,
suggestions_result_asset
,
whole_sentence
def
single_evaluation
(
self
,
fund_id
):
"""
...
...
app/utils/fund_rank.py
View file @
d488e753
from
sqlalchemy
import
create_engine
# db = create_engine(
# 'mysql+pymysql://tamp_fund:@imeng408@tamper.mysql.polardb.rds.aliyuncs.com:3306/tamp_fund?charset=utf8mb4',
# pool_size=50,
...
...
@@ -43,7 +39,7 @@ def get_nav(fund, start_date, rollback=False, invest_type='public'):
"WHERE ts_code='{}'"
.
format
(
fund
)
cur
=
tamp_product_session
.
execute
(
sql
)
data
=
cur
.
fetchall
()
df
=
pd
.
DataFrame
(
list
(
data
),
columns
=
[
'
ts_code
'
,
'end_date'
,
'adj_nav'
])
.
dropna
(
how
=
'any'
)
df
=
pd
.
DataFrame
(
list
(
data
),
columns
=
[
'
fund_id
'
,
'end_date'
,
'adj_nav'
])
.
dropna
(
how
=
'any'
)
df
.
rename
({
'ts_code'
:
'fund_id'
},
axis
=
1
,
inplace
=
True
)
else
:
sql
=
"SELECT fund_id, price_date, cumulative_nav FROM fund_nav "
\
...
...
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