三大经典策略

前导知识

1. tushare使用

tushare是一个免费的、开源的python财经数据接口包。主要实现对股票等金融数据从数据采集清洗加工数据存储的过程,能够为金融分析人员提供快速、整洁、和多样的便于分析的数据,为他们在数据获取方面极大地减轻工作量,使他们更加专注于策略和模型的研究与实现上。考虑到Python pandas包在金融量化分析中体现出的优势,Tushare返回的绝大部分的数据格式都是pandas DataFrame类型,非常便于用pandas/NumPy/Matplotlib进行数据分析和可视化。当然也可以使用tushare的数据存储功能将数据存储到excel。目前老版tushare不再维护,即将停止更新,可以使用Pro版接口,如果想要获取更多、更详细的数据,需要注册成为tushare社区用户,凭积分获取数据。

下面简单介绍tushare的安装与应用。在命令提示符下输入:

pip install tushare

下面演示如何通过tushare调取数据,我们这里对tushare pro进行演示。

我们获取股票基础数据,包括股票代码、名称、上市日期等,如下所示:

初始化pro接口:

>>> pro = ts.pro_api()

查询当前正常交易上市的股票信息:

>>> data = pro.stock_basic(exchange='', list_status='L',\
                           fields='ts_code,symbol,name,area,industry,list_date')
>>> data.head()
     ts_code  symbol  name area industry list_date
0  000001.SZ  000001  平安银行   深圳       银行  19910403
1  000002.SZ  000002   万科A   深圳     全国地产  19910129
2  000004.SZ  000004  国华网安   深圳      互联网  19910114
3  000005.SZ  000005  世纪星源   深圳     环境保护  19901210
4  000006.SZ  000006  深振业A   深圳     区域地产  19920427

我们还可以获取股票日线行情数据,如下所示:

获取平安银行2020年12月至2021年1月的前复权数据:

>>> df = ts.pro_bar(ts_code='000001.SZ', adj='qfq', start_date='20201201', end_date='20210131')
>>> df.head()
     ts_code trade_date   open   high  ...  change  pct_chg         vol       amount
0  000001.SZ   20210129  22.81  23.54  ...    0.28   1.2275  1240258.41  2864101.419
1  000001.SZ   20210128  22.78  23.18  ...   -0.27  -1.1698   857476.96  1948881.146
2  000001.SZ   20210127  22.31  23.47  ...    0.71   3.1739  1294152.72  2976800.955
3  000001.SZ   20210126  22.30  23.32  ...   -0.12  -0.5336  1126720.55  2558575.511
4  000001.SZ   20210125  21.72  22.60  ...    0.46   2.0881  1028365.27  2269032.820

[5 rows x 11 columns]

我们可以获取平安银行均线数据:

>>> df = ts.pro_bar(ts_code='000001.SZ', start_date='20201201', end_date='20210131', ma=[5, 10])
>>> df.head()
     ts_code trade_date   open   high  ...     ma5       ma_v_5    ma10      ma_v_10
0  000001.SZ   20210129  22.81  23.54  ...  22.768  1109394.782  22.561  1209637.021
1  000001.SZ   20210128  22.78  23.18  ...  22.556  1046229.984  22.352  1333680.078
2  000001.SZ   20210127  22.31  23.47  ...  22.440  1063690.312  22.088  1360947.944
3  000001.SZ   20210126  22.30  23.32  ...  22.318  1061018.400  21.850  1336444.645
4  000001.SZ   20210125  21.72  22.60  ...  22.312  1084091.958  21.713  1352589.140

[5 rows x 15 columns]

当然有些数据需要一定的积分才能够调取,所以为了获取足够的积分,调取更多数据,可以积极注册称为tushare社区用户,多多参与社区活动,获取更多平台的权益。

tushare pro的网址:https://tushare.pro/

在下面策略中我们使用老版tushare接口调取沪深300日线数据用于策略的实现。

2. python包的使用

在量化投资领域,最流行的语言为python,其原因在于python语法简单、易上手,有许多数据分析、可视化和统计建模的包可供使用,在下面的策略中,我们使用如下的包:

import matplotlib.pyplot as plt   
import matplotlib as mpl      #matplotlib是绘图时最常用的包
plt.style.use('seaborn')      #seaborn也是可视化的包,这里为了让绘制的图如seaborn那般美观
mpl.rcParams['font.family'] = 'serif'  #设置字体防止乱码
import warnings; warnings.simplefilter('ignore')#由于版本的原因,会出现警告信息,这里忽略
import pandas as pd 
import numpy as np
import tushare as ts

3. 收益率计算方式

