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
a12f0fb3
Commit
a12f0fb3
authored
Dec 02, 2020
by
李宗熹
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
添加个基评价
parent
33df3fe6
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
94 additions
and
61 deletions
+94
-61
base_optimizer.py
app/pypfopt/base_optimizer.py
+0
-2
portfolio_diagnose.py
app/service/portfolio_diagnose.py
+87
-56
fund_rank.py
app/utils/fund_rank.py
+7
-3
No files found.
app/pypfopt/base_optimizer.py
View file @
a12f0fb3
...
...
@@ -305,8 +305,6 @@ class BaseConvexOptimizer(BaseOptimizer):
is_sector
=
[
sector_mapper
[
t
]
==
sector
for
t
in
self
.
tickers
]
self
.
_constraints
.
append
(
cp
.
sum
(
self
.
_w
[
is_sector
])
>=
sector_lower
[
sector
])
print
(
self
.
_constraints
)
def
convex_objective
(
self
,
custom_objective
,
weights_sum_to_one
=
True
,
**
kwargs
):
"""
Optimise a custom convex objective function. Constraints should be added with
...
...
app/service/portfolio_diagnose.py
View file @
a12f0fb3
...
...
@@ -16,6 +16,7 @@ def cal_correlation(prod):
"""
prod_return
=
prod
.
iloc
[:,
:]
.
apply
(
lambda
x
:
simple_return
(
x
))
correlation
=
prod_return
.
corr
()
correlation
=
correlation
.
round
(
2
)
return
correlation
.
mask
(
np
.
eye
(
correlation
.
shape
[
0
],
dtype
=
np
.
bool
))
...
...
@@ -92,7 +93,8 @@ def choose_good_evaluation(evaluation):
if
v1
[
0
]
>
1
:
del
evaluation
[
1
]
if
v2
[
0
]
>
1
:
# if v2[0] > 1:
if
v2
:
del
evaluation
[
2
]
if
v3
[
0
]
>
1
:
del
evaluation
[
3
]
...
...
@@ -112,7 +114,8 @@ def choose_bad_evaluation(evaluation):
if
v1
[
0
]
<
2
:
del
evaluation
[
1
]
if
v2
[
0
]
<
2
:
# if v2[0] < 2:
if
v2
:
del
evaluation
[
2
]
if
v3
[
0
]
<
2
:
del
evaluation
[
3
]
...
...
@@ -207,7 +210,7 @@ def get_fund_name(fund):
# 获取排名信息
fund_rank
=
get_fund_rank
()
# 获取探普产品池
tamp_fund
=
get_
fund_rank
()
tamp_fund
=
get_
tamp_fund
()
class
PortfolioDiagnose
(
object
):
...
...
@@ -337,6 +340,10 @@ class PortfolioDiagnose(object):
if
np
.
any
(
self
.
old_correlation
[
fund
]
>
0.8
):
self
.
abandon_fund_corr
.
append
(
fund
)
prod
=
prod
.
drop
(
fund
,
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
):
...
...
@@ -349,17 +356,17 @@ class PortfolioDiagnose(object):
"""
# 组合内已包含的策略
included_strategy
=
set
()
#
included_strategy = set()
# 按每种基金最少投资100w确定组合包含的最大基金数量
max_len
=
self
.
invest_amount
//
1e6
-
len
(
prod
.
columns
)
# 排名表内包含的所有策略
all_strategy
=
set
(
fund_rank
[
'substrategy'
]
.
to_list
())
if
prod
is
not
None
:
included_strategy
=
set
([
search_rank
(
fund_rank
,
fund
,
metric
=
'substrategy'
)
for
fund
in
prod
.
columns
])
#
all_strategy = set(fund_rank['substrategy'].to_list())
#
if prod is not None:
#
included_strategy = set([search_rank(fund_rank, fund, metric='substrategy') for fund in prod.columns])
# 待添加策略为所有策略-组合已包含策略
add_strategy
=
all_strategy
-
included_strategy
#
add_strategy = all_strategy - included_strategy
# 遍历产品池,推荐得分>80且与组合内其他基金相关度低于0.8的属于待添加策略的基金
for
proposal
in
tamp_fund
[
'fund_id'
]:
...
...
@@ -370,8 +377,8 @@ class PortfolioDiagnose(object):
else
:
continue
if
proposal_z_score
>
80
and
proposal_strategy
in
add_strategy
:
# if proposal_z_score > 8
0:
#
if proposal_z_score > 80 and proposal_strategy in add_strategy:
if
proposal_z_score
>
6
0
:
proposal_nav
=
get_nav
(
proposal
,
self
.
start_date
,
invest_type
=
self
.
invest_type
)
# 忽略净值周期大于周更的产品
...
...
@@ -387,29 +394,42 @@ class PortfolioDiagnose(object):
prod
.
ffill
(
inplace
=
True
)
prod
=
resample
(
prod
,
get_trade_cal
(),
min
(
self
.
freq_list
))
_correlation
=
cal_correlation
(
prod
)
_correlation
=
_correlation
.
fillna
(
0
)
self
.
new
_correlation
=
cal_correlation
(
prod
)
judge_correlation
=
self
.
new
_correlation
.
fillna
(
0
)
if
np
.
all
(
_correlation
<
0.8
):
if
np
.
all
(
judge
_correlation
<
0.8
):
self
.
proposal_fund
.
append
(
proposal
)
max_len
-=
1
add_strategy
-=
{
proposal_strategy
}
if
len
(
add_strategy
)
==
0
or
max_len
==
0
:
#
if max_len == 0:
#
add_strategy -= {proposal_strategy}
#
if len(add_strategy) == 0 or max_len == 0:
if
max_len
==
0
:
break
else
:
prod
.
drop
(
columns
=
proposal
,
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
()
origin_portfolio
=
self
.
get_portfolio
()
end1
=
time
.
time
()
print
(
"原始组合数据获取时间:"
,
end1
-
start
)
abandoned_portfolio
=
self
.
abandon
(
origin_portfolio
)
end2
=
time
.
time
()
print
(
"计算换仓基金时间:"
,
end2
-
end1
)
propose_portfolio
=
self
.
proposal
(
abandoned_portfolio
)
end3
=
time
.
time
()
print
(
"遍历产品池获取候选推荐时间:"
,
end3
-
end2
)
# propose_portfolio.to_csv('test_portfolio.csv', encoding='gbk')
returns
=
propose_portfolio
.
pct_change
()
.
dropna
()
mu
=
expected_returns
.
mean_historical_return
(
propose_portfolio
)
S
=
risk_models
.
sample_cov
(
propose_portfolio
)
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
)
# if self.client_type == 1:
# proposal_risk = [[x, get_risk_level(search_rank(fund_rank, x, metric='substrategy'))] for x in
# self.proposal_fund]
...
...
@@ -422,13 +442,16 @@ class PortfolioDiagnose(object):
risk_upper
=
{
"H"
:
0.0
}
risk_lower
=
{
"L"
:
0.6
,
"M"
:
0.4
}
ef
=
EfficientFrontier
(
mu
,
S
)
ef
=
EfficientFrontier
(
mu
,
S
,
expected_drawdown
=
dd
)
ef
.
add_sector_constraints
(
propose_risk_mapper
,
risk_lower
,
risk_upper
)
# weights = ef.nonconvex_objective(deviation_risk_parity, ef.cov_matrix)
ef
.
efficient_
return
(
0.2
)
ef
.
efficient_
drawdown
(
drawdown_limit
=
0.5
)
clean_weights
=
ef
.
clean_weights
()
# ef.portfolio_performance(verbose=True)
self
.
new_weights
=
np
.
array
(
list
(
clean_weights
.
values
()))
print
(
clean_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))
...
...
@@ -471,7 +494,7 @@ class PortfolioDiagnose(object):
current_day
=
datetime
.
datetime
.
now
()
.
day
past_month
=
(
current_year
-
start_year
)
*
12
+
current_month
-
start_month
num_fund
=
len
(
self
.
portfolio
)
abandon_fund
=
[[
x
,
self
.
invest_type
]
for
x
in
self
.
abandon_fund
]
abandon_fund
=
[[
x
,
self
.
invest_type
]
for
x
in
self
.
abandon_fund
_score
+
self
.
abandon_fund_corr
]
old_strategy
=
set
([
search_rank
(
fund_rank
,
x
,
metric
=
'substrategy'
)
for
x
in
self
.
portfolio
])
data
=
[
start_year
,
start_month
,
past_month
,
self
.
invest_amount
,
...
...
@@ -532,11 +555,11 @@ class PortfolioDiagnose(object):
sharp_rank
<
0.6
],
[
0
,
1
,
2
])
.
item
()
data
=
{
1
:
[
total_level
,
return_level
,
drawdown_level
,
sharp_level
],
2
:
[
return_triple
,
"
TO DO"
,
return_triple
],
3
:
[
drawdown_triple
,
drawdown_triple
,
drawdown_value
,
drawdown_triple
],
2
:
[
return_triple
,
"
12"
,
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
:
if
fund_id
in
self
.
abandon_fund
_score
:
data
[
'remove'
]
=
True
elif
fund_id
in
self
.
proposal_fund
:
data
[
5
]
=
[
1
]
*
7
...
...
@@ -545,33 +568,34 @@ class PortfolioDiagnose(object):
data
[
'remove'
]
=
False
x
=
'30
%
'
# 第一个评价
content
=
{
1
:
[[
"优秀"
,
"良好"
,
"一般"
],
[
"优秀"
,
"良好"
,
"合格"
,
"较差"
],
[
"优秀"
,
"良好"
,
"合格"
,
"较差"
],
[
"高"
,
"一般"
,
"较低"
]],
# 第二个评价
2
:
[[
"高于"
,
"持平"
,
"低于"
],
x
,
[
"优秀"
,
"一般"
]],
# 第三个评价
3
:
[[
"优秀"
,
"良好"
,
"一般"
],
[
"高"
,
"中"
,
"低"
],
x
,
[
"高于"
,
"持平"
,
"低于"
]],
# 第四个评价
4
:
[[
"较好"
,
"较差"
],
[
"较小"
,
"较大"
],
[
"较小"
,
"较小"
],
[
"较大"
,
"较小"
],
[
"较低"
,
"较高"
]],
5
:
[[
"TO DO"
]
*
7
]}
content
=
{
# 第一个评价
1
:
[[
"优秀"
,
"良好"
,
"一般"
],
[
"优秀"
,
"良好"
,
"合格"
,
"较差"
],
[
"优秀"
,
"良好"
,
"合格"
,
"较差"
],
[
"高"
,
"一般"
,
"较低"
]],
# 第二个评价
2
:
[[
"高于"
,
"持平"
,
"低于"
],
x
,
[
"优秀"
,
"一般"
]],
# 第三个评价
3
:
[[
"优秀"
,
"良好"
,
"一般"
],
[
"高"
,
"中"
,
"低"
],
x
,
[
"高于"
,
"持平"
,
"低于"
]],
# 第四个评价
4
:
[[
"较好"
,
"较差"
],
[
"较小"
,
"较大"
],
[
"较小"
,
"较小"
],
[
"较大"
,
"较小"
],
[
"较低"
,
"较高"
]],
5
:
[[
"TO DO"
]]
*
7
}
sentence
=
{
1
:
"
1、
该基金整体表现
%
s,收益能力
%
s,回撤控制能力
%
s,风险收益比例
%
s;
\n
"
,
2
:
"
2、
在收益方面,该基金年化收益能力
%
s同类基金平均水平,有
%
s区间跑赢指数,绝对收益能力
%
s;
\n
"
,
3
:
"
3、
在风险方面,该基金抵御风险能力
%
s,在同类基金中处于
%
s等水平,最大回撤为
%
s,
%
s同类基金平均水平;
\n
"
,
4
:
"
4、
该基金收益
%
s的同时回撤
%
s,也就是说,该基金在用
%
s风险换取
%
s收益,存在
%
s风险;
\n
"
,
5
:
"
5、
基金经理,投资年限
%
s年,经验丰富;投资能力较强,生涯中共管理过
%
s只基金,历任的
%
s只基金平均业绩在同类中处于上游水平,其中
%
s只排名在前
%
s;生涯年化回报率
%
s,同期大盘只有
%
s;"
}
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"
]
...
...
@@ -582,18 +606,21 @@ class PortfolioDiagnose(object):
# 剔除,选择坏的话术
else
:
evaluation
=
choose_bad_evaluation
(
data
)
print
(
evaluation
)
ret
=
""
for
k
,
v
in
evaluation
.
items
():
# print(translate_single(content[k], v))
ret
=
ret
+
sentence
[
k
]
%
translate_single
(
content
[
k
],
v
)
return
{
fund_id
:
ret
}
fund_name
=
get_fund_name
(
fund_id
)
.
values
[
0
][
0
]
return
{
'name'
:
fund_name
,
'data'
:
ret
}
def
old_portfolio_evaluation
(
self
,
):
result
=
[]
for
fund
in
self
.
portfolio
:
result
.
append
(
self
.
single_evaluation
(
fund
))
try
:
result
.
append
(
self
.
single_evaluation
(
fund
))
except
IndexError
:
continue
return
result
def
propose_fund_evaluation
(
self
,
):
...
...
@@ -622,6 +649,10 @@ portfolio = ['HF00002JJ2', 'HF00005DBQ', 'HF0000681Q', 'HF00006693', 'HF00006AZF
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.propose_fund_evaluation())
# 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
())
app/utils/fund_rank.py
View file @
a12f0fb3
# import pymysql
from
sqlalchemy
import
create_engine
db
=
create_engine
(
'mysql+pymysql://tamp_fund:@imeng408@tamper.mysql.polardb.rds.aliyuncs.com:3306/tamp_fund?charset=utf8mb4'
)
'mysql+pymysql://tamp_fund:@imeng408@tamper.mysql.polardb.rds.aliyuncs.com:3306/tamp_fund?charset=utf8mb4'
,
pool_size
=
50
,
pool_recycle
=
3600
,
pool_pre_ping
=
True
)
con
=
db
.
connect
()
import
logging
logging
.
basicConfig
(
level
=
logging
.
INFO
)
logging
.
basicConfig
(
level
=
logging
.
INFO
)
from
app.utils.week_evaluation
import
*
...
...
@@ -297,4 +301,4 @@ if __name__ == '__main__':
# fund_rank.to_csv("fund_rank.csv", encoding='gbk')
# df = pd.read_csv('fund_rank.csv')
# df.to_sql("fund_rank", con, if_exists='replace')
con
.
close
()
\ No newline at end of file
con
.
close
()
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