量化投资 — 简单动量策略(Momentum Strategy)

时间:2024-03-18 19:17:33

动量策略 - Momentum Strategy

0. 引库

import numpy as np
import pandas as pd
import tushare as ts
import matplotlib.pyplot as plt
import seaborn
plt.style.use('seaborn')      
import matplotlib as mpl
%matplotlib inline
mpl.rcParams['font.family'] = 'serif'
import warnings; warnings.simplefilter('ignore')     # 忽略警告信息

1. 数据准备 & 回测准备

# tushare 获取沪深300股票数据
data = ts.get_k_data('hs300', start = '2010-01-01', end='2017-06-30')[['date','close']]
data.rename(columns={'close': 'price'}, inplace=True)
data.set_index('date', inplace = True)
data.head()
price
date
2010-01-04 3535.229
2010-01-05 3564.038
2010-01-06 3541.727
2010-01-07 3471.456
2010-01-08 3480.130

2. 策略开发思路

# 计算连续收益率
data['returns'] = np.log(data['price'] / data['price'].shift(1))
data.head()
price returns
date
2010-01-04 3535.229 NaN
2010-01-05 3564.038 0.008116
2010-01-06 3541.727 -0.006280
2010-01-07 3471.456 -0.020040
2010-01-08 3480.130 0.002496
# np.sign()符号函数支持向量化
data['position'] = np.sign(data['returns'])     
data.head()
price returns position
date
2010-01-04 3535.229 NaN NaN
2010-01-05 3564.038 0.008116 1.0
2010-01-06 3541.727 -0.006280 -1.0
2010-01-07 3471.456 -0.020040 -1.0
2010-01-08 3480.130 0.002496 1.0
# 计算Momentum策略收益(注意未来函数问题)
data['strategy'] = data['position'].shift(1) * data['returns']  
data.head(10)
price returns position strategy
date
2010-01-04 3535.229 NaN NaN NaN
2010-01-05 3564.038 0.008116 1.0 NaN
2010-01-06 3541.727 -0.006280 -1.0 -0.006280
2010-01-07 3471.456 -0.020040 -1.0 0.020040
2010-01-08 3480.130 0.002496 1.0 -0.002496
2010-01-11 3482.052 0.000552 1.0 0.000552
2010-01-12 3534.916 0.015068 1.0 0.015068
2010-01-13 3421.144 -0.032715 -1.0 -0.032715
2010-01-14 3469.051 0.013906 1.0 -0.013906
2010-01-15 3482.738 0.003938 1.0 0.003938

3. 策略可视化

# 计算策略最终累计收益
data[['returns', 'strategy']].cumsum().apply(np.exp).plot(figsize=(10, 6))

量化投资 — 简单动量策略(Momentum Strategy)

4. 策略优化之思路——参数优化和穷举

# 计算5日内平均信号
data['position_5'] = np.sign(data['returns'].rolling(5).mean())
data['strategy_5'] = data['position_5'].shift(1) * data['returns']
data[['returns', 'strategy_5']].dropna().cumsum().apply(np.exp).plot(figsize=(10, 6))

量化投资 — 简单动量策略(Momentum Strategy)

参数寻优——使用离散Return计算方法

data['returns_dis'] = data['price'] / data['price'].shift(1) - 1
# 也可这样计算离散收益率:data['returns_dis'] = data['price'].pct_change()
data['returns_dis_cum'] = (data['returns_dis'] + 1).cumprod()
data.head()
price returns position strategy position_5 strategy_5 returns_dis returns_dis_cum
date
2010-01-04 3535.229 NaN NaN NaN NaN NaN NaN NaN
2010-01-05 3564.038 0.008116 1.0 NaN NaN NaN 0.008149 1.008149
2010-01-06 3541.727 -0.006280 -1.0 -0.006280 NaN NaN -0.006260 1.001838
2010-01-07 3471.456 -0.020040 -1.0 0.020040 NaN NaN -0.019841 0.981961
2010-01-08 3480.130 0.002496 1.0 -0.002496 NaN NaN 0.002499 0.984414
# 建立一个绘制图形的 list
price_plot = ['returns_dis_cum']    
type(price_plot)
list
# 参数寻优(入门方法)
for days in [10,20,30,60]:
    price_plot.append('sty_cumr_%dd' % days)
    data['position_%dd' % days] = np.where(data['returns'].rolling(days).mean()>0, 1, -1)
    data['strategy_%dd' % days] = data['position_%dd' % days].shift(1) * data['returns']
    data['sty_cumr_%dd' % days] = (data['strategy_%dd' % days] + 1).cumprod()