收益率的计算方式有两种:离散型连续型。设当期股票价格为 P t P_t Pt,则离散型股票收益率计算方式为: P t P t − 1 − 1 \frac{P_t}{P_{t-1}}-1 Pt1Pt1;连续型收益率计算方式为: log ⁡ ( P t / P t − 1 ) \log(P_t/P_{t-1}) log(Pt/Pt1),两种计算方式都相差不大,在下面的策略实现时,两种收益率计算方式都有使用。

双均线策略

1. 策略思想

均线:对每一个交易日,可以计算出前 N N N日股票收盘价的平均值,这个平均值叫做移动平均,将每一个交易日的前 N N N日移动平均值连在一起就构成了均线。

双均线:双均线的意思即为有两条这样的均线,一条是用前 N N N日收盘价计算所得,另一条使用前 M M M日收盘价计算所得。

金叉(Golden cross)和死叉(Death cross):时间短的均线在下方向上穿过时间长的均线,称为金叉,这时认为,股票强势,可以买入该股票。时间短的均线在上方向下穿过时间长的均线,称为死叉,这时股票弱势,应该卖出该股票。如下图所示,图中橘色的线为20日均线,黄色的线为45日均线。

在这里插入图片描述

思想:当 x x x天均线上升并且交叉穿过 y y y天的均线时股票多头;当 x x x天均线下降并且交叉穿过 y y y天的均线时股票空头。在A股市场,虽然有着融资融券业务的存在,但是目前想要做空股票,投资者就得从券商那里借入股票并卖出。通常情况下,投资者是不容易借入股票的。本文为了演示策略,引入了股票空头,读者请知悉。

2. 策略实现

使用老版tushare获取沪深300k线数据:

df = ts.get_k_data('hs300',start='2010-01-01',end='2021-07-02')
df = df[['date','close']]
df.set_index('date',inplace=True)

计算10日均线和60日均线:(当然10日和60日是参数,你可以调整为你想要的值)

df['SMA_10'] = df['close'].rolling(10).mean()
df['SMA_60'] = df['close'].rolling(60).mean()
df[['close','SMA_10','SMA_60']].plot(title='hs300 stock price and SMAs of 10 and 60 days',figsize=(10,6))

沪深300日线、10日均线和60日均线如下图所示:

在这里插入图片描述

建立头寸,1表示多头,-1表示空头,头寸如下图所示。

df['position'] = np.where(df['SMA_10']>df['SMA_60'],1,-1)
df.dropna(inplace=True)
df['position'].plot(ylim=[-1.1,1.1],title='market position')

在这里插入图片描述

计算沪深300的收益率以及双均线策略的收益率:使用的是连续型收益率

df['return'] = np.log(df['close']/df['close'].shift(1))
df['strategy'] = df['position'].shift(1) * df['return']
df[['return','strategy']].cumsum().apply(np.exp).plot(figsize=(10,6))

累计收益率如下图所示:

在这里插入图片描述

3. 策略评估

年化收益率:一年也就252个交易日

df[['return','strategy']].mean() * 252

result:return 0.03682 strategy 0.072253

也就是说如果你在2010-01-01买入沪深300并持有至2021-07-02,你的年化收益为3.6%,如果你使用双均线策略,你的年化收益为7.2%。当然,我们在这里并没有考虑到实盘时的手续费、滑点等。

年化风险

df[['return','strategy']].mean() * 252 ** 0.5

result:return 0.002320 strategy 0.004552

最大回撤:最大回撤表示的是累计收益从最大的点到之后最低点的距离,如下图所示。

df['cumreturn'] = df['strategy'].cumsum().apply(np.exp)
df['cummax'] = df['cumreturn'].cummax()
df[['cummax','cumreturn']].plot(figsize=(10,6))

drawdown = df['cummax'] - df['cumreturn']
drawdown.max()

累计最大收益和累计收益如下图所示:

在这里插入图片描述

最大回测为:1.5747052701854531

4. 策略优化

试想像:如果双均线频繁的交叉而导致频繁的买卖,会不会造成成本增加呢?

所以策略优化的思路就是基于此进行优化,即不要频繁的操作。即我们可以设置一个阈值 c c c:当一个均线穿过另一个均线并且大于阈值 c c c或者小于 − c -c c时,才开仓,否者平仓。

df['SMA_diff'] = df['SMA_10'] - df['SMA_60']
c = 20
df['position'] = np.where(df['SMA_diff'] > c,1,0)
df['position'] = np.where(df['SMA_diff'] < -c,-1,df['position'])
df.dropna(inplace=True)
df['return'] = np.log(df['close']/df['close'].shift(1))
df['strategy'] = df['position'].shift(1) * df['return']
df[['return','strategy']].cumsum().apply(np.exp).plot(figsize=(10,6))

