Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
R
robo-dividend
Project
Project
Details
Activity
Releases
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
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wenwen.tang
robo-dividend
Commits
8ec40d32
Commit
8ec40d32
authored
Dec 25, 2024
by
吕先亚
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
加入中间过程报告
parent
d14e0351
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
140 additions
and
0 deletions
+140
-0
config-mdis_prr3.yml
config-mdis_prr3.yml
+2
-0
funds_selection.py
reports/funds_selection.py
+138
-0
No files found.
config-mdis_prr3.yml
View file @
8ec40d32
...
@@ -234,6 +234,8 @@ reports: # 报告模块相关
...
@@ -234,6 +234,8 @@ reports: # 报告模块相关
min-date
:
~
min-date
:
~
-
name
:
fund-selection-process-report
-
name
:
fund-selection-process-report
min-date
:
~
min-date
:
~
-
name
:
sigma-report
min-date
:
~
email
:
email
:
receives
:
receives
:
-
wenwen.tang@thizgroup.com
-
wenwen.tang@thizgroup.com
...
...
reports/funds_selection.py
0 → 100644
View file @
8ec40d32
import
json
from
datetime
import
datetime
as
dt
from
typing
import
List
import
pandas
as
pd
from
dateutil.relativedelta
import
relativedelta
from
empyrical
import
downside_risk
,
sortino_ratio
from
py_jftech
import
component
,
autowired
,
get_config
,
dict_remove
,
prev_workday
,
filter_weekend
from
api
import
RoboReportor
,
Datum
,
DatumType
,
PortfoliosRisk
,
Navs
from
asset_pool.asset_optimize
import
SortinoAssetOptimize
from
portfolios.solver
import
DefaultFactory
from
rebalance.dao
import
robo_rebalance_signal
as
rrs
@
component
(
bean_name
=
'fund-selection-process-report'
)
class
FundSelectionProcessReportor
(
RoboReportor
):
@
autowired
def
__init__
(
self
,
datum
:
Datum
=
None
,
optimize
:
SortinoAssetOptimize
=
None
,
navs
:
Navs
=
None
):
self
.
_datum
=
datum
self
.
_optimize
=
optimize
self
.
_navs
=
navs
@
property
def
report_name
(
self
)
->
str
:
return
'中間數據报告'
def
load_report
(
self
,
max_date
=
dt
.
today
(),
min_date
=
None
)
->
List
[
dict
]:
day
=
prev_workday
(
filter_weekend
(
max_date
))
funds
=
self
.
_datum
.
get_datums
(
type
=
DatumType
.
FUND
)
fund_ids
=
[
fund
[
'id'
]
for
fund
in
funds
]
pct_change
=
pd
.
DataFrame
(
self
.
_optimize
.
get_pct_change
(
fund_ids
,
day
))
pct_change
.
set_index
(
'date'
,
inplace
=
True
)
pct_change
=
pct_change
.
truncate
(
before
=
(
day
-
relativedelta
(
**
get_config
(
'asset-pool'
)[
'asset-optimize'
][
'annual-volatility-section'
][
0
])))
# 时间未够计算年化波动的直接剔除
funds
=
[
fund
for
fund
in
funds
if
fund
[
'id'
]
in
pct_change
.
columns
]
ratio
=
downside_risk
(
pct_change
)
d_risk
=
ratio
.
to_dict
()
# 索提诺
sortino_conf
=
[{
**
x
,
'name'
:
[
f
"sortino_{y[1]}_{y[0]}"
for
y
in
x
.
items
()
if
y
[
0
]
!=
'weight'
][
0
]
}
for
x
in
get_config
(
'asset-pool'
)[
'asset-optimize'
][
'sortino-weight'
]]
if
'sortino-weight'
in
\
get_config
(
'asset-pool'
)[
'asset-optimize'
]
else
[]
sortino
=
pd
.
DataFrame
()
for
item
in
sortino_conf
:
ratio
=
dict
(
sortino_ratio
(
pct_change
.
truncate
(
before
=
(
day
-
relativedelta
(
**
dict_remove
(
item
,
(
'weight'
,
'name'
)))))))
sortino
=
pd
.
concat
([
sortino
,
pd
.
DataFrame
([
ratio
],
index
=
[
item
[
'name'
]])])
sortino
=
sortino
.
T
sortino
[
'score'
]
=
sortino
.
apply
(
lambda
r
:
sum
([
x
[
'weight'
]
*
r
[
x
[
'name'
]]
for
x
in
sortino_conf
]),
axis
=
1
)
sortino
.
sort_values
(
'score'
,
ascending
=
False
,
inplace
=
True
)
records
=
sortino
.
to_dict
(
orient
=
'index'
)
sortino
=
{
fund_ids
[
k
]:
v
for
k
,
v
in
records
.
items
()}
last_re
=
rrs
.
get_last_one
(
max_date
=
day
,
risk
=
PortfoliosRisk
.
FT3
,
effective
=
True
)
portfolios
=
json
.
loads
(
last_re
[
'portfolio'
])
datas
=
[]
navs
=
self
.
get_navs
(
fund_ids
,
day
)
rtn_annualized
=
self
.
get_rtn_annualized
(
navs
)
for
fund
in
funds
:
data
=
{
'customType'
:
fund
[
'customType'
],
'chineseName'
:
fund
[
'chineseName'
],
'ftRisk'
:
fund
[
'ftRisk'
],
'下行風險'
:
d_risk
.
get
(
fund
[
'id'
]),
'downside_risk_rank'
:
None
,
'短期sortino'
:
sortino
.
get
(
fund
[
'id'
])
.
get
(
'sortino_3_months'
),
'中期sortino'
:
sortino
.
get
(
fund
[
'id'
])
.
get
(
'sortino_6_months'
),
'長期sortino'
:
sortino
.
get
(
fund
[
'id'
])
.
get
(
'sortino_1_years'
),
'score'
:
sortino
.
get
(
fund
[
'id'
])
.
get
(
'score'
),
'sortino_rank'
:
None
,
'加權後各類排名前3名'
:
None
,
'短期報酬'
:
rtn_annualized
[
fund
[
'id'
]],
'MPT計算'
:
f
"{portfolios.get(str(fund['id'])) * 100:.2f}
%
"
if
portfolios
.
get
(
str
(
fund
[
'id'
]))
else
None
,
}
datas
.
append
(
data
)
# 将数据转换为 DataFrame
df
=
pd
.
DataFrame
(
datas
)
# 按 customType 分组,并对每个组内的 score 进行排名
df
[
'sortino_rank'
]
=
df
.
groupby
(
'customType'
)[
'score'
]
.
rank
(
method
=
'dense'
,
ascending
=
False
)
# 将排名结果合并回原始数据
for
i
,
row
in
df
.
iterrows
():
datas
[
i
][
'sortino_rank'
]
=
int
(
row
[
'sortino_rank'
])
if
int
(
row
[
'sortino_rank'
])
<=
3
:
datas
[
i
][
'加權後各類排名前3名'
]
=
True
# 按 customType 分组,并对每个组内的 下行風險 进行排名
df
[
'downside_risk_rank'
]
=
df
.
groupby
(
'customType'
)[
'下行風險'
]
.
rank
(
method
=
'dense'
,
ascending
=
False
)
for
i
,
row
in
df
.
iterrows
():
datas
[
i
][
'downside_risk_rank'
]
=
int
(
row
[
'downside_risk_rank'
])
return
datas
def
get_navs
(
self
,
fund_ids
,
day
):
navs_conf
=
get_config
(
'portfolios'
)[
'solver'
][
'navs'
]
min_date
=
day
-
relativedelta
(
**
navs_conf
[
'range'
])
navs
=
pd
.
DataFrame
(
self
.
_navs
.
get_fund_navs
(
fund_ids
=
fund_ids
,
max_date
=
day
,
min_date
=
min_date
))
navs
=
navs
[
navs
[
'nav_date'
]
.
dt
.
day_of_week
<
5
]
navs
[
'nav_date'
]
=
pd
.
to_datetime
(
navs
[
'nav_date'
])
navs
=
navs
.
pivot_table
(
index
=
'nav_date'
,
columns
=
'fund_id'
,
values
=
'nav_cal'
)
navs
=
navs
.
sort_index
()
navs_nan
=
navs
.
isna
()
.
sum
()
navs
.
drop
(
columns
=
[
x
for
x
in
navs_nan
.
index
if
navs_nan
.
loc
[
x
]
>=
navs_conf
[
'max-nan'
][
'asset'
]],
inplace
=
True
)
navs_nan
=
navs
.
apply
(
lambda
r
:
r
.
isna
()
.
sum
()
/
len
(
r
),
axis
=
1
)
navs
.
drop
(
index
=
[
x
for
x
in
navs_nan
.
index
if
navs_nan
.
loc
[
x
]
>=
navs_conf
[
'max-nan'
][
'day'
]],
inplace
=
True
)
navs
.
fillna
(
method
=
'ffill'
,
inplace
=
True
)
if
navs
.
iloc
[
0
]
.
isna
()
.
sum
()
>
0
:
navs
.
fillna
(
method
=
'bfill'
,
inplace
=
True
)
return
navs
def
get_rtn_annualized
(
self
,
navs
):
result
=
navs
/
navs
.
shift
(
get_config
(
'portfolios'
)[
'solver'
][
'matrix-rtn-days'
])
-
1
result
.
dropna
(
inplace
=
True
)
return
result
.
mean
()
*
12
@
component
(
bean_name
=
'sigma-report'
)
class
SigmaReportor
(
FundSelectionProcessReportor
):
@
autowired
def
__init__
(
self
):
super
()
.
__init__
()
@
property
def
report_name
(
self
)
->
str
:
return
'sigma'
def
load_report
(
self
,
max_date
=
dt
.
today
(),
min_date
=
None
)
->
List
[
dict
]:
day
=
prev_workday
(
filter_weekend
(
max_date
))
funds
=
self
.
_datum
.
get_datums
(
type
=
DatumType
.
FUND
)
fund_ids
=
[
fund
[
'id'
]
for
fund
in
funds
]
navs
=
self
.
get_navs
(
fund_ids
,
day
)
rtn
=
(
navs
/
navs
.
shift
(
1
)
-
1
)[
1
:]
return
rtn
.
cov
()
*
252
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