data.head()
price returns position strategy position_5 strategy_5 returns_dis returns_dis_cum position_10d strategy_10d sty_cumr_10d position_20d strategy_20d sty_cumr_20d position_30d strategy_30d sty_cumr_30d position_60d strategy_60d sty_cumr_60d
date
2010-01-04 3535.229 NaN NaN NaN NaN NaN NaN NaN -1 NaN NaN -1 NaN NaN -1 NaN NaN -1 NaN NaN
2010-01-05 3564.038 0.008116 1.0 NaN NaN NaN 0.008149 1.008149 -1 -0.008116 0.991884 -1 -0.008116 0.991884 -1 -0.008116 0.991884 -1 -0.008116 0.991884
2010-01-06 3541.727 -0.006280 -1.0 -0.006280 NaN NaN -0.006260 1.001838 -1 0.006280 0.998113 -1 0.006280 0.998113 -1 0.006280 0.998113 -1 0.006280 0.998113
2010-01-07 3471.456 -0.020040 -1.0 0.020040 NaN NaN -0.019841 0.981961 -1 0.020040 1.018115 -1 0.020040 1.018115 -1 0.020040 1.018115 -1 0.020040 1.018115
2010-01-08 3480.130 0.002496 1.0 -0.002496 NaN NaN 0.002499 0.984414 -1 -0.002496 1.015574 -1 -0.002496 1.015574 -1 -0.002496 1.015574 -1 -0.002496 1.015574
# 查看绘制图形的 list
price_plot
['returns_dis_cum',
 'sty_cumr_10d',
 'sty_cumr_20d',
 'sty_cumr_30d',
 'sty_cumr_60d']
data[price_plot].dropna().plot(
    title='HS300 Multi Parameters Momuntum Strategy',
    figsize=(10, 6), style=['--', '--', '--', '--','--'])

量化投资 — 简单动量策略(Momentum Strategy)

5. 策略优化思路之—— High Frequency Data用于Momentum策略

hs300_hf = ts.get_k_data('hs300', ktype='5')
hs300_hf.head(10)
date open close high low volume amount turnoverratio code
0 2019-03-28 14:55 3724.82 3725.07 3725.68 3724.42 3806742.0 {} 0.0000 hs300
1 2019-03-28 15:00 3725.07 3728.40 3728.40 3724.90 2450800.0 {} 0.0000 hs300
2 2019-03-29 09:35 3739.77 3754.43 3754.51 3739.77 10164739.0 {} 0.0000 hs300
3 2019-03-29 09:40 3754.44 3763.63 3763.94 3748.90 6341654.0 {} 0.0000 hs300
4 2019-03-29 09:45 3764.66 3763.26 3764.84 3759.35 5622416.0 {} 0.0000 hs300
5 2019-03-29 09:50 3763.44 3762.66 3763.89 3754.12 5955572.0 {} 0.0000 hs300
6 2019-03-29 09:55 3762.87 3766.84 3769.46 3762.87 4600542.0 {} 0.0000 hs300
7 2019-03-29 10:00 3766.66 3758.50 3766.66 3757.00 5533989.0 {} 0.0000 hs300
8 2019-03-29 10:05 3758.20 3765.39 3765.39 3758.20 3587029.0 {} 0.0000 hs300
9 2019-03-29 10:10 3766.19 3775.06 3775.15 3766.19 3993704.0 {} 0.0000 hs300
hs300_hf.set_index('date',inplace = True)
hs300_hf.index = hs300_hf.index.to_datetime()
hs300_hf.info()          
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 482 entries, 2019-03-28 14:55:00 to 2019-04-12 15:00:00
Data columns (total 8 columns):
open             482 non-null float64
close            482 non-null float64
high             482 non-null float64
low              482 non-null float64
volume           482 non-null float64
amount           482 non-null object
turnoverratio    482 non-null object
code             482 non-null object
dtypes: float64(5), object(3)
memory usage: 33.9+ KB
# 如果自己实现,请注意具体日期范围,否则可能没有数据
hs300_hf['2019-04-01':'2019-04-02'].head()
open close high low volume amount turnoverratio code
2019-04-01 09:35:00 3901.17 3923.72 3929.06 3901.17 25618175.0 {} 0.0000 hs300
2019-04-01 09:40:00 3923.72 3952.36 3952.74 3921.96 14481548.0 {} 0.0000 hs300
2019-04-01 09:45:00 3952.36 3952.94 3955.06 3951.27 13020862.0 {} 0.0000 hs300
2019-04-01 09:50:00 3952.94 3965.55 3967.12 3952.94 11968217.0 {} 0.0000 hs300
2019-04-01 09:55:00 3965.55 3953.47 3965.55 3951.80 9892385.0 {} 0.0000 hs300
hs300_hf['returns'] = np.log(hs300_hf['close'] / hs300_hf['close'].shift(1))
hs300_hf['position'] = np.sign(hs300_hf['returns'].rolling(10).mean()) 
hs300_hf['strategy'] = hs300_hf['position'].shift(1) * hs300_hf['returns']
# 画图
hs300_hf[['returns', 'strategy']].dropna().cumsum().apply(np.exp).plot(figsize=(10, 6), style=['--', '--'])

量化投资 — 简单动量策略(Momentum Strategy)