累计收益如下图所示:(好像和没优化时没多大区别,但是在实盘时考虑到交易费用等时区别应当明显)

在这里插入图片描述

动量策略

1. 策略思想

动量效应:在一定时期内,如果某股票或者某股票投资组合在前一段时期表现较好(差),那么,在下一段时期该股票或股票投资组合仍然将有良好(较差)的表现。

思路

  • 当前一期收益率为正时,当期采取股票多头;当前一期收益率为负时,下一期采取股票空头。
  • 当前几期收益率的移动平均为正时,当期采取股票多头;当前几期收益率的移动平均为负时,当期采取股票空头。

2. 策略实现

df = ts.get_k_data('hs300',start='2010-01-01',end='2021-07-02')
df = df[['date','close']]
df.set_index('date',inplace=True)
df['return'] = np.log(df['close']/df['close'].shift(1))
df['position'] = np.sign(df['return'])
df['strategy'] = df['position'].shift(1) * df['return']
df.dropna(inplace=True)
df[['return','strategy']].cumsum().apply(np.exp).plot(figsize=(12,6))

累计收益如下图所示:

在这里插入图片描述

3. 策略优化

前面的策略实现过程中,当前一期收益率为正,采取股票多头,反之采取股票空头。但是我们可以用前面5期、10期、20期等的收益率平均值来作为建立头寸的依据。优化的思路即是参数寻优,一个简单的枚举法如下所示:

df2 = ts.get_k_data('hs300',start='2010-01-01',end='2021-07-02')
df2 = df2[['date','close']]
df2.set_index('date',inplace=True)
df2['return'] = df2['close'] / df2['close'].shift(1) - 1
df2['return_cum'] = (df2['return']+1).cumprod()
df2['position'] = np.sign(df2['return'])
df2['strategy'] = df2['position'].shift(1) * df2['return']
df2['strategy_cum'] = (df2['strategy']+1).cumprod()

table_title = ['return_cum']
for day in [5,10,20,30,60]:
    table_title.append('strategy_%dd_cum' % day)
    df2['position_%dd' % day] = np.sign(df2['return'].rolling(day).mean())
    df2['strategy_%dd' % day] = df2['position_%dd' % day].shift(1) * df2['return']
    df2['strategy_%dd_cum' % day] = (df2['strategy_%dd' % day] + 1).cumprod()
    
df2[table_title].dropna().plot(title='hs300 multi parameters momuntum strategy',figsize=(12,6),style=['--']*6)

各种参数的累计收益率如下图所示:

在这里插入图片描述

均值回归策略

1. 策略思想

均值回归是在价格震荡中寻求反弹的交易思路,即:涨上去的迟早要跌回来,跌下去的迟早要涨回来。均值回归策略应用了股市投资中经典的高抛低吸思想,该类型策略一般在震荡市中表现优异; 但是在单边趋势行情中一般表现糟糕,往往会大幅跑输市场。

distance:收盘价和均线的差值,如distance=close-SMA(50)

threshold:阈值,是对仓位调整的信号

思路

  • 当distance > threshold时,下一步做空;
  • 当distance < -threshold时,下一步做多;
  • 当连续两天的distance出现一正一负时,说明distance回归均值,平仓

2. 策略实现

df = ts.get_k_data('hs300',start='2010-01-01',end='2021-07-02')
df = df[['date','close']]
df.set_index('date',inplace=True)
df['return'] = np.log(df['close']/df['close'].shift(1))

SMA = 60
df['SMA'] = df['close'].rolling(SMA).mean()
df['distance'] = df['close'] - df['SMA']

threshold = 250  #阈值参数,可以调整
    
df.dropna(inplace=True)
df['distance'].plot(figsize=(10,6),legend=True)
plt.axhline(threshold,color='y')
plt.axhline(-threshold,color='y')
plt.axhline(0,color='y')

distance和阈值如下图所示:

在这里插入图片描述

下面建立股票头寸:

df['position'] = np.where(df['distance'] > threshold,-1,np.nan)
df['position'] = np.where(df['distance'] < - threshold,1,df['position'])
df['position'] = np.where(df['distance']*df['distance'].shift(1)<0,0,df['position'])
df['position'] = df['position'].ffill().fillna(0)
df['position'].plot(figsize=(10,6))

头寸如下图所示:

在这里插入图片描述

计算收益并可视化:

df['strategy'] = df['position'].shift(1) * df['return']
df[['return','strategy']].cumsum().apply(np.exp).plot(figsize=(10,6))

累计收益如下图所示:

在这里插入图片描述

可以发现,在14-15年那波大牛市中,均值回测策略表现糟糕,大幅跑输市场。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