Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
A
alpha-mind
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
Dr.李
alpha-mind
Commits
233c92ad
Unverified
Commit
233c92ad
authored
Mar 16, 2018
by
lion-sing
Committed by
GitHub
Mar 16, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #6 from alpha-miner/master
update
parents
9b36cc04
79792651
Changes
18
Show whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
1064 additions
and
15835 deletions
+1064
-15835
README.md
README.md
+2
-2
crosssetctions.py
alphamind/analysis/crosssetctions.py
+94
-0
factoranalysis.py
alphamind/analysis/factoranalysis.py
+1
-1
models.py
alphamind/data/dbmodel/models.py
+1
-13
neutralize.py
alphamind/data/neutralize.py
+9
-14
rank.py
alphamind/data/rank.py
+2
-2
factor_analysis_example.py
alphamind/examples/factor_analysis_example.py
+211
-242
factor_res_analysis.py
alphamind/examples/factor_res_analysis.py
+1
-1
composer.py
alphamind/model/composer.py
+3
-1
constraints.py
alphamind/portfolio/constraints.py
+11
-4
test_rank.py
alphamind/tests/data/test_rank.py
+25
-1
Example 1 - Factor IC analysis.ipynb
notebooks/Example 1 - Factor IC analysis.ipynb
+53
-23
Example 2 - Strategy Analysis.ipynb
notebooks/Example 2 - Strategy Analysis.ipynb
+41
-28
Example 3 - Multi Weight Gap Comparison.ipynb
notebooks/Example 3 - Multi Weight Gap Comparison.ipynb
+80
-1410
Example 4 - Single Factor Analysis.ipynb
notebooks/Example 4 - Single Factor Analysis.ipynb
+42
-14048
Example 5 - Style Factor Analysis.ipynb
notebooks/Example 5 - Style Factor Analysis.ipynb
+180
-0
notebook_utilities.py
notebooks/notebook_utilities.py
+128
-0
update_uqer_data_postgres.py
scripts/update_uqer_data_postgres.py
+180
-45
No files found.
README.md
View file @
233c92ad
...
...
@@ -4,8 +4,8 @@
<tr>
<td>
Build Status
</td>
<td>
<a
href=
"https://travis-ci.org/
wegamekinglc
/alpha-mind"
>
<img
src=
"https://travis-ci.org/
wegamekinglc
/alpha-mind.svg?branch=master"
alt=
"travis build status"
/>
<a
href=
"https://travis-ci.org/
alpha-miner
/alpha-mind"
>
<img
src=
"https://travis-ci.org/
alpha-miner
/alpha-mind.svg?branch=master"
alt=
"travis build status"
/>
</a>
</td>
</tr>
...
...
alphamind/analysis/crosssetctions.py
0 → 100644
View file @
233c92ad
# -*- coding: utf-8 -*-
"""
Created on 2018-3-5
@author: cheng.li
"""
import
numpy
as
np
import
pandas
as
pd
import
statsmodels.api
as
sm
from
alphamind.utilities
import
alpha_logger
from
alphamind.data.processing
import
factor_processing
def
cs_impl
(
ref_date
,
factor_data
,
factor_name
,
risk_exposure
,
constraint_risk
,
industry_matrix
,
dx_returns
):
total_data
=
pd
.
merge
(
factor_data
,
risk_exposure
,
on
=
'code'
)
total_data
=
pd
.
merge
(
total_data
,
industry_matrix
,
on
=
'code'
)
.
dropna
()
if
len
(
total_data
)
<
0.33
*
len
(
factor_data
):
alpha_logger
.
warning
(
f
"valid data point({len(total_data)}) "
f
"is less than 33
%
of the total sample ({len(factor_data)}). Omit this run"
)
return
np
.
nan
,
np
.
nan
,
np
.
nan
total_risk_exp
=
total_data
[
constraint_risk
]
er
=
total_data
[
factor_name
]
.
values
.
astype
(
float
)
er
=
factor_processing
(
er
,
[],
total_risk_exp
.
values
,
[])
.
flatten
()
industry
=
total_data
.
industry_name
.
values
codes
=
total_data
.
code
.
tolist
()
target_pos
=
pd
.
DataFrame
({
'code'
:
codes
,
'weight'
:
er
,
'industry'
:
industry
})
target_pos
[
'weight'
]
=
target_pos
[
'weight'
]
/
target_pos
[
'weight'
]
.
abs
()
.
sum
()
target_pos
=
pd
.
merge
(
target_pos
,
dx_returns
,
on
=
[
'code'
])
target_pos
=
pd
.
merge
(
target_pos
,
total_data
[[
'code'
]
+
constraint_risk
],
on
=
[
'code'
])
activate_weight
=
target_pos
.
weight
.
values
excess_return
=
np
.
exp
(
target_pos
.
dx
.
values
)
-
1.
port_ret
=
np
.
log
(
activate_weight
@
excess_return
+
1.
)
ic
=
np
.
corrcoef
(
excess_return
,
activate_weight
)[
0
,
1
]
x
=
sm
.
add_constant
(
activate_weight
)
results
=
sm
.
OLS
(
excess_return
,
x
)
.
fit
()
t_stats
=
results
.
tvalues
[
1
]
alpha_logger
.
info
(
f
"{ref_date} is finished with {len(target_pos)} stocks for {factor_name}"
)
alpha_logger
.
info
(
f
"{ref_date} risk_exposure: "
f
"{np.sum(np.square(target_pos.weight.values @ target_pos[constraint_risk].values))}"
)
return
port_ret
,
ic
,
t_stats
def
cross_section_analysis
(
ref_date
,
factor_name
,
universe
,
horizon
,
constraint_risk
,
engine
):
codes
=
engine
.
fetch_codes
(
ref_date
,
universe
)
risk_exposure
=
engine
.
fetch_risk_model
(
ref_date
,
codes
)[
1
][[
'code'
]
+
constraint_risk
]
factor_data
=
engine
.
fetch_factor
(
ref_date
,
factor_name
,
codes
)
industry_matrix
=
engine
.
fetch_industry_matrix
(
ref_date
,
codes
,
'sw_adj'
,
1
)
dx_returns
=
engine
.
fetch_dx_return
(
ref_date
,
codes
,
horizon
=
horizon
,
offset
=
1
)
return
cs_impl
(
ref_date
,
factor_data
,
factor_name
,
risk_exposure
,
constraint_risk
,
industry_matrix
,
dx_returns
)
if
__name__
==
'__main__'
:
import
numpy
as
np
import
pandas
as
pd
import
statsmodels.api
as
sm
from
alphamind.api
import
*
factor_name
=
'SIZE'
data_source
=
'postgres+psycopg2://postgres:A12345678!@10.63.6.220/alpha'
engine
=
SqlEngine
(
data_source
)
risk_names
=
list
(
set
(
risk_styles
)
.
difference
({
factor_name
}))
industry_names
=
list
(
set
(
industry_styles
)
.
difference
({
factor_name
}))
constraint_risk
=
risk_names
+
industry_names
universe
=
Universe
(
'custom'
,
[
'ashare_ex'
])
horizon
=
9
x
=
cross_section_analysis
(
'2018-02-08'
,
factor_name
,
universe
,
horizon
,
constraint_risk
,
engine
=
engine
)
print
(
x
)
alphamind/analysis/factoranalysis.py
View file @
233c92ad
...
...
@@ -90,7 +90,7 @@ def er_portfolio_analysis(er: np.ndarray,
cons_exp
=
constraints
.
risk_exp
return
lbound
,
ubound
,
cons_exp
,
risk_lbound
,
risk_ubound
if
benchmark
is
not
None
and
method
==
'risk_neutral'
:
if
method
==
'risk_neutral'
:
lbound
,
ubound
,
cons_exp
,
risk_lbound
,
risk_ubound
=
create_constraints
(
benchmark
,
**
kwargs
)
turn_over_target
=
kwargs
.
get
(
'turn_over_target'
)
...
...
alphamind/data/dbmodel/models.py
View file @
233c92ad
...
...
@@ -1921,18 +1921,6 @@ class Gogoal(Base):
tcap
=
Column
(
Float
(
53
))
class
OutrightTmp
(
Base
):
__tablename__
=
'outright_tmp'
__table_args__
=
(
Index
(
'outright_trade_date_code_portfolio_name_uindex'
,
'trade_date'
,
'code'
,
'portfolio_name'
,
unique
=
True
),
)
trade_date
=
Column
(
DateTime
,
primary_key
=
True
,
nullable
=
False
)
code
=
Column
(
Integer
,
primary_key
=
True
,
nullable
=
False
)
portfolio_name
=
Column
(
String
(
50
),
primary_key
=
True
,
nullable
=
False
)
volume
=
Column
(
Integer
,
nullable
=
False
)
class
Outright
(
Base
):
__tablename__
=
'outright'
__table_args__
=
(
...
...
@@ -1956,5 +1944,5 @@ class Outright(Base):
if
__name__
==
'__main__'
:
from
sqlalchemy
import
create_engine
engine
=
create_engine
(
'postgres+psycopg2://postgres:we083826@1
01.132.104.118
/alpha'
)
engine
=
create_engine
(
'postgres+psycopg2://postgres:we083826@1
92.168.0.102
/alpha'
)
Base
.
metadata
.
create_all
(
engine
)
alphamind/data/neutralize.py
View file @
233c92ad
...
...
@@ -16,16 +16,12 @@ import alphamind.utilities as utils
def
neutralize
(
x
:
np
.
ndarray
,
y
:
np
.
ndarray
,
groups
:
np
.
ndarray
=
None
,
detail
:
bool
=
False
,
weights
:
np
.
ndarray
=
None
)
\
detail
:
bool
=
False
)
\
->
Union
[
np
.
ndarray
,
Tuple
[
np
.
ndarray
,
Dict
]]:
if
y
.
ndim
==
1
:
y
=
y
.
reshape
((
-
1
,
1
))
if
weights
is
None
:
weights
=
np
.
ones
(
len
(
y
),
dtype
=
float
)
output_dict
=
{}
if
detail
:
...
...
@@ -41,17 +37,17 @@ def neutralize(x: np.ndarray,
if
detail
:
for
diff_loc
in
index_diff
:
curr_idx
=
order
[
start
:
diff_loc
+
1
]
curr_x
,
b
=
_sub_step
(
x
,
y
,
weights
,
curr_idx
,
res
)
curr_x
,
b
=
_sub_step
(
x
,
y
,
curr_idx
,
res
)
exposure
[
curr_idx
,
:,
:]
=
b
explained
[
curr_idx
]
=
ls_explain
(
curr_x
,
b
)
start
=
diff_loc
+
1
else
:
for
diff_loc
in
index_diff
:
curr_idx
=
order
[
start
:
diff_loc
+
1
]
_sub_step
(
x
,
y
,
weights
,
curr_idx
,
res
)
_sub_step
(
x
,
y
,
curr_idx
,
res
)
start
=
diff_loc
+
1
else
:
b
=
ls_fit
(
x
,
y
,
weights
)
b
=
ls_fit
(
x
,
y
)
res
=
ls_res
(
x
,
y
,
b
)
if
detail
:
...
...
@@ -65,17 +61,16 @@ def neutralize(x: np.ndarray,
@
nb
.
njit
(
nogil
=
True
,
cache
=
True
)
def
_sub_step
(
x
,
y
,
w
,
curr_idx
,
res
)
->
Tuple
[
np
.
ndarray
,
np
.
ndarray
]:
curr_x
,
curr_y
,
curr_w
=
x
[
curr_idx
],
y
[
curr_idx
],
w
[
curr_idx
]
b
=
ls_fit
(
curr_x
,
curr_y
,
curr_w
)
def
_sub_step
(
x
,
y
,
curr_idx
,
res
)
->
Tuple
[
np
.
ndarray
,
np
.
ndarray
]:
curr_x
,
curr_y
=
x
[
curr_idx
],
y
[
curr_idx
]
b
=
ls_fit
(
curr_x
,
curr_y
)
res
[
curr_idx
]
=
ls_res
(
curr_x
,
curr_y
,
b
)
return
curr_x
,
b
@
nb
.
njit
(
nogil
=
True
,
cache
=
True
)
def
ls_fit
(
x
:
np
.
ndarray
,
y
:
np
.
ndarray
,
w
:
np
.
ndarray
)
->
np
.
ndarray
:
x_bar
=
x
.
T
*
w
b
=
np
.
linalg
.
solve
(
x_bar
@
x
,
x_bar
@
y
)
def
ls_fit
(
x
:
np
.
ndarray
,
y
:
np
.
ndarray
)
->
np
.
ndarray
:
b
=
np
.
linalg
.
lstsq
(
x
,
y
,
rcond
=-
1
)[
0
]
return
b
...
...
alphamind/data/rank.py
View file @
233c92ad
...
...
@@ -24,6 +24,6 @@ def rank(x: np.ndarray, groups: Optional[np.ndarray]=None) -> np.ndarray:
curr_idx
=
order
[
start
:
diff_loc
+
1
]
res
[
curr_idx
]
=
x
[
curr_idx
]
.
argsort
(
axis
=
0
)
start
=
diff_loc
+
1
return
res
else
:
return
x
.
argsort
(
axis
=
0
)
\ No newline at end of file
return
x
.
argsort
(
axis
=
0
)
.
argsort
(
axis
=
0
)
alphamind/examples/factor_analysis_example.py
View file @
233c92ad
...
...
@@ -7,12 +7,9 @@ Created on 2017-11-8
import
numpy
as
np
import
pandas
as
pd
from
matplotlib
import
pyplot
as
plt
from
alphamind.api
import
*
from
PyFin.api
import
*
from
PyFin.Math.Accumulators.StatefulAccumulators
import
MovingAverage
from
PyFin.Math.Accumulators.StatefulAccumulators
import
MovingSharp
from
PyFin.Math.Accumulators.StatefulAccumulators
import
MovingMaxDrawdown
from
alphamind.api
import
*
from
matplotlib
import
pyplot
as
plt
plt
.
style
.
use
(
'ggplot'
)
...
...
@@ -21,126 +18,143 @@ Back test parameter settings
"""
start_date
=
'2010-01-01'
end_date
=
'2018-0
1-29
'
end_date
=
'2018-0
2-27
'
frequency
=
'10b'
method
=
'risk_neutral'
freq
=
'10b'
industry_lower
=
1.
industry_upper
=
1.
neutralize_risk
=
[
'SIZE'
]
+
industry_styles
constraint_risk
=
[
'SIZE'
]
+
industry_styles
size_risk_lower
=
0
size_risk_upper
=
0
turn_over_target_base
=
0.30
neutralized_risk
=
industry_styles
industry_name
=
'sw'
industry_level
=
1
turn_over_target_base
=
2.0
benchmark_total_lower
=
0.8
benchmark_total_upper
=
1.0
horizon
=
map_freq
(
frequency
)
batch
=
0
horizon
=
map_freq
(
freq
)
weight_gap
=
0.01
universe
=
Universe
(
"custom"
,
[
'zz800'
])
data_source
=
'postgres+psycopg2://postgres:A12345678!@10.63.6.220/alpha'
benchmark_code
=
905
offset
=
1
executor
=
NaiveExecutor
()
ref_dates
=
makeSchedule
(
start_date
,
end_date
,
freq
,
'china.sse'
)
engine
=
SqlEngine
(
data_source
)
alpha_factors
=
{
'f01'
:
LAST
(
'ep_q'
),
'f02'
:
LAST
(
'roe_q'
),
'f03'
:
LAST
(
'market_confidence_25d'
),
'f04'
:
LAST
(
'ILLIQUIDITY'
),
'f05'
:
LAST
(
'cfinc1_q'
),
'f06'
:
LAST
(
'CFO2EV'
),
'f07'
:
LAST
(
'IVR'
),
'f08'
:
LAST
(
'con_pe_rolling_order'
),
'f09'
:
LAST
(
'con_pb_rolling_order'
),
}
weights
=
dict
(
f01
=
1.
,
f02
=
1.
,
f03
=
0.25
,
f04
=
0.25
,
f05
=
0.25
,
f06
=
0.25
,
f07
=
0.25
,
f08
=-
0.25
,
f09
=-
0.25
)
alpha_model
=
ConstLinearModel
(
features
=
alpha_factors
,
weights
=
weights
)
def
train_worker
(
ref_date
):
data_meta
=
DataMeta
(
freq
=
freq
,
universe
=
universe
,
batch
=
batch
,
neutralized_risk
=
neutralized_risk
,
risk_model
=
'short'
,
pre_process
=
[
winsorize_normal
,
standardize
],
post_process
=
[
winsorize_normal
,
standardize
,
rank
],
warm_start
=
0
,
data_source
=
data_source
)
return
train_model
(
ref_date
,
alpha_model
,
data_meta
)
def
predict_worker
(
params
):
data_meta
=
DataMeta
(
freq
=
freq
,
universe
=
universe
,
batch
=
batch
,
neutralized_risk
=
neutralized_risk
,
risk_model
=
'short'
,
pre_process
=
[
winsorize_normal
,
standardize
],
post_process
=
[
winsorize_normal
,
standardize
,
rank
],
warm_start
=
0
,
data_source
=
data_source
)
ref_date
,
model
=
params
er
=
predict_by_model
(
ref_date
,
model
,
data_meta
)
return
er
predicts
=
[
predict_worker
((
d
.
strftime
(
'
%
Y-
%
m-
%
d'
),
alpha_model
))
for
d
in
ref_dates
]
# rebalance
industry_names
=
industry_list
(
industry_name
,
industry_level
)
constraint_risk
=
[
'SIZE'
,
'SIZENL'
,
'BETA'
]
+
industry_names
total_risk_names
=
constraint_risk
+
[
'benchmark'
,
'total'
]
b_type
=
[]
l_val
=
[]
u_val
=
[]
previous_pos
=
pd
.
DataFrame
()
rets
=
[]
turn_overs
=
[]
leverags
=
[]
for
name
in
total_risk_names
:
if
name
==
'benchmark'
:
b_type
.
append
(
BoundaryType
.
RELATIVE
)
l_val
.
append
(
benchmark_total_lower
)
u_val
.
append
(
benchmark_total_upper
)
elif
name
in
{
'SIZE'
,
'SIZENL'
,
'BETA'
}:
b_type
.
append
(
BoundaryType
.
ABSOLUTE
)
l_val
.
append
(
0.0
)
u_val
.
append
(
0.0
)
else
:
b_type
.
append
(
BoundaryType
.
RELATIVE
)
l_val
.
append
(
industry_lower
)
u_val
.
append
(
industry_upper
)
def
factor_analysis
(
engine
,
factor_name
,
universe
,
benchmark_code
,
positive
=
True
,
neutralize_factors
=
None
):
bounds
=
create_box_bounds
(
total_risk_names
,
b_type
,
l_val
,
u_val
)
"""
Model phase: we need 1 constant linear model and one linear regression model
"""
alpha_name
=
[
str
(
factor_name
)
+
'_'
+
(
'pos'
if
positive
else
'neg'
)
]
industry_total
=
engine
.
fetch_industry_matrix_range
(
universe
,
dates
=
ref_dates
,
category
=
industry_name
,
level
=
industry_level
)
benchmark_total
=
engine
.
fetch_benchmark_range
(
dates
=
ref_dates
,
benchmark
=
benchmark_code
)
risk_total
=
engine
.
fetch_risk_model_range
(
universe
,
dates
=
ref_dates
)[
1
]
if
neutralize_factors
:
prev_factors
=
[]
for
i
,
f
in
enumerate
(
neutralize_factors
):
pure_factor
=
LAST
(
f
)
for
j
in
range
(
i
):
pure_factor
=
CSRes
(
pure_factor
,
prev_factors
[
j
])
prev_factors
.
append
(
pure_factor
)
for
i
,
ref_date
in
enumerate
(
ref_dates
):
ref_date
=
ref_date
.
strftime
(
'
%
Y-
%
m-
%
d'
)
industry_matrix
=
industry_total
[
industry_total
.
trade_date
==
ref_date
]
benchmark_w
=
benchmark_total
[
benchmark_total
.
trade_date
==
ref_date
]
risk_matrix
=
risk_total
[
risk_total
.
trade_date
==
ref_date
]
simple_expression
=
LAST
(
factor_name
)
for
f
in
prev_factors
:
simple_expression
=
CSRes
(
simple_expression
,
f
)
else
:
simple_expression
=
LAST
(
factor_name
)
if
not
positive
:
simple_expression
=
-
simple_expression
const_features
=
{
alpha_name
[
0
]:
simple_expression
}
const_weights
=
np
.
array
([
1.
])
const_model
=
ConstLinearModel
(
features
=
alpha_name
,
weights
=
const_weights
)
ref_dates
=
makeSchedule
(
start_date
,
end_date
,
frequency
,
'china.sse'
)
const_model_factor_data
=
engine
.
fetch_data_range
(
universe
,
const_features
,
dates
=
ref_dates
,
benchmark
=
benchmark_code
)[
'factor'
]
.
dropna
()
horizon
=
map_freq
(
frequency
)
rets
=
[]
turn_overs
=
[]
leverags
=
[]
previous_pos
=
pd
.
DataFrame
()
index_dates
=
[]
factor_groups
=
const_model_factor_data
.
groupby
(
'trade_date'
)
for
i
,
value
in
enumerate
(
factor_groups
):
date
=
value
[
0
]
data
=
value
[
1
]
index_dates
.
append
(
date
)
total_data
=
data
.
fillna
(
data
[
alpha_name
]
.
median
())
alpha_logger
.
info
(
'{0}: {1}'
.
format
(
date
,
len
(
total_data
)))
risk_exp
=
total_data
[
neutralize_risk
]
.
values
.
astype
(
float
)
industry
=
total_data
.
industry_code
.
values
benchmark_w
=
total_data
.
weight
.
values
constraint_exp
=
total_data
[
constraint_risk
]
.
values
risk_exp_expand
=
np
.
concatenate
((
constraint_exp
,
np
.
ones
((
len
(
risk_exp
),
1
))),
axis
=
1
)
.
astype
(
float
)
risk_names
=
constraint_risk
+
[
'total'
]
risk_target
=
risk_exp_expand
.
T
@
benchmark_w
lbound
=
np
.
maximum
(
0.
,
benchmark_w
-
0.02
)
# np.zeros(len(total_data))
ubound
=
0.02
+
benchmark_w
is_in_benchmark
=
(
benchmark_w
>
0.
)
.
astype
(
float
)
risk_exp_expand
=
np
.
concatenate
((
risk_exp_expand
,
is_in_benchmark
.
reshape
((
-
1
,
1
))),
axis
=
1
)
.
astype
(
float
)
risk_names
.
append
(
'benchmark_total'
)
constraint
=
Constraints
(
risk_exp_expand
,
risk_names
)
for
j
,
name
in
enumerate
(
risk_names
):
if
name
==
'total'
:
constraint
.
set_constraints
(
name
,
lower_bound
=
risk_target
[
j
],
upper_bound
=
risk_target
[
j
])
elif
name
==
'SIZE'
:
base_target
=
abs
(
risk_target
[
j
])
constraint
.
set_constraints
(
name
,
lower_bound
=
risk_target
[
j
]
+
base_target
*
size_risk_lower
,
upper_bound
=
risk_target
[
j
]
+
base_target
*
size_risk_upper
)
elif
name
==
'benchmark_total'
:
base_target
=
benchmark_w
.
sum
()
constraint
.
set_constraints
(
name
,
lower_bound
=
benchmark_total_lower
*
base_target
,
upper_bound
=
benchmark_total_upper
*
base_target
)
else
:
constraint
.
set_constraints
(
name
,
lower_bound
=
risk_target
[
j
]
*
industry_lower
,
upper_bound
=
risk_target
[
j
]
*
industry_upper
)
res
=
pd
.
merge
(
industry_matrix
,
benchmark_w
,
on
=
[
'code'
],
how
=
'left'
)
.
fillna
(
0.
)
res
=
pd
.
merge
(
res
,
risk_matrix
,
on
=
[
'code'
])
res
=
res
.
dropna
()
codes
=
res
.
code
.
values
.
tolist
()
factor_values
=
factor_processing
(
total_data
[
alpha_name
]
.
values
,
pre_process
=
[
winsorize_normal
,
standardize
],
risk_factors
=
risk_exp
,
post_process
=
[
winsorize_normal
,
standardize
])
benchmark_w
=
res
.
weight
.
values
is_in_benchmark
=
(
benchmark_w
>
0.
)
.
astype
(
float
)
.
reshape
((
-
1
,
1
))
# const linear model
er
=
const_model
.
predict
(
factor_values
)
total_risk_exp
=
np
.
concatenate
([
res
[
constraint_risk
]
.
values
.
astype
(
float
),
is_in_benchmark
,
np
.
ones_like
(
is_in_benchmark
)],
axis
=
1
)
total_risk_exp
=
pd
.
DataFrame
(
total_risk_exp
,
columns
=
total_risk_names
)
constraints
=
LinearConstraints
(
bounds
,
total_risk_exp
,
benchmark_w
)
codes
=
total_data
[
'code'
]
.
values
lbound
=
np
.
maximum
(
0.
,
benchmark_w
-
weight_gap
)
# np.zeros(len(total_data))
ubound
=
weight_gap
+
benchmark_w
if
previous_pos
.
empty
:
current_position
=
None
...
...
@@ -153,116 +167,71 @@ def factor_analysis(engine, factor_name, universe, benchmark_code, positive=True
turn_over_target
=
turn_over_target_base
current_position
=
remained_pos
.
weight
.
values
er
=
predicts
[
i
]
.
loc
[
codes
]
.
values
try
:
alpha_logger
.
info
(
'{0} partial re-balance: {1}'
.
format
(
ref_date
,
len
(
er
)))
target_pos
,
_
=
er_portfolio_analysis
(
er
,
industry
,
industry_matrix
.
industry_name
.
values
,
None
,
constraint
,
constraints
,
False
,
benchmark_w
,
method
=
method
,
method
=
'risk_neutral'
,
turn_over_target
=
turn_over_target
,
current_position
=
current_position
,
lbound
=
lbound
,
ubound
=
ubound
)
except
ValueError
:
alpha_logger
.
info
(
'{0} full re-balance'
.
format
(
date
))
alpha_logger
.
info
(
'{0} full re-balance: {1}'
.
format
(
ref_date
,
len
(
er
)
))
target_pos
,
_
=
er_portfolio_analysis
(
er
,
industry
,
industry_matrix
.
industry_name
.
values
,
None
,
constraint
,
constraints
,
False
,
benchmark_w
,
method
=
method
,
method
=
'risk_neutral'
,
lbound
=
lbound
,
ubound
=
ubound
)
target_pos
[
'code'
]
=
total_data
[
'code'
]
.
values
target_pos
[
'code'
]
=
codes
turn_over
,
executed_pos
=
executor
.
execute
(
target_pos
=
target_pos
)
executed_codes
=
executed_pos
.
code
.
tolist
()
dx_returns
=
engine
.
fetch_dx_return
(
date
,
executed_codes
,
horizon
=
horizon
,
offset
=
1
)
dx_returns
=
engine
.
fetch_dx_return
(
ref_date
,
executed_codes
,
horizon
=
horizon
,
offset
=
offset
)
result
=
pd
.
merge
(
executed_pos
,
dx_returns
,
on
=
[
'code'
])
result
=
pd
.
merge
(
executed_pos
,
total_data
[[
'code'
,
'weight'
]],
on
=
[
'code'
],
how
=
'inner'
)
result
=
pd
.
merge
(
result
,
dx_returns
,
on
=
[
'code'
])
leverage
=
result
.
weight
.
abs
()
.
sum
()
leverage
=
result
.
weight_x
.
abs
()
.
sum
()
ret
=
result
.
weight_x
.
values
@
(
np
.
exp
(
result
.
dx
.
values
)
-
1.
)
ret
=
result
.
weight
.
values
@
(
np
.
exp
(
result
.
dx
.
values
)
-
1.
)
rets
.
append
(
np
.
log
(
1.
+
ret
))
executor
.
set_current
(
executed_pos
)
turn_overs
.
append
(
turn_over
)
leverags
.
append
(
leverage
)
previous_pos
=
executed_pos
alpha_logger
.
info
(
'{0} is finished'
.
format
(
date
))
ret_df
=
pd
.
DataFrame
({
'returns'
:
rets
,
'turn_over'
:
turn_overs
,
'leverage'
:
leverags
},
index
=
index_dates
)
# index return
index_return
=
engine
.
fetch_dx_return_index_range
(
benchmark_code
,
start_date
,
end_date
,
horizon
=
horizon
,
offset
=
1
)
.
set_index
(
'trade_date'
)
ret_df
[
'index'
]
=
index_return
[
'dx'
]
ret_df
.
loc
[
advanceDateByCalendar
(
'china.sse'
,
ref_dates
[
-
1
],
frequency
)]
=
0.
ret_df
=
ret_df
.
shift
(
1
)
ret_df
.
iloc
[
0
]
=
0.
ret_df
[
'tc_cost'
]
=
ret_df
.
turn_over
*
0.002
ret_df
[
'returns'
]
=
ret_df
[
'returns'
]
-
ret_df
[
'index'
]
*
ret_df
[
'leverage'
]
return
alpha_name
[
0
],
ret_df
def
worker_func_positive
(
factor_name
):
from
alphamind.api
import
SqlEngine
,
Universe
neutralize_factors
=
[
'roe_q'
,
'ep_q'
]
engine
=
SqlEngine
()
benchmark_code
=
905
universe_name
=
[
'zz500'
]
universe
=
Universe
(
'custom'
,
universe_name
)
return
factor_analysis
(
engine
,
factor_name
,
universe
,
benchmark_code
,
positive
=
True
,
neutralize_factors
=
neutralize_factors
)
def
worker_func_negative
(
factor_name
):
from
alphamind.api
import
SqlEngine
,
Universe
neutralize_factors
=
[
'roe_q'
,
'ep_q'
]
engine
=
SqlEngine
()
benchmark_code
=
905
universe_name
=
[
'zz500'
]
universe
=
Universe
(
'custom'
,
universe_name
)
return
factor_analysis
(
engine
,
factor_name
,
universe
,
benchmark_code
,
positive
=
False
,
neutralize_factors
=
neutralize_factors
)
if
__name__
==
'__main__'
:
from
dask.distributed
import
Client
client
=
Client
(
'192.168.0.102:8786'
)
engine
=
SqlEngine
()
df
=
engine
.
fetch_factor_coverage
()
df
=
df
[
df
.
universe
==
'zz800'
]
.
groupby
(
'factor'
)
.
mean
()
df
=
df
[
df
.
coverage
>=
0.98
]
alpha_logger
.
info
(
'{0} is finished'
.
format
(
ref_date
))
tasks
=
client
.
map
(
worker_func_positive
,
df
.
index
.
tolist
())
res1
=
client
.
gather
(
tasks
)
ret_df
=
pd
.
DataFrame
({
'returns'
:
rets
,
'turn_over'
:
turn_overs
,
'leverage'
:
leverags
},
index
=
ref_dates
)
tasks
=
client
.
map
(
worker_func_negative
,
df
.
index
.
tolist
())
res2
=
client
.
gather
(
tasks
)
# index return
index_return
=
engine
.
fetch_dx_return_index_range
(
benchmark_code
,
start_date
,
end_date
,
horizon
=
horizon
,
offset
=
offset
)
.
set_index
(
'trade_date'
)
ret_df
[
'index'
]
=
index_return
[
'dx'
]
factor_df
=
pd
.
DataFrame
()
ret_df
.
loc
[
advanceDateByCalendar
(
'china.sse'
,
ref_dates
[
-
1
],
freq
)]
=
0.
ret_df
=
ret_df
.
shift
(
1
)
ret_df
.
iloc
[
0
]
=
0.
ret_df
[
'tc_cost'
]
=
ret_df
.
turn_over
*
0.002
ret_df
[
'returns'
]
=
ret_df
[
'returns'
]
-
ret_df
[
'index'
]
*
ret_df
[
'leverage'
]
for
f_name
,
df
in
res1
:
factor_df
[
f_name
]
=
df
[
'returns'
]
ret_df
[[
'returns'
,
'tc_cost'
]]
.
cumsum
()
.
plot
(
figsize
=
(
12
,
6
),
title
=
'Fixed freq rebalanced: {0} with benchmark {1}'
.
format
(
freq
,
905
),
secondary_y
=
'tc_cost'
)
for
f_name
,
df
in
res2
:
factor_df
[
f_name
]
=
df
[
'returns'
]
ret_df
[[
'returns'
,
'tc_cost'
]][
-
30
:]
.
cumsum
()
.
plot
(
figsize
=
(
12
,
6
),
title
=
'Fixed freq rebalanced: {0} with benchmark {1}'
.
format
(
freq
,
905
),
secondary_y
=
'tc_cost'
)
# factor_name = LAST('EBITDA') / LAST('ev')
# f_name, ret_df = worker_func_positive(factor_name)
#
# ret_df[['returns', 'tc_cost']].cumsum().plot(figsize=(12, 6),
# title='Fixed frequency rebalanced: {0} for {1} with benchmark {2}'.format(
# frequency, factor_name, 905),
# secondary_y='tc_cost')
# plt.show()
plt
.
show
()
alphamind/examples/factor_res_analysis.py
View file @
233c92ad
...
...
@@ -94,7 +94,7 @@ def factor_analysis(f_name):
if
__name__
==
'__main__'
:
from
dask.distributed
import
Client
client
=
Client
(
'10.63.6.1
76
:8786'
)
client
=
Client
(
'10.63.6.1
3
:8786'
)
engine
=
SqlEngine
()
df
=
engine
.
fetch_factor_coverage
()
...
...
alphamind/model/composer.py
View file @
233c92ad
...
...
@@ -16,12 +16,14 @@ from alphamind.model.data_preparing import fetch_predict_phase
from
alphamind.data.engines.universe
import
Universe
from
alphamind.data.engines.sqlengine
import
SqlEngine
from
alphamind.data.winsorize
import
winsorize_normal
from
alphamind.data.rank
import
rank
from
alphamind.data.standardize
import
standardize
from
alphamind.model.loader
import
load_model
PROCESS_MAPPING
=
{
'winsorize_normal'
:
winsorize_normal
,
'standardize'
:
standardize
'standardize'
:
standardize
,
'rank'
:
rank
,
}
...
...
alphamind/portfolio/constraints.py
View file @
233c92ad
...
...
@@ -105,21 +105,28 @@ class LinearConstraints(object):
def
__init__
(
self
,
bounds
:
Dict
[
str
,
BoxBoundary
],
cons_mat
:
pd
.
DataFrame
,
backbone
:
np
.
ndarray
):
backbone
:
np
.
ndarray
=
None
):
pyFinAssert
(
len
(
bounds
)
==
cons_mat
.
shape
[
1
],
"Number of bounds should be same as number of col of cons_mat"
)
pyFinAssert
(
cons_mat
.
shape
[
0
]
==
len
(
backbone
),
"length of back bond should be same as number of rows of cons_mat"
)
self
.
names
=
list
(
bounds
.
keys
())
self
.
bounds
=
bounds
self
.
cons_mat
=
cons_mat
self
.
backbone
=
backbone
pyFinAssert
(
cons_mat
.
shape
[
0
]
==
len
(
backbone
)
if
backbone
is
not
None
else
True
,
"length of back bond should be same as number of rows of cons_mat"
)
def
risk_targets
(
self
)
->
Tuple
[
np
.
ndarray
,
np
.
ndarray
]:
lower_bounds
=
[]
upper_bounds
=
[]
if
self
.
backbone
is
None
:
backbone
=
np
.
zeros
(
len
(
self
.
cons_mat
))
else
:
backbone
=
self
.
backbone
for
name
in
self
.
names
:
center
=
self
.
backbone
@
self
.
cons_mat
[
name
]
.
values
center
=
backbone
@
self
.
cons_mat
[
name
]
.
values
l
,
u
=
self
.
bounds
[
name
]
.
bounds
(
center
)
lower_bounds
.
append
(
l
)
upper_bounds
.
append
(
u
)
...
...
alphamind/tests/data/test_rank.py
View file @
233c92ad
...
...
@@ -6,9 +6,33 @@ Created on 2017-8-8
"""
import
unittest
import
numpy
as
np
import
pandas
as
pd
from
alphamind.data.rank
import
rank
class
TestRank
(
unittest
.
TestCase
):
def
setUp
(
self
):
self
.
x
=
np
.
random
.
randn
(
1000
,
1
)
self
.
groups
=
np
.
random
.
randint
(
0
,
10
,
1000
)
def
test_rank
(
self
):
pass
\ No newline at end of file
data_rank
=
rank
(
self
.
x
)
sorted_array
=
np
.
zeros_like
(
self
.
x
)
for
i
in
range
(
self
.
x
.
shape
[
0
]):
for
j
in
range
(
self
.
x
.
shape
[
1
]):
sorted_array
[
data_rank
[
i
,
j
],
j
]
=
self
.
x
[
i
,
j
]
arr_diff
=
np
.
diff
(
sorted_array
,
axis
=
0
)
np
.
testing
.
assert_array_less
(
0
,
arr_diff
)
def
test_rank_with_groups
(
self
):
data_rank
=
rank
(
self
.
x
,
groups
=
self
.
groups
)
df
=
pd
.
DataFrame
(
self
.
x
,
index
=
self
.
groups
)
expected_rank
=
df
.
groupby
(
level
=
0
)
.
apply
(
lambda
x
:
x
.
values
.
argsort
(
axis
=
0
)
.
argsort
(
axis
=
0
))
print
(
expected_rank
)
notebooks/Example 1 - Factor IC analysis.ipynb
View file @
233c92ad
...
...
@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
"execution_count":
1
,
"execution_count":
null
,
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -19,7 +19,7 @@
},
{
"cell_type": "code",
"execution_count":
2
,
"execution_count":
null
,
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -34,7 +34,7 @@
"industry_lower = 1.0\n",
"industry_upper = 1.0\n",
"method = 'risk_neutral'\n",
"neutralize_risk =
['SIZE'] +
industry_styles\n",
"neutralize_risk = industry_styles\n",
"industry_name = 'sw_adj'\n",
"industry_level = 1\n",
"benchmark_total_lower = 0.8\n",
...
...
@@ -53,7 +53,7 @@
},
{
"cell_type": "code",
"execution_count":
3
,
"execution_count":
null
,
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -62,7 +62,7 @@
"\"\"\"\n",
"\n",
"industry_names = industry_list(industry_name, industry_level)\n",
"constraint_risk = ['SIZE', 'SIZENL', 'BETA']\n",
"constraint_risk = ['SIZE', 'SIZENL', 'BETA']
+ industry_names
\n",
"total_risk_names = constraint_risk + ['benchmark', 'total']\n",
"\n",
"b_type = []\n",
...
...
@@ -88,7 +88,7 @@
},
{
"cell_type": "code",
"execution_count":
4
,
"execution_count":
null
,
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -160,7 +160,7 @@
" factor_values = factor_processing(total_data[alpha_name].values,\n",
" pre_process=[winsorize_normal, standardize],\n",
" risk_factors=risk_exp,\n",
" post_process=[winsorize_normal, standardize
, rank
])\n",
" post_process=[winsorize_normal, standardize])\n",
"\n",
" # const linear model\n",
" er = const_model.predict(pd.DataFrame(data={alpha_name[0]: factor_values.flatten()}))\n",
...
...
@@ -222,10 +222,12 @@
},
{
"cell_type": "code",
"execution_count":
5
,
"execution_count":
null
,
"metadata": {},
"outputs": [],
"source": [
"%%time\n",
"\n",
"df = engine.fetch_factor_coverage(start_date='2011-01-01',\n",
" end_date='2018-02-12',\n",
" universe=universe_name[0])\n",
...
...
@@ -236,17 +238,9 @@
},
{
"cell_type": "code",
"execution_count":
6
,
"execution_count":
null
,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Wall time: 1h 25min 5s\n"
]
}
],
"outputs": [],
"source": [
"%%time\n",
"\n",
...
...
@@ -274,7 +268,7 @@
},
{
"cell_type": "code",
"execution_count":
7
,
"execution_count":
null
,
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -287,26 +281,33 @@
},
{
"cell_type": "code",
"execution_count":
8
,
"execution_count":
null
,
"metadata": {},
"outputs": [],
"source": [
"with pd.ExcelWriter(f'{universe_name[0]}_{benchmark_code}.xlsx', engine='xlsxwriter') as writer:\n",
" factor_df.to_excel(writer, sheet_name='ret')\n",
"
factor_res
.to_excel(writer, sheet_name='ic')\n",
" factor_
df
.to_excel(writer, sheet_name='ret_stat')\n",
"
ic_df
.to_excel(writer, sheet_name='ic')\n",
" factor_
res
.to_excel(writer, sheet_name='ret_stat')\n",
" ic_res.to_excel(writer, sheet_name='ic_stat')"
]
},
{
"cell_type": "code",
"execution_count":
9
,
"execution_count":
null
,
"metadata": {},
"outputs": [],
"source": [
"client.close()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
...
...
@@ -332,6 +333,35 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.4"
},
"varInspector": {
"cols": {
"lenName": 16,
"lenType": 16,
"lenVar": 40
},
"kernels_config": {
"python": {
"delete_cmd_postfix": "",
"delete_cmd_prefix": "del ",
"library": "var_list.py",
"varRefreshCmd": "print(var_dic_list())"
},
"r": {
"delete_cmd_postfix": ") ",
"delete_cmd_prefix": "rm(",
"library": "var_list.r",
"varRefreshCmd": "cat(var_dic_list()) "
}
},
"types_to_exclude": [
"module",
"function",
"builtin_function_or_method",
"instance",
"_Feature"
],
"window_display": false
}
},
"nbformat": 4,
...
...
notebooks/Example 2 - Strategy Analysis.ipynb
View file @
233c92ad
...
...
@@ -41,6 +41,7 @@
"universe = Universe(\"custom\", ['zz800'])\n",
"data_source = 'postgres+psycopg2://postgres:A12345678!@10.63.6.220/alpha'\n",
"benchmark_code = 905\n",
"offset = 0\n",
"\n",
"executor = NaiveExecutor()\n",
"ref_dates = makeSchedule(start_date, end_date, freq, 'china.sse')\n",
...
...
@@ -112,12 +113,12 @@
"metadata": {},
"outputs": [],
"source": [
"
#
%%time\n",
"%%time\n",
"\n",
"# training / predict on dask executor\n",
"\n",
"from dask.distributed import Client\n",
"client = Client('10.63.6.1
3
:8786')\n",
"client = Client('10.63.6.1
76
:8786')\n",
"\n",
"tasks = client.map(predict_worker, [(d.strftime('%Y-%m-%d'), alpha_model) for d in ref_dates], pure=False)\n",
"predicts = client.gather(tasks)"
...
...
@@ -230,7 +231,7 @@
" turn_over, executed_pos = executor.execute(target_pos=target_pos)\n",
"\n",
" executed_codes = executed_pos.code.tolist()\n",
" dx_returns = engine.fetch_dx_return(ref_date, executed_codes, horizon=horizon, offset=
1
)\n",
" dx_returns = engine.fetch_dx_return(ref_date, executed_codes, horizon=horizon, offset=
offset
)\n",
" result = pd.merge(executed_pos, dx_returns, on=['code'])\n",
"\n",
" leverage = result.weight.abs().sum()\n",
...
...
@@ -247,36 +248,15 @@
},
{
"cell_type": "code",
"execution_count": 75,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.axes._subplots.AxesSubplot at 0x1b2d29094a8>"
]
},
"execution_count": 75,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x1b2d1759ac8>"
]
},
"execution_count": null,
"metadata": {},
"output_type": "display_data"
}
],
"outputs": [],
"source": [
"ret_df = pd.DataFrame({'returns': rets, 'turn_over': turn_overs, 'leverage': leverags}, index=ref_dates)\n",
"\n",
"# index return\n",
"index_return = engine.fetch_dx_return_index_range(benchmark_code, start_date, end_date, horizon=horizon,\n",
" offset=
1
).set_index('trade_date')\n",
" offset=
offset
).set_index('trade_date')\n",
"ret_df['index'] = index_return['dx']\n",
"\n",
"ret_df.loc[advanceDateByCalendar('china.sse', ref_dates[-1], freq)] = 0.\n",
...
...
@@ -295,7 +275,11 @@
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
"source": [
"ret_df[['returns', 'tc_cost']][-30:].cumsum().plot(figsize=(12, 6),\n",
" title='Fixed freq rebalanced: {0} with benchmark {1}'.format(freq, 905),\n",
" secondary_y='tc_cost')"
]
},
{
"cell_type": "code",
...
...
@@ -322,6 +306,35 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.4"
},
"varInspector": {
"cols": {
"lenName": 16,
"lenType": 16,
"lenVar": 40
},
"kernels_config": {
"python": {
"delete_cmd_postfix": "",
"delete_cmd_prefix": "del ",
"library": "var_list.py",
"varRefreshCmd": "print(var_dic_list())"
},
"r": {
"delete_cmd_postfix": ") ",
"delete_cmd_prefix": "rm(",
"library": "var_list.r",
"varRefreshCmd": "cat(var_dic_list()) "
}
},
"types_to_exclude": [
"module",
"function",
"builtin_function_or_method",
"instance",
"_Feature"
],
"window_display": false
}
},
"nbformat": 4,
...
...
notebooks/Example 3 - Multi Weight Gap Comparison.ipynb
View file @
233c92ad
...
...
@@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
"execution_count":
1
,
"execution_count":
null
,
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -21,7 +21,7 @@
},
{
"cell_type": "code",
"execution_count":
12
,
"execution_count":
null
,
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -54,7 +54,7 @@
},
{
"cell_type": "code",
"execution_count":
13
,
"execution_count":
null
,
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -62,27 +62,50 @@
"Factor Model\n",
"\"\"\"\n",
"\n",
"# alpha_factors = {\n",
"# 'f01': LAST('ep_q'),\n",
"# 'f02': LAST('roe_q'),\n",
"# 'f03': LAST('market_confidence_25d'),\n",
"# 'f04': LAST('ILLIQUIDITY'),\n",
"# 'f05': LAST('cfinc1_q'),\n",
"# 'f06': LAST('CFO2EV'),\n",
"# 'f07': LAST('IVR'),\n",
"# 'f08': LAST('con_pe_rolling_order'),\n",
"# 'f09': LAST('con_pb_rolling_order')\n",
"# }\n",
"\n",
"\n",
"# weights = dict(f01=1.,\n",
"# f02=0.5,\n",
"# f03=0.5,\n",
"# f04=0.5,\n",
"# f05=0.5,\n",
"# f06=0.5,\n",
"# f07=0.5,\n",
"# f08=-0.5,\n",
"# f09=-0.5)\n",
"\n",
"alpha_factors = {\n",
" 'f01': LAST('ep_q'),\n",
" 'f02': LAST('roe_q'),\n",
" 'f03': LAST('market_confidence_
2
5d'),\n",
" 'f03': LAST('market_confidence_
7
5d'),\n",
" 'f04': LAST('DivP'),\n",
" 'f05': LAST('
BP
'),\n",
" 'f06': LAST('
val_q
'),\n",
" 'f07': LAST('
VOL60
'),\n",
" 'f05': LAST('
val_q
'),\n",
" 'f06': LAST('
con_np_rolling
'),\n",
" 'f07': LAST('
GREV
'),\n",
" 'f08': LAST('con_pe_rolling_order'),\n",
" 'f09': LAST('con_pb_rolling_order')\n",
"}\n",
"\n",
"weights = dict(f01=1.,\n",
" f02=
1.
,\n",
" f03=0.
2
5,\n",
" f04=0.
2
5,\n",
" f05=0.
2
5,\n",
" f06=0.
2
5,\n",
" f07=
-0.2
5,\n",
" f08=-0.
2
5,\n",
" f09=-0.
2
5)\n",
" f02=
0.5
,\n",
" f03=0.5,\n",
" f04=0.5,\n",
" f05=0.5,\n",
" f06=0.5,\n",
" f07=
0.
5,\n",
" f08=-0.5,\n",
" f09=-0.5)\n",
"\n",
"alpha_model = ConstLinearModel(features=alpha_factors, weights=weights)\n",
"\n",
...
...
@@ -103,17 +126,9 @@
},
{
"cell_type": "code",
"execution_count":
14
,
"execution_count":
null
,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Wall time: 0 ns\n"
]
}
],
"outputs": [],
"source": [
"%%time\n",
"\n",
...
...
@@ -126,17 +141,9 @@
},
{
"cell_type": "code",
"execution_count":
15
,
"execution_count":
null
,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Wall time: 8.42 s\n"
]
}
],
"outputs": [],
"source": [
"%%time\n",
"\n",
...
...
@@ -145,15 +152,16 @@
"\"\"\"\n",
"\n",
"from dask.distributed import Client\n",
"client = Client('10.63.6.1
3
:8786')\n",
"client = Client('10.63.6.1
76
:8786')\n",
"\n",
"tasks = client.map(predict_worker, [(d.strftime('%Y-%m-%d'), alpha_model) for d in ref_dates], pure=False)\n",
"predicts = client.gather(tasks)"
"predicts = client.gather(tasks)\n",
"client.close()"
]
},
{
"cell_type": "code",
"execution_count":
16
,
"execution_count":
null
,
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -174,7 +182,7 @@
" b_type.append(BoundaryType.RELATIVE)\n",
" l_val.append(benchmark_total_lower)\n",
" u_val.append(benchmark_total_upper)\n",
" elif name in {'SIZE', 'SIZENL', 'BETA'}:\n",
" elif name in {'SIZE', 'SIZENL', 'BETA'
, 'total'
}:\n",
" b_type.append(BoundaryType.ABSOLUTE)\n",
" l_val.append(0.0)\n",
" u_val.append(0.0)\n",
...
...
@@ -192,7 +200,7 @@
},
{
"cell_type": "code",
"execution_count":
17
,
"execution_count":
null
,
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -298,7 +306,7 @@
},
{
"cell_type": "code",
"execution_count":
18
,
"execution_count":
null
,
"metadata": {},
"outputs": [],
"source": [
...
...
@@ -332,26 +340,9 @@
},
{
"cell_type": "code",
"execution_count":
19
,
"execution_count":
null
,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"d:\\ProgramData\\Anaconda3\\lib\\site-packages\\ipykernel_launcher.py:39: FutureWarning: \n",
"Passing list-likes to .loc or [] with any missing label will raise\n",
"KeyError in the future, you can use .reindex() as an alternative.\n",
"\n",
"See the documentation here:\n",
"http://pandas.pydata.org/pandas-docs/stable/indexing.html#deprecate-loc-reindex-listlike\n",
"2018-02-27 15:42:15,597 - ALPHA_MIND - INFO - 0.005 finished\n",
"2018-02-27 15:43:09,157 - ALPHA_MIND - INFO - 0.01 finished\n",
"2018-02-27 15:44:02,819 - ALPHA_MIND - INFO - 0.015 finished\n",
"2018-02-27 15:44:56,827 - ALPHA_MIND - INFO - 0.02 finished\n"
]
}
],
"outputs": [],
"source": [
"weight_gaps = [0.005, 0.010, 0.015, 0.020]\n",
"\n",
...
...
@@ -363,1356 +354,6 @@
" alpha_logger.info(f\"{weight_gap} finished\")"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>daily_return</th>\n",
" <th>cum_ret</th>\n",
" <th>sharp</th>\n",
" <th>drawdown</th>\n",
" <th>max_drawn</th>\n",
" <th>leverage</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>2010-01-04</th>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.00000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-01-18</th>\n",
" <td>0.002456</td>\n",
" <td>0.002456</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.98210</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-02-01</th>\n",
" <td>-0.003691</td>\n",
" <td>-0.001234</td>\n",
" <td>0.000000</td>\n",
" <td>-0.003691</td>\n",
" <td>-0.003691</td>\n",
" <td>0.98080</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-02-22</th>\n",
" <td>-0.001398</td>\n",
" <td>-0.002632</td>\n",
" <td>0.000000</td>\n",
" <td>-0.005088</td>\n",
" <td>-0.005088</td>\n",
" <td>0.99880</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-03-08</th>\n",
" <td>0.001219</td>\n",
" <td>-0.001413</td>\n",
" <td>0.000000</td>\n",
" <td>-0.005088</td>\n",
" <td>-0.005088</td>\n",
" <td>1.00070</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-03-22</th>\n",
" <td>-0.003154</td>\n",
" <td>-0.004567</td>\n",
" <td>-1.564942</td>\n",
" <td>-0.007023</td>\n",
" <td>-0.007023</td>\n",
" <td>0.99990</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-04-06</th>\n",
" <td>0.005331</td>\n",
" <td>0.000764</td>\n",
" <td>0.170609</td>\n",
" <td>-0.007023</td>\n",
" <td>-0.007023</td>\n",
" <td>1.00030</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-04-20</th>\n",
" <td>-0.011791</td>\n",
" <td>-0.011027</td>\n",
" <td>-1.339591</td>\n",
" <td>-0.013484</td>\n",
" <td>-0.013484</td>\n",
" <td>1.00090</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-05-05</th>\n",
" <td>0.000307</td>\n",
" <td>-0.010720</td>\n",
" <td>-1.229194</td>\n",
" <td>-0.013484</td>\n",
" <td>-0.013484</td>\n",
" <td>0.99920</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-05-19</th>\n",
" <td>0.007962</td>\n",
" <td>-0.002758</td>\n",
" <td>-0.255024</td>\n",
" <td>-0.013484</td>\n",
" <td>-0.013484</td>\n",
" <td>0.99890</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-06-02</th>\n",
" <td>-0.007907</td>\n",
" <td>-0.010665</td>\n",
" <td>-0.862161</td>\n",
" <td>-0.013484</td>\n",
" <td>-0.013484</td>\n",
" <td>0.99980</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-06-21</th>\n",
" <td>0.007624</td>\n",
" <td>-0.003041</td>\n",
" <td>-0.214491</td>\n",
" <td>-0.013484</td>\n",
" <td>-0.013484</td>\n",
" <td>0.99990</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-07-05</th>\n",
" <td>0.008193</td>\n",
" <td>0.005152</td>\n",
" <td>0.323698</td>\n",
" <td>-0.013484</td>\n",
" <td>-0.013484</td>\n",
" <td>0.99960</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-07-19</th>\n",
" <td>0.001580</td>\n",
" <td>0.006732</td>\n",
" <td>0.408208</td>\n",
" <td>-0.013484</td>\n",
" <td>-0.013484</td>\n",
" <td>0.97430</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-08-02</th>\n",
" <td>0.005666</td>\n",
" <td>0.012399</td>\n",
" <td>0.708708</td>\n",
" <td>-0.013484</td>\n",
" <td>-0.013484</td>\n",
" <td>0.97470</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-08-16</th>\n",
" <td>-0.013279</td>\n",
" <td>-0.000880</td>\n",
" <td>-0.041376</td>\n",
" <td>-0.013484</td>\n",
" <td>-0.013484</td>\n",
" <td>1.00010</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-08-30</th>\n",
" <td>-0.002519</td>\n",
" <td>-0.003399</td>\n",
" <td>-0.154688</td>\n",
" <td>-0.015798</td>\n",
" <td>-0.015798</td>\n",
" <td>0.99900</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-09-13</th>\n",
" <td>-0.012298</td>\n",
" <td>-0.015698</td>\n",
" <td>-0.633037</td>\n",
" <td>-0.028096</td>\n",
" <td>-0.028096</td>\n",
" <td>0.99960</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-09-30</th>\n",
" <td>0.003504</td>\n",
" <td>-0.012194</td>\n",
" <td>-0.474059</td>\n",
" <td>-0.028096</td>\n",
" <td>-0.028096</td>\n",
" <td>0.99970</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-10-21</th>\n",
" <td>0.032270</td>\n",
" <td>0.020077</td>\n",
" <td>0.508137</td>\n",
" <td>-0.028096</td>\n",
" <td>-0.028096</td>\n",
" <td>0.99950</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-11-04</th>\n",
" <td>-0.001903</td>\n",
" <td>0.018173</td>\n",
" <td>0.448466</td>\n",
" <td>-0.028096</td>\n",
" <td>-0.028096</td>\n",
" <td>0.99990</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-11-18</th>\n",
" <td>0.004564</td>\n",
" <td>0.022737</td>\n",
" <td>0.546899</td>\n",
" <td>-0.028096</td>\n",
" <td>-0.028096</td>\n",
" <td>0.99980</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-12-02</th>\n",
" <td>0.005751</td>\n",
" <td>0.028489</td>\n",
" <td>0.667092</td>\n",
" <td>-0.028096</td>\n",
" <td>-0.028096</td>\n",
" <td>0.99970</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-12-16</th>\n",
" <td>-0.001650</td>\n",
" <td>0.026839</td>\n",
" <td>0.614522</td>\n",
" <td>-0.028096</td>\n",
" <td>-0.028096</td>\n",
" <td>0.99950</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-12-30</th>\n",
" <td>0.007329</td>\n",
" <td>0.034168</td>\n",
" <td>0.759830</td>\n",
" <td>-0.028096</td>\n",
" <td>-0.028096</td>\n",
" <td>0.99960</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2011-01-14</th>\n",
" <td>0.013885</td>\n",
" <td>0.048052</td>\n",
" <td>1.030272</td>\n",
" <td>-0.028096</td>\n",
" <td>-0.028096</td>\n",
" <td>0.99960</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2011-01-28</th>\n",
" <td>0.010359</td>\n",
" <td>0.058411</td>\n",
" <td>1.180538</td>\n",
" <td>-0.028096</td>\n",
" <td>-0.028096</td>\n",
" <td>0.95740</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2011-02-18</th>\n",
" <td>0.001031</td>\n",
" <td>0.059442</td>\n",
" <td>1.290546</td>\n",
" <td>-0.028096</td>\n",
" <td>-0.028096</td>\n",
" <td>0.95720</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2011-03-04</th>\n",
" <td>0.001280</td>\n",
" <td>0.060722</td>\n",
" <td>1.351831</td>\n",
" <td>-0.028096</td>\n",
" <td>-0.028096</td>\n",
" <td>0.99890</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2011-03-18</th>\n",
" <td>0.018729</td>\n",
" <td>0.079451</td>\n",
" <td>1.632026</td>\n",
" <td>-0.028096</td>\n",
" <td>-0.028096</td>\n",
" <td>0.99900</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2016-12-19</th>\n",
" <td>0.001795</td>\n",
" <td>0.619046</td>\n",
" <td>1.928640</td>\n",
" <td>-0.013104</td>\n",
" <td>-0.035754</td>\n",
" <td>0.99999</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-01-03</th>\n",
" <td>0.006513</td>\n",
" <td>0.625559</td>\n",
" <td>1.833167</td>\n",
" <td>-0.013104</td>\n",
" <td>-0.035754</td>\n",
" <td>0.99999</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-01-17</th>\n",
" <td>0.006098</td>\n",
" <td>0.631657</td>\n",
" <td>1.732021</td>\n",
" <td>-0.013104</td>\n",
" <td>-0.035754</td>\n",
" <td>1.00003</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-02-07</th>\n",
" <td>0.003424</td>\n",
" <td>0.635081</td>\n",
" <td>2.190087</td>\n",
" <td>-0.013104</td>\n",
" <td>-0.035754</td>\n",
" <td>1.00003</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-02-21</th>\n",
" <td>0.010451</td>\n",
" <td>0.645533</td>\n",
" <td>2.439619</td>\n",
" <td>-0.013104</td>\n",
" <td>-0.035754</td>\n",
" <td>0.99996</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-03-07</th>\n",
" <td>-0.001086</td>\n",
" <td>0.644447</td>\n",
" <td>2.149152</td>\n",
" <td>-0.013104</td>\n",
" <td>-0.035754</td>\n",
" <td>0.99798</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-03-21</th>\n",
" <td>0.016426</td>\n",
" <td>0.660873</td>\n",
" <td>2.235613</td>\n",
" <td>-0.013104</td>\n",
" <td>-0.035754</td>\n",
" <td>1.00003</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-04-06</th>\n",
" <td>-0.001144</td>\n",
" <td>0.659729</td>\n",
" <td>2.356093</td>\n",
" <td>-0.013104</td>\n",
" <td>-0.035754</td>\n",
" <td>1.00003</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-04-20</th>\n",
" <td>0.007881</td>\n",
" <td>0.667610</td>\n",
" <td>2.448745</td>\n",
" <td>-0.013104</td>\n",
" <td>-0.035754</td>\n",
" <td>1.00004</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-05-05</th>\n",
" <td>-0.008892</td>\n",
" <td>0.658717</td>\n",
" <td>2.227092</td>\n",
" <td>-0.013104</td>\n",
" <td>-0.035754</td>\n",
" <td>1.00004</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-05-19</th>\n",
" <td>-0.002924</td>\n",
" <td>0.655793</td>\n",
" <td>2.487909</td>\n",
" <td>-0.012972</td>\n",
" <td>-0.035754</td>\n",
" <td>0.99990</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-06-06</th>\n",
" <td>0.003434</td>\n",
" <td>0.659228</td>\n",
" <td>2.593745</td>\n",
" <td>-0.012802</td>\n",
" <td>-0.035754</td>\n",
" <td>0.99990</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-06-20</th>\n",
" <td>0.011297</td>\n",
" <td>0.670525</td>\n",
" <td>2.860042</td>\n",
" <td>-0.011817</td>\n",
" <td>-0.035754</td>\n",
" <td>1.00004</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-07-04</th>\n",
" <td>0.009526</td>\n",
" <td>0.680050</td>\n",
" <td>3.041796</td>\n",
" <td>-0.011817</td>\n",
" <td>-0.035754</td>\n",
" <td>1.00004</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-07-18</th>\n",
" <td>0.016175</td>\n",
" <td>0.696225</td>\n",
" <td>3.055025</td>\n",
" <td>-0.011817</td>\n",
" <td>-0.035754</td>\n",
" <td>0.99999</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-08-01</th>\n",
" <td>0.002968</td>\n",
" <td>0.699193</td>\n",
" <td>2.857844</td>\n",
" <td>-0.011817</td>\n",
" <td>-0.035754</td>\n",
" <td>0.99999</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-08-15</th>\n",
" <td>-0.007531</td>\n",
" <td>0.691662</td>\n",
" <td>2.289452</td>\n",
" <td>-0.011817</td>\n",
" <td>-0.035754</td>\n",
" <td>1.00004</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-08-29</th>\n",
" <td>0.001026</td>\n",
" <td>0.692688</td>\n",
" <td>2.742168</td>\n",
" <td>-0.011817</td>\n",
" <td>-0.035754</td>\n",
" <td>1.00004</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-09-12</th>\n",
" <td>0.000855</td>\n",
" <td>0.693543</td>\n",
" <td>2.830931</td>\n",
" <td>-0.011817</td>\n",
" <td>-0.035754</td>\n",
" <td>1.00004</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-09-26</th>\n",
" <td>-0.000392</td>\n",
" <td>0.693151</td>\n",
" <td>2.633798</td>\n",
" <td>-0.011817</td>\n",
" <td>-0.035754</td>\n",
" <td>0.99997</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-10-17</th>\n",
" <td>-0.006175</td>\n",
" <td>0.686976</td>\n",
" <td>2.390601</td>\n",
" <td>-0.012217</td>\n",
" <td>-0.035754</td>\n",
" <td>0.99997</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-10-31</th>\n",
" <td>-0.004647</td>\n",
" <td>0.682329</td>\n",
" <td>2.037490</td>\n",
" <td>-0.016864</td>\n",
" <td>-0.035754</td>\n",
" <td>1.00002</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-11-14</th>\n",
" <td>0.005732</td>\n",
" <td>0.688061</td>\n",
" <td>2.259706</td>\n",
" <td>-0.016864</td>\n",
" <td>-0.035754</td>\n",
" <td>1.00011</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-11-28</th>\n",
" <td>0.014009</td>\n",
" <td>0.702070</td>\n",
" <td>2.700705</td>\n",
" <td>-0.016864</td>\n",
" <td>-0.035754</td>\n",
" <td>1.00011</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-12-12</th>\n",
" <td>0.000715</td>\n",
" <td>0.702786</td>\n",
" <td>2.437891</td>\n",
" <td>-0.016864</td>\n",
" <td>-0.035754</td>\n",
" <td>0.99994</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-12-26</th>\n",
" <td>0.003241</td>\n",
" <td>0.706027</td>\n",
" <td>2.481936</td>\n",
" <td>-0.016864</td>\n",
" <td>-0.035754</td>\n",
" <td>0.99996</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2018-01-10</th>\n",
" <td>0.009375</td>\n",
" <td>0.715401</td>\n",
" <td>2.536598</td>\n",
" <td>-0.016864</td>\n",
" <td>-0.035754</td>\n",
" <td>1.00008</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2018-01-24</th>\n",
" <td>0.001758</td>\n",
" <td>0.717159</td>\n",
" <td>2.417740</td>\n",
" <td>-0.016864</td>\n",
" <td>-0.035754</td>\n",
" <td>0.99998</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2018-02-07</th>\n",
" <td>0.003852</td>\n",
" <td>0.721011</td>\n",
" <td>2.429653</td>\n",
" <td>-0.016864</td>\n",
" <td>-0.035754</td>\n",
" <td>0.99993</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2018-02-28</th>\n",
" <td>0.000391</td>\n",
" <td>0.721402</td>\n",
" <td>2.185579</td>\n",
" <td>-0.016864</td>\n",
" <td>-0.035754</td>\n",
" <td>0.99994</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>199 rows × 6 columns</p>\n",
"</div>"
],
"text/plain": [
" daily_return cum_ret sharp drawdown max_drawn leverage\n",
"2010-01-04 0.000000 0.000000 0.000000 0.000000 0.000000 0.00000\n",
"2010-01-18 0.002456 0.002456 0.000000 0.000000 0.000000 0.98210\n",
"2010-02-01 -0.003691 -0.001234 0.000000 -0.003691 -0.003691 0.98080\n",
"2010-02-22 -0.001398 -0.002632 0.000000 -0.005088 -0.005088 0.99880\n",
"2010-03-08 0.001219 -0.001413 0.000000 -0.005088 -0.005088 1.00070\n",
"2010-03-22 -0.003154 -0.004567 -1.564942 -0.007023 -0.007023 0.99990\n",
"2010-04-06 0.005331 0.000764 0.170609 -0.007023 -0.007023 1.00030\n",
"2010-04-20 -0.011791 -0.011027 -1.339591 -0.013484 -0.013484 1.00090\n",
"2010-05-05 0.000307 -0.010720 -1.229194 -0.013484 -0.013484 0.99920\n",
"2010-05-19 0.007962 -0.002758 -0.255024 -0.013484 -0.013484 0.99890\n",
"2010-06-02 -0.007907 -0.010665 -0.862161 -0.013484 -0.013484 0.99980\n",
"2010-06-21 0.007624 -0.003041 -0.214491 -0.013484 -0.013484 0.99990\n",
"2010-07-05 0.008193 0.005152 0.323698 -0.013484 -0.013484 0.99960\n",
"2010-07-19 0.001580 0.006732 0.408208 -0.013484 -0.013484 0.97430\n",
"2010-08-02 0.005666 0.012399 0.708708 -0.013484 -0.013484 0.97470\n",
"2010-08-16 -0.013279 -0.000880 -0.041376 -0.013484 -0.013484 1.00010\n",
"2010-08-30 -0.002519 -0.003399 -0.154688 -0.015798 -0.015798 0.99900\n",
"2010-09-13 -0.012298 -0.015698 -0.633037 -0.028096 -0.028096 0.99960\n",
"2010-09-30 0.003504 -0.012194 -0.474059 -0.028096 -0.028096 0.99970\n",
"2010-10-21 0.032270 0.020077 0.508137 -0.028096 -0.028096 0.99950\n",
"2010-11-04 -0.001903 0.018173 0.448466 -0.028096 -0.028096 0.99990\n",
"2010-11-18 0.004564 0.022737 0.546899 -0.028096 -0.028096 0.99980\n",
"2010-12-02 0.005751 0.028489 0.667092 -0.028096 -0.028096 0.99970\n",
"2010-12-16 -0.001650 0.026839 0.614522 -0.028096 -0.028096 0.99950\n",
"2010-12-30 0.007329 0.034168 0.759830 -0.028096 -0.028096 0.99960\n",
"2011-01-14 0.013885 0.048052 1.030272 -0.028096 -0.028096 0.99960\n",
"2011-01-28 0.010359 0.058411 1.180538 -0.028096 -0.028096 0.95740\n",
"2011-02-18 0.001031 0.059442 1.290546 -0.028096 -0.028096 0.95720\n",
"2011-03-04 0.001280 0.060722 1.351831 -0.028096 -0.028096 0.99890\n",
"2011-03-18 0.018729 0.079451 1.632026 -0.028096 -0.028096 0.99900\n",
"... ... ... ... ... ... ...\n",
"2016-12-19 0.001795 0.619046 1.928640 -0.013104 -0.035754 0.99999\n",
"2017-01-03 0.006513 0.625559 1.833167 -0.013104 -0.035754 0.99999\n",
"2017-01-17 0.006098 0.631657 1.732021 -0.013104 -0.035754 1.00003\n",
"2017-02-07 0.003424 0.635081 2.190087 -0.013104 -0.035754 1.00003\n",
"2017-02-21 0.010451 0.645533 2.439619 -0.013104 -0.035754 0.99996\n",
"2017-03-07 -0.001086 0.644447 2.149152 -0.013104 -0.035754 0.99798\n",
"2017-03-21 0.016426 0.660873 2.235613 -0.013104 -0.035754 1.00003\n",
"2017-04-06 -0.001144 0.659729 2.356093 -0.013104 -0.035754 1.00003\n",
"2017-04-20 0.007881 0.667610 2.448745 -0.013104 -0.035754 1.00004\n",
"2017-05-05 -0.008892 0.658717 2.227092 -0.013104 -0.035754 1.00004\n",
"2017-05-19 -0.002924 0.655793 2.487909 -0.012972 -0.035754 0.99990\n",
"2017-06-06 0.003434 0.659228 2.593745 -0.012802 -0.035754 0.99990\n",
"2017-06-20 0.011297 0.670525 2.860042 -0.011817 -0.035754 1.00004\n",
"2017-07-04 0.009526 0.680050 3.041796 -0.011817 -0.035754 1.00004\n",
"2017-07-18 0.016175 0.696225 3.055025 -0.011817 -0.035754 0.99999\n",
"2017-08-01 0.002968 0.699193 2.857844 -0.011817 -0.035754 0.99999\n",
"2017-08-15 -0.007531 0.691662 2.289452 -0.011817 -0.035754 1.00004\n",
"2017-08-29 0.001026 0.692688 2.742168 -0.011817 -0.035754 1.00004\n",
"2017-09-12 0.000855 0.693543 2.830931 -0.011817 -0.035754 1.00004\n",
"2017-09-26 -0.000392 0.693151 2.633798 -0.011817 -0.035754 0.99997\n",
"2017-10-17 -0.006175 0.686976 2.390601 -0.012217 -0.035754 0.99997\n",
"2017-10-31 -0.004647 0.682329 2.037490 -0.016864 -0.035754 1.00002\n",
"2017-11-14 0.005732 0.688061 2.259706 -0.016864 -0.035754 1.00011\n",
"2017-11-28 0.014009 0.702070 2.700705 -0.016864 -0.035754 1.00011\n",
"2017-12-12 0.000715 0.702786 2.437891 -0.016864 -0.035754 0.99994\n",
"2017-12-26 0.003241 0.706027 2.481936 -0.016864 -0.035754 0.99996\n",
"2018-01-10 0.009375 0.715401 2.536598 -0.016864 -0.035754 1.00008\n",
"2018-01-24 0.001758 0.717159 2.417740 -0.016864 -0.035754 0.99998\n",
"2018-02-07 0.003852 0.721011 2.429653 -0.016864 -0.035754 0.99993\n",
"2018-02-28 0.000391 0.721402 2.185579 -0.016864 -0.035754 0.99994\n",
"\n",
"[199 rows x 6 columns]"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"res_df"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>leverage</th>\n",
" <th>returns</th>\n",
" <th>turn_over</th>\n",
" <th>index</th>\n",
" <th>tc_cost</th>\n",
" <th>ret_after_tc</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>2010-01-04</th>\n",
" <td>0.00000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-01-18</th>\n",
" <td>1.00000</td>\n",
" <td>0.053401</td>\n",
" <td>1.824820</td>\n",
" <td>0.058077</td>\n",
" <td>0.003650</td>\n",
" <td>-0.008325</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-02-01</th>\n",
" <td>1.00000</td>\n",
" <td>-0.119192</td>\n",
" <td>0.294016</td>\n",
" <td>-0.115825</td>\n",
" <td>0.000588</td>\n",
" <td>-0.003955</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-02-22</th>\n",
" <td>0.99839</td>\n",
" <td>0.030674</td>\n",
" <td>0.416928</td>\n",
" <td>0.035925</td>\n",
" <td>0.000834</td>\n",
" <td>-0.006026</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-03-08</th>\n",
" <td>0.99537</td>\n",
" <td>0.055301</td>\n",
" <td>0.400000</td>\n",
" <td>0.044084</td>\n",
" <td>0.000800</td>\n",
" <td>0.010621</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-03-22</th>\n",
" <td>0.99846</td>\n",
" <td>-0.005239</td>\n",
" <td>0.400000</td>\n",
" <td>-0.000303</td>\n",
" <td>0.000800</td>\n",
" <td>-0.005736</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-04-06</th>\n",
" <td>0.99846</td>\n",
" <td>0.041815</td>\n",
" <td>0.400000</td>\n",
" <td>0.043072</td>\n",
" <td>0.000800</td>\n",
" <td>-0.001990</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-04-20</th>\n",
" <td>0.99837</td>\n",
" <td>0.007571</td>\n",
" <td>0.400000</td>\n",
" <td>0.006209</td>\n",
" <td>0.000800</td>\n",
" <td>0.000573</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-05-05</th>\n",
" <td>0.99837</td>\n",
" <td>-0.086619</td>\n",
" <td>0.400000</td>\n",
" <td>-0.101913</td>\n",
" <td>0.000800</td>\n",
" <td>0.014328</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-05-19</th>\n",
" <td>0.99857</td>\n",
" <td>-0.120487</td>\n",
" <td>0.400000</td>\n",
" <td>-0.124804</td>\n",
" <td>0.000800</td>\n",
" <td>0.003338</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-06-02</th>\n",
" <td>0.99857</td>\n",
" <td>0.038966</td>\n",
" <td>0.400000</td>\n",
" <td>0.038406</td>\n",
" <td>0.000800</td>\n",
" <td>-0.000185</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-06-21</th>\n",
" <td>0.99856</td>\n",
" <td>0.027008</td>\n",
" <td>0.400000</td>\n",
" <td>0.016080</td>\n",
" <td>0.000800</td>\n",
" <td>0.010152</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-07-05</th>\n",
" <td>0.99856</td>\n",
" <td>-0.101685</td>\n",
" <td>0.400000</td>\n",
" <td>-0.116871</td>\n",
" <td>0.000800</td>\n",
" <td>0.014218</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-07-19</th>\n",
" <td>0.99864</td>\n",
" <td>0.090080</td>\n",
" <td>0.357899</td>\n",
" <td>0.075146</td>\n",
" <td>0.000716</td>\n",
" <td>0.014320</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-08-02</th>\n",
" <td>0.99864</td>\n",
" <td>0.065057</td>\n",
" <td>0.400000</td>\n",
" <td>0.059507</td>\n",
" <td>0.000800</td>\n",
" <td>0.004831</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-08-16</th>\n",
" <td>0.99857</td>\n",
" <td>0.060243</td>\n",
" <td>0.442552</td>\n",
" <td>0.061077</td>\n",
" <td>0.000885</td>\n",
" <td>-0.001633</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-08-30</th>\n",
" <td>0.99857</td>\n",
" <td>0.020421</td>\n",
" <td>0.400000</td>\n",
" <td>0.029092</td>\n",
" <td>0.000800</td>\n",
" <td>-0.009430</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-09-13</th>\n",
" <td>0.99857</td>\n",
" <td>0.038996</td>\n",
" <td>0.400000</td>\n",
" <td>0.046005</td>\n",
" <td>0.000800</td>\n",
" <td>-0.007743</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-09-30</th>\n",
" <td>0.99870</td>\n",
" <td>0.017004</td>\n",
" <td>0.400000</td>\n",
" <td>-0.007814</td>\n",
" <td>0.000800</td>\n",
" <td>0.024007</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-10-21</th>\n",
" <td>0.99882</td>\n",
" <td>0.060105</td>\n",
" <td>0.400000</td>\n",
" <td>0.022792</td>\n",
" <td>0.000800</td>\n",
" <td>0.036541</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-11-04</th>\n",
" <td>0.99882</td>\n",
" <td>0.091060</td>\n",
" <td>0.400000</td>\n",
" <td>0.085199</td>\n",
" <td>0.000800</td>\n",
" <td>0.005161</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-11-18</th>\n",
" <td>0.99871</td>\n",
" <td>-0.033025</td>\n",
" <td>0.400000</td>\n",
" <td>-0.044425</td>\n",
" <td>0.000800</td>\n",
" <td>0.010543</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-12-02</th>\n",
" <td>0.99871</td>\n",
" <td>0.011059</td>\n",
" <td>0.400000</td>\n",
" <td>0.003812</td>\n",
" <td>0.000800</td>\n",
" <td>0.006452</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-12-16</th>\n",
" <td>0.99889</td>\n",
" <td>0.037539</td>\n",
" <td>0.342705</td>\n",
" <td>0.024784</td>\n",
" <td>0.000685</td>\n",
" <td>0.012097</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2010-12-30</th>\n",
" <td>0.99889</td>\n",
" <td>-0.051308</td>\n",
" <td>0.400000</td>\n",
" <td>-0.057394</td>\n",
" <td>0.000800</td>\n",
" <td>0.005223</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2011-01-14</th>\n",
" <td>0.99889</td>\n",
" <td>-0.067475</td>\n",
" <td>0.320836</td>\n",
" <td>-0.088210</td>\n",
" <td>0.000642</td>\n",
" <td>0.019996</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2011-01-28</th>\n",
" <td>0.99886</td>\n",
" <td>0.032970</td>\n",
" <td>0.400000</td>\n",
" <td>0.019919</td>\n",
" <td>0.000800</td>\n",
" <td>0.012274</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2011-02-18</th>\n",
" <td>0.99886</td>\n",
" <td>0.096319</td>\n",
" <td>0.400000</td>\n",
" <td>0.089584</td>\n",
" <td>0.000800</td>\n",
" <td>0.006037</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2011-03-04</th>\n",
" <td>0.99669</td>\n",
" <td>0.027365</td>\n",
" <td>0.445334</td>\n",
" <td>0.018727</td>\n",
" <td>0.000891</td>\n",
" <td>0.007809</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2011-03-18</th>\n",
" <td>0.99883</td>\n",
" <td>-0.007476</td>\n",
" <td>0.400000</td>\n",
" <td>-0.010187</td>\n",
" <td>0.000800</td>\n",
" <td>0.001899</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2016-12-19</th>\n",
" <td>0.99999</td>\n",
" <td>-0.033943</td>\n",
" <td>0.400000</td>\n",
" <td>-0.029751</td>\n",
" <td>0.000800</td>\n",
" <td>-0.004993</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-01-03</th>\n",
" <td>0.99999</td>\n",
" <td>0.017296</td>\n",
" <td>0.400000</td>\n",
" <td>0.014796</td>\n",
" <td>0.000800</td>\n",
" <td>0.001700</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-01-17</th>\n",
" <td>1.00015</td>\n",
" <td>-0.052533</td>\n",
" <td>0.495767</td>\n",
" <td>-0.052350</td>\n",
" <td>0.000992</td>\n",
" <td>-0.001166</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-02-07</th>\n",
" <td>1.00015</td>\n",
" <td>0.043140</td>\n",
" <td>0.400000</td>\n",
" <td>0.036071</td>\n",
" <td>0.000800</td>\n",
" <td>0.006263</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-02-21</th>\n",
" <td>0.99995</td>\n",
" <td>0.037631</td>\n",
" <td>0.298597</td>\n",
" <td>0.028620</td>\n",
" <td>0.000597</td>\n",
" <td>0.008415</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-03-07</th>\n",
" <td>0.99995</td>\n",
" <td>0.008797</td>\n",
" <td>0.392917</td>\n",
" <td>0.003521</td>\n",
" <td>0.000786</td>\n",
" <td>0.004491</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-03-21</th>\n",
" <td>0.99992</td>\n",
" <td>0.013840</td>\n",
" <td>0.400000</td>\n",
" <td>0.000433</td>\n",
" <td>0.000800</td>\n",
" <td>0.012607</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-04-06</th>\n",
" <td>0.99992</td>\n",
" <td>0.018937</td>\n",
" <td>0.400000</td>\n",
" <td>0.012087</td>\n",
" <td>0.000800</td>\n",
" <td>0.006052</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-04-20</th>\n",
" <td>1.00001</td>\n",
" <td>-0.025861</td>\n",
" <td>0.400000</td>\n",
" <td>-0.043176</td>\n",
" <td>0.000800</td>\n",
" <td>0.016516</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-05-05</th>\n",
" <td>1.00001</td>\n",
" <td>-0.064204</td>\n",
" <td>0.400000</td>\n",
" <td>-0.052973</td>\n",
" <td>0.000800</td>\n",
" <td>-0.012030</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-05-19</th>\n",
" <td>1.00002</td>\n",
" <td>-0.017313</td>\n",
" <td>0.400000</td>\n",
" <td>-0.014611</td>\n",
" <td>0.000800</td>\n",
" <td>-0.003502</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-06-06</th>\n",
" <td>1.00002</td>\n",
" <td>0.021499</td>\n",
" <td>0.400000</td>\n",
" <td>0.011175</td>\n",
" <td>0.000800</td>\n",
" <td>0.009524</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-06-20</th>\n",
" <td>1.00001</td>\n",
" <td>0.026088</td>\n",
" <td>0.400000</td>\n",
" <td>0.020476</td>\n",
" <td>0.000800</td>\n",
" <td>0.004812</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-07-04</th>\n",
" <td>1.00001</td>\n",
" <td>0.036755</td>\n",
" <td>0.400000</td>\n",
" <td>0.018864</td>\n",
" <td>0.000800</td>\n",
" <td>0.017091</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-07-18</th>\n",
" <td>1.00009</td>\n",
" <td>-0.002142</td>\n",
" <td>0.497130</td>\n",
" <td>-0.021973</td>\n",
" <td>0.000994</td>\n",
" <td>0.018838</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-08-01</th>\n",
" <td>1.00009</td>\n",
" <td>0.044924</td>\n",
" <td>0.400000</td>\n",
" <td>0.031278</td>\n",
" <td>0.000800</td>\n",
" <td>0.012844</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-08-15</th>\n",
" <td>1.00001</td>\n",
" <td>0.015946</td>\n",
" <td>0.400000</td>\n",
" <td>0.010663</td>\n",
" <td>0.000800</td>\n",
" <td>0.004483</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-08-29</th>\n",
" <td>1.00001</td>\n",
" <td>0.023096</td>\n",
" <td>0.400000</td>\n",
" <td>0.021099</td>\n",
" <td>0.000800</td>\n",
" <td>0.001197</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-09-12</th>\n",
" <td>1.00001</td>\n",
" <td>0.042608</td>\n",
" <td>0.400000</td>\n",
" <td>0.035183</td>\n",
" <td>0.000800</td>\n",
" <td>0.006625</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-09-26</th>\n",
" <td>1.00006</td>\n",
" <td>-0.014834</td>\n",
" <td>0.400000</td>\n",
" <td>-0.015251</td>\n",
" <td>0.000800</td>\n",
" <td>-0.000382</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-10-17</th>\n",
" <td>1.00006</td>\n",
" <td>-0.002885</td>\n",
" <td>0.400000</td>\n",
" <td>-0.002997</td>\n",
" <td>0.000800</td>\n",
" <td>-0.000688</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-10-31</th>\n",
" <td>1.00001</td>\n",
" <td>0.003111</td>\n",
" <td>0.372023</td>\n",
" <td>-0.001593</td>\n",
" <td>0.000744</td>\n",
" <td>0.003961</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-11-14</th>\n",
" <td>1.00002</td>\n",
" <td>-0.002265</td>\n",
" <td>0.400000</td>\n",
" <td>-0.002333</td>\n",
" <td>0.000800</td>\n",
" <td>-0.000731</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-11-28</th>\n",
" <td>1.00002</td>\n",
" <td>-0.026042</td>\n",
" <td>0.400000</td>\n",
" <td>-0.034113</td>\n",
" <td>0.000800</td>\n",
" <td>0.007272</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-12-12</th>\n",
" <td>0.99995</td>\n",
" <td>-0.004642</td>\n",
" <td>0.400000</td>\n",
" <td>-0.006497</td>\n",
" <td>0.000800</td>\n",
" <td>0.001054</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2017-12-26</th>\n",
" <td>0.99995</td>\n",
" <td>-0.014361</td>\n",
" <td>0.515549</td>\n",
" <td>-0.016749</td>\n",
" <td>0.001031</td>\n",
" <td>0.001356</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2018-01-10</th>\n",
" <td>0.99999</td>\n",
" <td>0.070323</td>\n",
" <td>0.400000</td>\n",
" <td>0.040133</td>\n",
" <td>0.000800</td>\n",
" <td>0.029391</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2018-01-24</th>\n",
" <td>1.00011</td>\n",
" <td>0.004529</td>\n",
" <td>0.400000</td>\n",
" <td>-0.006750</td>\n",
" <td>0.000800</td>\n",
" <td>0.010480</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2018-02-07</th>\n",
" <td>1.00004</td>\n",
" <td>-0.080637</td>\n",
" <td>0.400000</td>\n",
" <td>-0.101533</td>\n",
" <td>0.000800</td>\n",
" <td>0.020100</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2018-02-28</th>\n",
" <td>0.99994</td>\n",
" <td>0.031790</td>\n",
" <td>0.400000</td>\n",
" <td>0.044632</td>\n",
" <td>0.000800</td>\n",
" <td>-0.013639</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>199 rows × 6 columns</p>\n",
"</div>"
],
"text/plain": [
" leverage returns turn_over index tc_cost ret_after_tc\n",
"2010-01-04 0.00000 0.000000 0.000000 0.000000 0.000000 0.000000\n",
"2010-01-18 1.00000 0.053401 1.824820 0.058077 0.003650 -0.008325\n",
"2010-02-01 1.00000 -0.119192 0.294016 -0.115825 0.000588 -0.003955\n",
"2010-02-22 0.99839 0.030674 0.416928 0.035925 0.000834 -0.006026\n",
"2010-03-08 0.99537 0.055301 0.400000 0.044084 0.000800 0.010621\n",
"2010-03-22 0.99846 -0.005239 0.400000 -0.000303 0.000800 -0.005736\n",
"2010-04-06 0.99846 0.041815 0.400000 0.043072 0.000800 -0.001990\n",
"2010-04-20 0.99837 0.007571 0.400000 0.006209 0.000800 0.000573\n",
"2010-05-05 0.99837 -0.086619 0.400000 -0.101913 0.000800 0.014328\n",
"2010-05-19 0.99857 -0.120487 0.400000 -0.124804 0.000800 0.003338\n",
"2010-06-02 0.99857 0.038966 0.400000 0.038406 0.000800 -0.000185\n",
"2010-06-21 0.99856 0.027008 0.400000 0.016080 0.000800 0.010152\n",
"2010-07-05 0.99856 -0.101685 0.400000 -0.116871 0.000800 0.014218\n",
"2010-07-19 0.99864 0.090080 0.357899 0.075146 0.000716 0.014320\n",
"2010-08-02 0.99864 0.065057 0.400000 0.059507 0.000800 0.004831\n",
"2010-08-16 0.99857 0.060243 0.442552 0.061077 0.000885 -0.001633\n",
"2010-08-30 0.99857 0.020421 0.400000 0.029092 0.000800 -0.009430\n",
"2010-09-13 0.99857 0.038996 0.400000 0.046005 0.000800 -0.007743\n",
"2010-09-30 0.99870 0.017004 0.400000 -0.007814 0.000800 0.024007\n",
"2010-10-21 0.99882 0.060105 0.400000 0.022792 0.000800 0.036541\n",
"2010-11-04 0.99882 0.091060 0.400000 0.085199 0.000800 0.005161\n",
"2010-11-18 0.99871 -0.033025 0.400000 -0.044425 0.000800 0.010543\n",
"2010-12-02 0.99871 0.011059 0.400000 0.003812 0.000800 0.006452\n",
"2010-12-16 0.99889 0.037539 0.342705 0.024784 0.000685 0.012097\n",
"2010-12-30 0.99889 -0.051308 0.400000 -0.057394 0.000800 0.005223\n",
"2011-01-14 0.99889 -0.067475 0.320836 -0.088210 0.000642 0.019996\n",
"2011-01-28 0.99886 0.032970 0.400000 0.019919 0.000800 0.012274\n",
"2011-02-18 0.99886 0.096319 0.400000 0.089584 0.000800 0.006037\n",
"2011-03-04 0.99669 0.027365 0.445334 0.018727 0.000891 0.007809\n",
"2011-03-18 0.99883 -0.007476 0.400000 -0.010187 0.000800 0.001899\n",
"... ... ... ... ... ... ...\n",
"2016-12-19 0.99999 -0.033943 0.400000 -0.029751 0.000800 -0.004993\n",
"2017-01-03 0.99999 0.017296 0.400000 0.014796 0.000800 0.001700\n",
"2017-01-17 1.00015 -0.052533 0.495767 -0.052350 0.000992 -0.001166\n",
"2017-02-07 1.00015 0.043140 0.400000 0.036071 0.000800 0.006263\n",
"2017-02-21 0.99995 0.037631 0.298597 0.028620 0.000597 0.008415\n",
"2017-03-07 0.99995 0.008797 0.392917 0.003521 0.000786 0.004491\n",
"2017-03-21 0.99992 0.013840 0.400000 0.000433 0.000800 0.012607\n",
"2017-04-06 0.99992 0.018937 0.400000 0.012087 0.000800 0.006052\n",
"2017-04-20 1.00001 -0.025861 0.400000 -0.043176 0.000800 0.016516\n",
"2017-05-05 1.00001 -0.064204 0.400000 -0.052973 0.000800 -0.012030\n",
"2017-05-19 1.00002 -0.017313 0.400000 -0.014611 0.000800 -0.003502\n",
"2017-06-06 1.00002 0.021499 0.400000 0.011175 0.000800 0.009524\n",
"2017-06-20 1.00001 0.026088 0.400000 0.020476 0.000800 0.004812\n",
"2017-07-04 1.00001 0.036755 0.400000 0.018864 0.000800 0.017091\n",
"2017-07-18 1.00009 -0.002142 0.497130 -0.021973 0.000994 0.018838\n",
"2017-08-01 1.00009 0.044924 0.400000 0.031278 0.000800 0.012844\n",
"2017-08-15 1.00001 0.015946 0.400000 0.010663 0.000800 0.004483\n",
"2017-08-29 1.00001 0.023096 0.400000 0.021099 0.000800 0.001197\n",
"2017-09-12 1.00001 0.042608 0.400000 0.035183 0.000800 0.006625\n",
"2017-09-26 1.00006 -0.014834 0.400000 -0.015251 0.000800 -0.000382\n",
"2017-10-17 1.00006 -0.002885 0.400000 -0.002997 0.000800 -0.000688\n",
"2017-10-31 1.00001 0.003111 0.372023 -0.001593 0.000744 0.003961\n",
"2017-11-14 1.00002 -0.002265 0.400000 -0.002333 0.000800 -0.000731\n",
"2017-11-28 1.00002 -0.026042 0.400000 -0.034113 0.000800 0.007272\n",
"2017-12-12 0.99995 -0.004642 0.400000 -0.006497 0.000800 0.001054\n",
"2017-12-26 0.99995 -0.014361 0.515549 -0.016749 0.001031 0.001356\n",
"2018-01-10 0.99999 0.070323 0.400000 0.040133 0.000800 0.029391\n",
"2018-01-24 1.00011 0.004529 0.400000 -0.006750 0.000800 0.010480\n",
"2018-02-07 1.00004 -0.080637 0.400000 -0.101533 0.000800 0.020100\n",
"2018-02-28 0.99994 0.031790 0.400000 0.044632 0.000800 -0.013639\n",
"\n",
"[199 rows x 6 columns]"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ret_df"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'zz800'"
]
},
"execution_count": 46,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"universe.base_universe[0]"
]
},
{
"cell_type": "code",
"execution_count": null,
...
...
@@ -1738,6 +379,35 @@
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.4"
},
"varInspector": {
"cols": {
"lenName": 16,
"lenType": 16,
"lenVar": 40
},
"kernels_config": {
"python": {
"delete_cmd_postfix": "",
"delete_cmd_prefix": "del ",
"library": "var_list.py",
"varRefreshCmd": "print(var_dic_list())"
},
"r": {
"delete_cmd_postfix": ") ",
"delete_cmd_prefix": "rm(",
"library": "var_list.r",
"varRefreshCmd": "cat(var_dic_list()) "
}
},
"types_to_exclude": [
"module",
"function",
"builtin_function_or_method",
"instance",
"_Feature"
],
"window_display": false
}
},
"nbformat": 4,
...
...
notebooks/Example 4 - Single Factor Analysis.ipynb
View file @
233c92ad
This source diff could not be displayed because it is too large. You can
view the blob
instead.
notebooks/Example 5 - Style Factor Analysis.ipynb
0 → 100644
View file @
233c92ad
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> The methodolegy is similar to The Barra China Equity Model (CNE5)'s documentation"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"\n",
"import numpy as np\n",
"import pandas as pd\n",
"from matplotlib import pyplot as plt\n",
"import statsmodels.api as sm\n",
"from alphamind.api import *\n",
"from PyFin.api import *\n",
"from alphamind.analysis.crosssetctions import cross_section_analysis\n",
"\n",
"plt.style.use('ggplot')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"\"\"\"\n",
"Back test parameter settings\n",
"\"\"\"\n",
"\n",
"start_date = '2010-01-01'\n",
"end_date = '2018-02-28'\n",
"category = 'sw_adj'\n",
"level = 1\n",
"freq = '20b'\n",
"universe = Universe('custom', ['ashare_ex'])\n",
"\n",
"\n",
"horizon = map_freq(freq)\n",
"ref_dates = makeSchedule(start_date, end_date, freq, 'china.sse')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def risk_factor_analysis(factor_name):\n",
" data_source = 'postgres+psycopg2://postgres:A12345678!@10.63.6.220/alpha'\n",
" engine = SqlEngine(data_source)\n",
" risk_names = list(set(risk_styles).difference({factor_name}))\n",
" industry_names = list(set(industry_styles).difference({factor_name}))\n",
" constraint_risk = risk_names + industry_names\n",
" \n",
" df = pd.DataFrame(columns=['ret', 'ic', 't.'], dtype=float)\n",
"\n",
" for ref_date in ref_dates:\n",
" df.loc[ref_date, :] = cross_section_analysis(ref_date,\n",
" factor_name,\n",
" universe,\n",
" horizon,\n",
" constraint_risk,\n",
" engine=engine)\n",
" df.index = pd.to_datetime(df.index)\n",
" return df"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"candidates_factors = risk_styles + industry_styles"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from dask.distributed import Client\n",
"\n",
"with Client('10.63.6.176:8786') as client:\n",
" tasks = client.map(risk_factor_analysis, candidates_factors, pure=False)\n",
" res = client.gather(tasks)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df = pd.DataFrame()\n",
"\n",
"for f_name, data in zip(candidates_factors, res):\n",
" data['factor'] = f_name\n",
" df = df.append(data)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df['abs t.'] = np.abs(df['t.'])\n",
"df[['factor', 'abs t.']].groupby('factor').mean().sort_values('abs t.', ascending=False).head()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.4"
},
"varInspector": {
"cols": {
"lenName": 16,
"lenType": 16,
"lenVar": 40
},
"kernels_config": {
"python": {
"delete_cmd_postfix": "",
"delete_cmd_prefix": "del ",
"library": "var_list.py",
"varRefreshCmd": "print(var_dic_list())"
},
"r": {
"delete_cmd_postfix": ") ",
"delete_cmd_prefix": "rm(",
"library": "var_list.r",
"varRefreshCmd": "cat(var_dic_list()) "
}
},
"position": {
"height": "607px",
"left": "1093px",
"right": "20px",
"top": "94px",
"width": "756px"
},
"types_to_exclude": [
"module",
"function",
"builtin_function_or_method",
"instance",
"_Feature"
],
"window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 2
}
notebooks/notebook_utilities.py
0 → 100644
View file @
233c92ad
# -*- coding: utf-8 -*-
"""
Created on 2018-3-5
@author: cheng.li
"""
import
numpy
as
np
import
pandas
as
pd
import
statsmodels.api
as
sm
from
alphamind.api
import
(
SqlEngine
,
LinearConstraints
,
er_portfolio_analysis
,
alpha_logger
)
def
cross_section_analysis
(
ref_date
,
factor_name
,
universe
,
horizon
,
constraint_risk
,
linear_bounds
,
lbound
,
ubound
,
engine
):
codes
=
engine
.
fetch_codes
(
ref_date
,
universe
)
risk_exposure
=
engine
.
fetch_risk_model
(
ref_date
,
codes
)[
1
][[
'code'
]
+
constraint_risk
]
factor_data
=
engine
.
fetch_factor
(
ref_date
,
factor_name
,
codes
)
industry_matrix
=
engine
.
fetch_industry_matrix
(
ref_date
,
codes
,
'sw_adj'
,
1
)
total_data
=
pd
.
merge
(
factor_data
,
risk_exposure
,
on
=
'code'
)
total_data
=
pd
.
merge
(
total_data
,
industry_matrix
,
on
=
'code'
)
.
dropna
()
total_risk_exp
=
total_data
[
constraint_risk
]
constraints
=
LinearConstraints
(
linear_bounds
,
total_risk_exp
)
er
=
total_data
[
factor_name
]
.
values
industry
=
total_data
.
industry_name
.
values
target_pos
,
_
=
er_portfolio_analysis
(
er
,
industry
,
None
,
constraints
,
False
,
None
,
method
=
'risk_neutral'
,
lbound
=
lbound
*
np
.
ones
(
len
(
er
)),
ubound
=
ubound
*
np
.
ones
(
len
(
er
)))
codes
=
total_data
.
code
.
tolist
()
target_pos
[
'code'
]
=
codes
dx_returns
=
engine
.
fetch_dx_return
(
ref_date
,
codes
,
horizon
=
horizon
,
offset
=
1
)
target_pos
=
pd
.
merge
(
target_pos
,
dx_returns
,
on
=
[
'code'
])
activate_weight
=
target_pos
.
weight
.
values
excess_return
=
np
.
exp
(
target_pos
.
dx
.
values
)
-
1.
port_ret
=
np
.
log
(
activate_weight
@
excess_return
+
1.
)
ic
=
np
.
corrcoef
(
excess_return
,
activate_weight
)[
0
,
1
]
x
=
sm
.
add_constant
(
activate_weight
)
results
=
sm
.
OLS
(
excess_return
,
x
)
.
fit
()
t_stats
=
results
.
tvalues
[
1
]
alpha_logger
.
info
(
f
"{ref_date} is finished with {len(target_pos)} stocks for {factor_name}"
)
return
port_ret
,
ic
,
t_stats
if
__name__
==
'__main__'
:
from
alphamind.api
import
(
Universe
,
map_freq
,
risk_styles
,
industry_styles
,
macro_styles
,
BoundaryType
,
create_box_bounds
)
"""
Back test parameter settings
"""
start_date
=
'2010-01-01'
end_date
=
'2018-02-28'
category
=
'sw_adj'
level
=
1
freq
=
'20b'
universe
=
Universe
(
'custom'
,
[
'zz800'
])
data_source
=
'postgres+psycopg2://postgres:A12345678!@10.63.6.220/alpha'
engine
=
SqlEngine
(
data_source
)
horizon
=
map_freq
(
freq
)
"""
Factor Model
"""
factor_name
=
'SIZE'
"""
Constraints
"""
risk_names
=
list
(
set
(
risk_styles
)
.
difference
({
factor_name
}))
industry_names
=
list
(
set
(
industry_styles
)
.
difference
({
factor_name
}))
constraint_risk
=
risk_names
+
industry_names
+
macro_styles
b_type
=
[]
l_val
=
[]
u_val
=
[]
for
name
in
constraint_risk
:
if
name
in
set
(
risk_styles
):
b_type
.
append
(
BoundaryType
.
ABSOLUTE
)
l_val
.
append
(
0.0
)
u_val
.
append
(
0.0
)
else
:
b_type
.
append
(
BoundaryType
.
RELATIVE
)
l_val
.
append
(
1.0
)
u_val
.
append
(
1.0
)
linear_bounds
=
create_box_bounds
(
constraint_risk
,
b_type
,
l_val
,
u_val
)
ref_date
=
'2018-02-08'
df
=
pd
.
DataFrame
(
columns
=
[
'ret'
,
'ic'
,
't.'
])
print
(
cross_section_analysis
(
ref_date
,
factor_name
,
universe
,
horizon
,
constraint_risk
,
linear_bounds
,
lbound
=-
0.01
,
ubound
=
0.01
,
engine
=
engine
))
\ No newline at end of file
scripts/update_uqer_data_postgres.py
View file @
233c92ad
...
...
@@ -21,7 +21,7 @@ from alphamind.data.dbmodel.models import *
uqer
.
DataAPI
.
api_base
.
timeout
=
300
start_date
=
dt
.
datetime
(
201
7
,
8
,
22
)
start_date
=
dt
.
datetime
(
201
0
,
1
,
1
)
dag_name
=
'update_uqer_data_postgres'
default_args
=
{
...
...
@@ -71,6 +71,41 @@ def data_info_log(df, table):
raise
ValueError
(
msg
)
def
update_uqer_index_market
(
ds
,
**
kwargs
):
ref_date
,
this_date
=
process_date
(
ds
)
flag
=
check_holiday
(
this_date
)
if
not
flag
:
return
df
=
api
.
MktIdxdGet
(
tradeDate
=
ref_date
)
df
=
df
[
df
.
exchangeCD
.
isin
([
'XSHE'
,
'XSHG'
,
'ZICN'
])]
df
=
df
[
df
.
ticker
<=
'999999'
]
df
.
rename
(
columns
=
{
'tradeDate'
:
'trade_date'
,
'ticker'
:
'indexCode'
,
'CHGPct'
:
'chgPct'
,
'secShortName'
:
'indexShortName'
},
inplace
=
True
)
df
=
df
[[
'trade_date'
,
'indexCode'
,
'preCloseIndex'
,
'openIndex'
,
'highestIndex'
,
'lowestIndex'
,
'closeIndex'
,
'turnoverVol'
,
'turnoverValue'
,
'chgPct'
]]
df
[
'indexCode'
]
=
df
.
indexCode
.
astype
(
int
)
query
=
delete
(
IndexMarket
)
.
where
(
IndexMarket
.
trade_date
==
this_date
)
engine
.
execute
(
query
)
data_info_log
(
df
,
Market
)
format_data
(
df
,
format
=
'
%
Y-
%
m-
%
d'
)
df
.
to_sql
(
IndexMarket
.
__table__
.
name
,
engine
,
index
=
False
,
if_exists
=
'append'
)
def
update_uqer_factors
(
ds
,
**
kwargs
):
ref_date
,
this_date
=
process_date
(
ds
)
flag
=
check_holiday
(
this_date
)
...
...
@@ -265,6 +300,105 @@ def update_uqer_universe_zz800(ds, **kwargs):
df
.
to_sql
(
Universe
.
__table__
.
name
,
engine
,
index
=
False
,
if_exists
=
'append'
)
def
update_uqer_universe_zz1000
(
ds
,
**
kwargs
):
ref_date
,
this_date
=
process_date
(
ds
)
flag
=
check_holiday
(
this_date
)
if
not
flag
:
return
query
=
delete
(
Universe
)
.
where
(
and_
(
Universe
.
trade_date
==
this_date
,
Universe
.
universe
==
'zz1000'
)
)
engine
.
execute
(
query
)
query
=
select
([
IndexComponent
.
trade_date
,
IndexComponent
.
code
])
.
where
(
and_
(
IndexComponent
.
trade_date
==
this_date
,
IndexComponent
.
indexCode
==
852
)
)
df
=
pd
.
read_sql
(
query
,
engine
)
if
df
.
empty
:
return
df
[
'universe'
]
=
'zz1000'
data_info_log
(
df
,
Universe
)
format_data
(
df
)
df
.
to_sql
(
Universe
.
__table__
.
name
,
engine
,
index
=
False
,
if_exists
=
'append'
)
def
update_uqer_universe_zxb
(
ds
,
**
kwargs
):
ref_date
,
this_date
=
process_date
(
ds
)
flag
=
check_holiday
(
this_date
)
if
not
flag
:
return
query
=
delete
(
Universe
)
.
where
(
and_
(
Universe
.
trade_date
==
this_date
,
Universe
.
universe
==
'zxb'
)
)
engine
.
execute
(
query
)
query
=
select
([
IndexComponent
.
trade_date
,
IndexComponent
.
code
])
.
where
(
and_
(
IndexComponent
.
trade_date
==
this_date
,
IndexComponent
.
indexCode
==
399005
)
)
df
=
pd
.
read_sql
(
query
,
engine
)
if
df
.
empty
:
return
df
[
'universe'
]
=
'zxb'
data_info_log
(
df
,
Universe
)
format_data
(
df
)
df
.
to_sql
(
Universe
.
__table__
.
name
,
engine
,
index
=
False
,
if_exists
=
'append'
)
def
update_uqer_universe_cyb
(
ds
,
**
kwargs
):
ref_date
,
this_date
=
process_date
(
ds
)
flag
=
check_holiday
(
this_date
)
if
not
flag
:
return
query
=
delete
(
Universe
)
.
where
(
and_
(
Universe
.
trade_date
==
this_date
,
Universe
.
universe
==
'cyb'
)
)
engine
.
execute
(
query
)
query
=
select
([
IndexComponent
.
trade_date
,
IndexComponent
.
code
])
.
where
(
and_
(
IndexComponent
.
trade_date
==
this_date
,
IndexComponent
.
indexCode
==
399006
)
)
df
=
pd
.
read_sql
(
query
,
engine
)
if
df
.
empty
:
return
df
[
'universe'
]
=
'cyb'
data_info_log
(
df
,
Universe
)
format_data
(
df
)
df
.
to_sql
(
Universe
.
__table__
.
name
,
engine
,
index
=
False
,
if_exists
=
'append'
)
def
update_uqer_universe_security_master
(
ds
,
**
kwargs
):
ref_date
,
this_date
=
process_date
(
ds
)
flag
=
check_holiday
(
this_date
)
...
...
@@ -442,7 +576,20 @@ def update_uqer_index_components(ds, **kwargs):
if
df
.
empty
:
continue
alpha_logger
.
info
(
'{0} is finished with previous data {1}'
.
format
(
index
,
len
(
df
)))
else
:
################################
# 2017-10-09, patch for uqer bug
def
filter_out_eqy
(
code
:
str
):
if
code
[
0
]
in
[
'0'
,
'3'
]
and
code
[
-
4
:]
in
[
'XSHE'
]:
return
True
elif
code
[
0
]
in
[
'6'
]
and
code
[
-
4
:]
in
[
'XSHG'
]:
return
True
else
:
return
False
df
=
df
[
df
.
consID
.
apply
(
lambda
x
:
filter_out_eqy
(
x
))]
################################
df
.
rename
(
columns
=
{
'ticker'
:
'indexCode'
,
'secShortName'
:
'indexShortName'
,
'consTickerSymbol'
:
'code'
,
...
...
@@ -453,6 +600,7 @@ def update_uqer_index_components(ds, **kwargs):
df
[
'trade_date'
]
=
this_date
del
df
[
'secID'
]
del
df
[
'consID'
]
alpha_logger
.
info
(
'{0} is finished with new data {1}'
.
format
(
index
,
len
(
df
)))
total_data
=
total_data
.
append
(
df
)
index_codes
=
total_data
.
indexCode
.
unique
()
...
...
@@ -551,23 +699,6 @@ def update_uqer_risk_model(ds, **kwargs):
df
.
to_sql
(
SpecificRiskLong
.
__table__
.
name
,
engine
,
index
=
False
,
if_exists
=
'append'
)
def
update_uqer_daily_return
(
ds
,
**
kwargs
):
ref_date
,
this_date
=
process_date
(
ds
)
flag
=
check_holiday
(
this_date
)
if
not
flag
:
return
previous_date
=
advanceDateByCalendar
(
'china.sse'
,
this_date
,
'-1b'
)
.
strftime
(
'
%
Y-
%
m-
%
d'
)
query
=
select
([
Market
.
code
,
Market
.
chgPct
.
label
(
'd1'
)])
.
where
(
Market
.
trade_date
==
this_date
)
df
=
pd
.
read_sql
(
query
,
engine
)
df
[
'trade_date'
]
=
previous_date
engine
.
execute
(
delete
(
DailyReturn
)
.
where
(
DailyReturn
.
trade_date
==
previous_date
))
data_info_log
(
df
,
DailyReturn
)
df
.
to_sql
(
DailyReturn
.
__table__
.
name
,
engine
,
index
=
False
,
if_exists
=
'append'
)
def
update_uqer_industry_info
(
ds
,
**
kwargs
):
ref_date
,
this_date
=
process_date
(
ds
)
flag
=
check_holiday
(
this_date
)
...
...
@@ -623,11 +754,12 @@ def fetch_date(table, query_date, engine):
return
df
def
update_materialized_views
(
ds
,
**
kwargs
):
alpha_logger
.
info
(
"starting refresh full_factor_view ..."
)
engine
.
execute
(
"REFRESH MATERIALIZED VIEW CONCURRENTLY full_factor_view;"
)
alpha_logger
.
info
(
"starting cluster full_factor_view ..."
)
engine
.
execute
(
"CLUSTER full_factor_view;"
)
index_market_task
=
PythonOperator
(
task_id
=
'update_uqer_index_market'
,
provide_context
=
True
,
python_callable
=
update_uqer_index_market
,
dag
=
dag
)
uqer_task
=
PythonOperator
(
...
...
@@ -644,13 +776,6 @@ market_task = PythonOperator(
dag
=
dag
)
return_task
=
PythonOperator
(
task_id
=
'update_uqer_daily_return'
,
provide_context
=
True
,
python_callable
=
update_uqer_daily_return
,
dag
=
dag
)
industry_task
=
PythonOperator
(
task_id
=
'update_uqer_industry_info'
,
provide_context
=
True
,
...
...
@@ -658,7 +783,6 @@ industry_task = PythonOperator(
dag
=
dag
)
return_task
.
set_upstream
(
market_task
)
industry_task
.
set_upstream
(
market_task
)
index_task
=
PythonOperator
(
...
...
@@ -689,6 +813,13 @@ universe800_task = PythonOperator(
dag
=
dag
)
universe1000_task
=
PythonOperator
(
task_id
=
'update_uqer_universe_zz1000'
,
provide_context
=
True
,
python_callable
=
update_uqer_universe_zz1000
,
dag
=
dag
)
universe50_task
=
PythonOperator
(
task_id
=
'update_uqer_universe_sh50'
,
provide_context
=
True
,
...
...
@@ -696,16 +827,32 @@ universe50_task = PythonOperator(
dag
=
dag
)
universe_zxb_task
=
PythonOperator
(
task_id
=
'update_uqer_universe_zxb'
,
provide_context
=
True
,
python_callable
=
update_uqer_universe_zxb
,
dag
=
dag
)
universe_cyb_task
=
PythonOperator
(
task_id
=
'update_uqer_universe_cyb'
,
provide_context
=
True
,
python_callable
=
update_uqer_universe_cyb
,
dag
=
dag
)
universe300_task
.
set_upstream
(
index_task
)
universe500_task
.
set_upstream
(
index_task
)
universe800_task
.
set_upstream
(
index_task
)
universe1000_task
.
set_upstream
(
index_task
)
universe50_task
.
set_upstream
(
index_task
)
universe_zxb_task
.
set_upstream
(
index_task
)
universe_cyb_task
.
set_upstream
(
index_task
)
security_master_task
=
PythonOperator
(
task_id
=
'update_uqer_universe_security_master'
,
provide_context
=
True
,
python_callable
=
update_uqer_universe_security_master
,
dependes_on_past
=
True
,
dag
=
dag
)
...
...
@@ -742,18 +889,6 @@ _ = PythonOperator(
dag
=
dag
)
refresh_materialized_views_task
=
PythonOperator
(
task_id
=
'update_materialized_views'
,
provide_context
=
True
,
python_callable
=
update_materialized_views
,
dag
=
dag
)
refresh_materialized_views_task
.
set_upstream
(
market_task
)
refresh_materialized_views_task
.
set_upstream
(
uqer_task
)
refresh_materialized_views_task
.
set_upstream
(
risk_model_task
)
if
__name__
==
'__main__'
:
update_uqer_index_components
(
ds
=
'201
0-02-01
'
)
update_uqer_index_components
(
ds
=
'201
7-11-10
'
)
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