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
e6e5d8e8
Commit
e6e5d8e8
authored
Dec 09, 2020
by
李宗熹
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
修改基金诊断
parent
742c85d2
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
95 additions
and
78 deletions
+95
-78
efficient_frontier.py
app/pypfopt/efficient_frontier.py
+3
-2
portfolio_diagnose.py
app/service/portfolio_diagnose.py
+91
-75
fund_rank.py
app/utils/fund_rank.py
+1
-1
No files found.
app/pypfopt/efficient_frontier.py
View file @
e6e5d8e8
...
...
@@ -375,7 +375,7 @@ class EfficientFrontier(base_optimizer.BaseConvexOptimizer):
return
self
.
_solve_cvxpy_opt_problem
()
def
efficient_return
(
self
,
target_return
,
market_neutral
=
False
):
def
efficient_return
(
self
,
target_return
,
target_drawdown
,
market_neutral
=
False
):
"""
Calculate the 'Markowitz portfolio', minimising volatility for a given target return.
...
...
@@ -405,12 +405,13 @@ class EfficientFrontier(base_optimizer.BaseConvexOptimizer):
self
.
objective
=
cp
.
quad_form
(
self
.
_w
,
self
.
cov_matrix
)
ret
=
self
.
expected_returns
.
T
@
self
.
_w
drawdown
=
self
.
expected_drawdown
.
T
@
self
.
_w
for
obj
in
self
.
_additional_objectives
:
self
.
_objective
+=
obj
self
.
_constraints
.
append
(
ret
>=
target_return
)
self
.
_constraints
.
append
(
drawdown
<=
target_drawdown
)
# The equality constraint is either "weights sum to 1" (default), or
# "weights sum to 0" (market neutral).
if
market_neutral
:
...
...
app/service/portfolio_diagnose.py
View file @
e6e5d8e8
...
...
@@ -4,6 +4,10 @@
@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
...
...
@@ -113,7 +117,7 @@ def choose_good_evaluation(evaluation):
if
v1
[
0
]
>
1
:
del
evaluation
[
1
]
if
v2
[
0
]
>
1
:
if
v2
[
0
]
>
1
and
float
(
v2
[
1
]
.
strip
(
'
%
'
))
<=
60
:
del
evaluation
[
2
]
if
v3
[
0
]
>
1
:
del
evaluation
[
3
]
...
...
@@ -135,6 +139,7 @@ def choose_bad_evaluation(evaluation):
if
v1
[
0
]
<
2
:
del
evaluation
[
1
]
if
v2
[
0
]
<
2
:
# if v2:
del
evaluation
[
2
]
if
v3
[
0
]
<
2
:
del
evaluation
[
3
]
...
...
@@ -331,8 +336,8 @@ tamp_fund = get_tamp_fund()
class
PortfolioDiagnose
(
object
):
def
__init__
(
self
,
client_type
,
portfolio
,
invest_amount
,
expect_return
=
0.
2
,
expect_drawdown
=
0.1
,
index_id
=
'000905.SH'
,
invest_type
=
'private'
,
start_date
=
None
,
end_date
=
None
):
def
__init__
(
self
,
client_type
,
portfolio
,
invest_amount
,
expect_return
=
0.
1
,
expect_drawdown
=
0.1
5
,
index_id
=
'000905.SH'
,
invest_type
=
'private'
,
start_date
=
None
,
end_date
=
None
):
"""基金诊断
Args:
...
...
@@ -386,6 +391,7 @@ class PortfolioDiagnose(object):
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
]]
...
...
@@ -412,7 +418,8 @@ class PortfolioDiagnose(object):
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 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
:
...
...
@@ -442,6 +449,7 @@ class PortfolioDiagnose(object):
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
):
...
...
@@ -454,8 +462,8 @@ class PortfolioDiagnose(object):
"""
self
.
old_correlation
=
cal_correlation
(
prod
)
for
fund
in
prod
.
columns
:
print
(
fund
)
z_score
=
search_rank
(
fund_rank
,
fund
,
metric
=
'z_score'
)
# 建议替换得分为60或与其他基金相关度大于0.8的基金
if
z_score
<
60
:
...
...
@@ -465,7 +473,7 @@ class PortfolioDiagnose(object):
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
)
prod
.
drop
(
self
.
abandon_fund_score
+
self
.
abandon_fund_corr
,
axis
=
1
,
inplace
=
True
)
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
])
...
...
@@ -480,35 +488,36 @@ class PortfolioDiagnose(object):
Returns: 增加建议申购基金的组合净值表
"""
# 组合内已包含的策略
# included_strategy = set()
# 按每种基金最少投资100w确定组合包含的最大基金数量
max_len
=
self
.
invest_amount
//
1e6
-
len
(
prod
.
columns
)
max_len
=
len
(
self
.
portfolio
)
-
len
(
prod
.
columns
)
# 排名表内包含的所有策略
# all_strategy = set(fund_rank['substrategy'].to_list())
# if prod is not None:
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
():
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]
proposal_strategy
=
fund_rank
[
fund_rank
[
'fund_id'
]
==
proposal
][
'substrategy'
]
.
values
[
0
]
else
:
continue
# if proposal_z_score > 80 and proposal_strategy in add_strategy:
if
proposal_z_score
>
60
:
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
#
if get_frequency(proposal_nav) <= 52:
#
continue
self
.
freq_list
.
append
(
get_frequency
(
proposal_nav
))
proposal_nav
=
rename_col
(
proposal_nav
,
proposal
)
...
...
@@ -517,7 +526,6 @@ class PortfolioDiagnose(object):
prod
=
pd
.
merge
(
prod
,
proposal_nav
,
how
=
'outer'
,
on
=
'end_date'
)
.
astype
(
float
)
prod
.
sort_index
(
inplace
=
True
)
prod
.
ffill
(
inplace
=
True
)
prod
.
bfill
(
inplace
=
True
)
prod
=
resample
(
prod
,
get_trade_cal
(),
min
(
self
.
freq_list
))
self
.
new_correlation
=
cal_correlation
(
prod
)
...
...
@@ -526,14 +534,15 @@ class PortfolioDiagnose(object):
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
])
...
...
@@ -572,32 +581,32 @@ class PortfolioDiagnose(object):
propose_risk_mapper
[
fund
]
=
str
(
get_risk_level
(
search_rank
(
fund_rank
,
fund
,
metric
=
'substrategy'
)))
if
self
.
client_type
==
1
:
risk_upper
=
{
"
H"
:
1
.0
}
risk_lower
=
{
"L"
:
0.0
}
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
=
{
"
H"
:
1.0
}
risk_lower
=
{
"L"
:
0.
0
}
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
=
{
"
H"
:
1.0
}
risk_lower
=
{
"L"
:
0.
0
}
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
=
{
"
H"
:
1.0
}
risk_lower
=
{
"L"
:
0.
0
}
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
=
{
"
H"
:
1.0
}
risk_lower
=
{
"L"
:
0.0
}
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
#
ef = EfficientFrontier(mu, S, weight_bounds=[w_low, 1], expected_drawdown=dd)
ef
=
EfficientFrontier
(
mu
,
S
,
weight_bounds
=
[
0
,
1
],
expected_drawdown
=
dd
)
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
)
ef
.
efficient_return
(
target_return
=
self
.
expect_return
,
target_drawdown
=
self
.
expect_drawdown
)
clean_weights
=
ef
.
clean_weights
()
#
ef.portfolio_performance(verbose=True)
ef
.
portfolio_performance
(
verbose
=
True
)
self
.
new_weights
=
np
.
array
(
list
(
clean_weights
.
values
()))
print
(
clean_weights
)
end4
=
time
.
time
()
...
...
@@ -769,9 +778,11 @@ class PortfolioDiagnose(object):
# 基金名称,策略分级
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
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_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
],
...
...
@@ -813,26 +824,25 @@ class PortfolioDiagnose(object):
# 新组合累积收益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
)
propose_fund_return_limit_data
[
"new_return"
]
=
(
propose_fund_return_limit_data
[
"return"
]
-
start_return
)
/
(
1
+
start_return
)
# 新组合累积收益
try
:
new_return_ratio
=
propose_fund_return_limit_data
[
"new_return"
]
.
values
[
-
1
]
except
:
new_return_ratio
=
0
# 新组合区间年化收益率
freq_max
=
group_order_df
[
"freq"
]
.
max
()
n_freq
=
freq_days
(
int
(
freq_max
))
new_return_ratio_year
=
annual_return
(
new_return_ratio
,
propose_fund_return_limit_data
,
n_freq
)
# 新组合波动率
new_volatility
=
volatility
(
propose_fund_return_limit_data
[
"new_return"
]
+
1
,
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
)
new_drawdown
=
max_drawdown
(
propose_fund_return_limit_data
[
"new_return"
]
+
1
)
# 新组合夏普比率
sim
=
simple_return
(
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
)
...
...
@@ -841,21 +851,23 @@ class PortfolioDiagnose(object):
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
(
propose_fund_return_limit_data
[
"new_return"
]
+
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
(
propose_fund_return_limit_data
[
"new_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
,
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_df
.
iloc
[
1
:
-
1
,
:][
"date"
]
=
""
return_compare_result
=
{
"new_combination"
:
{
"name"
:
"新组合"
,
"data"
:
return_compare_df
[
"new_return"
]
.
values
},
"index"
:
{
"name"
:
"中证500"
,
"data"
:
return_compare_df
[
"new_index_return"
]
.
values
},
...
...
@@ -864,15 +876,20 @@ class PortfolioDiagnose(object):
}
# 指标对比
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
)}
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
]
...
...
@@ -930,7 +947,7 @@ class PortfolioDiagnose(object):
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
()
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
,
...
...
@@ -955,7 +972,7 @@ class PortfolioDiagnose(object):
sharp_rank
<
0.6
],
[
0
,
1
,
2
])
.
item
()
data
=
{
1
:
[
total_level
,
return_level
,
drawdown_level
,
sharp_level
],
2
:
[
return_triple
,
str
(
fund_win_rate
),
return_bool
],
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
]}
...
...
@@ -992,7 +1009,7 @@ class PortfolioDiagnose(object):
sentence
=
{
1
:
"该基金整体表现
%
s,收益能力
%
s,回撤控制能力
%
s,风险收益比例
%
s;
\n
"
,
2
:
"在收益方面,该基金年化收益能力
%
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;"
}
...
...
@@ -1060,14 +1077,13 @@ 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
# test_portfolio = ['HF00002JJ2', 'HF00005DBQ', 'HF0000681Q', 'HF00006693', 'HF00006AZF', 'HF00006BGS']
# portfolio_diagnose = PortfolioDiagnose(client_type=3, portfolio=test_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_correlation)
# print('新组合相关性:', portfolio_diagnose.new_correlation)
# print('旧组合个基评价:', portfolio_diagnose.old_portfolio_evaluation())
# print('新组合个基评价:', portfolio_diagnose.propose_fund_evaluation())
app/utils/fund_rank.py
View file @
e6e5d8e8
...
...
@@ -8,7 +8,7 @@
import
logging
logging
.
basicConfig
(
level
=
logging
.
INFO
)
from
app.api.engine
import
tamp_fund_engine
,
TAMP_SQL
from
app.api.engine
import
tamp_fund_engine
,
TAMP_SQL
,
tamp_product_engine
from
app.utils.week_evaluation
import
*
...
...
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