文章目录
一、计算布林带三、构建策略,计算持仓头寸序列和买卖信号序列四、计算策略收益五、绘制交易信号布林带(BOLL)指标是美国股市分析家约翰·布林根据统计学中的标准差原理设计出来的一种非常简单实用的技术分析指标。一般而言,股价的运动总是围绕某一价值中枢(如均线、成本线等)在一定的范围内变动,布林线指标正是在上述条件的基础上,引进了“股价通道”的概念,其认为股价通道的宽窄随着股价波动幅度的大小而变化,而且股价通道又具有变异性,它会随着股价的变化而自动调整。
一、计算布林带
首先我们导入相关库。
import pandas as pdimport numpy as npfrom matplotlib import pyplot as plt
接下来编写一个函数来计算我们的布林带。
中轨:股价的平均成本,N时间段的简单移动平均上轨:压力线,上轨 = 中轨 + K × N时间段的标准差下轨:支撑线,下轨 = 中轨 − K × N时间段的标准差
def calculate_bollinger_bands(df, window = 20, no_of_std = 2, column_name = ''):'''Parameters----------df : 股价数据集window : 计算的周期,默认20天no_of_std : 标准偏差的倍数,默认2column_name : 股价数据集选择的列名,默认为第一列'''if column_name == '':column_name = df.columns[0] df['Observation']=df[column_name]df['RollingMean'] = df[column_name].rolling(window).mean()std = df[column_name].rolling(window).std(ddof=0) df['UpperBound'] = df['RollingMean'] + no_of_std * stddf['LowerBound'] = df['RollingMean'] - no_of_std * stdbb = df[['Observation','RollingMean','UpperBound','LowerBound']]bb.plot(title='Observation with Bollinger Bands') #绘制布林带return df
我们以SPY数据为例,csv文件地址如下:链接:/s/1uqX_F07q28SaYMtosque3w ,提取码:vwi2。
我们读取SPY价格数据。
df = pd.read_csv(r'C:\Users\mi\Desktop\SPY.csv') df = df.set_index('Date')
数据如下:
>>>dfOpen High ... Adj Close VolumeDate ... -08-10 442.609985 443.440002 ... 436.474243 43339300-08-11 443.820007 443.880005 ... 437.558807 44034300-08-12 443.619995 445.260010 ... 438.870117 38909400-08-13 445.589996 445.940002 ... 439.668823 39470300-08-16 444.529999 447.109985 ... 440.704102 73740000... ... ... ... ...-08-04 414.369995 415.089996 ... 414.170013 45656600-08-05 409.660004 414.149994 ... 413.470001 56755600-08-08 415.250000 417.619995 ... 412.989990 53886100-08-09 412.220001 412.750000 ... 411.350006 44840500-08-10 418.779999 420.040009 ... 419.276886 30838744[253 rows x 6 columns]
我们以SPY数据为例,计算其布林带。
df = calculate_bollinger_bands(df, 10, 2, 'Adj Close') #计算布林带
数据如下:
>>>dfOpen High ... UpperBound LowerBoundDate ... -08-10 442.609985 443.440002 ... NaN NaN-08-11 443.820007 443.880005 ... NaN NaN-08-12 443.619995 445.260010 ... NaN NaN-08-13 445.589996 445.940002 ... NaN NaN-08-16 444.529999 447.109985 ... NaN NaN... ... ... ... ...-08-04 414.369995 415.089996 ... 421.151341 388.468666-08-05 409.660004 414.149994 ... 422.323881 390.972127-08-08 415.250000 417.619995 ... 422.553138 394.226867-08-09 412.220001 412.750000 ... 418.489248 402.382755-08-10 418.779999 420.040009 ... 419.151863 405.367516[253 rows x 10 columns]
绘制的布林带图形如下:
三、构建策略,计算持仓头寸序列和买卖信号序列
策略的关键是得到持仓头寸序列和买卖信号序列。
布林带策略有多种。
(1)均值回归策略
布林线均值回归策略认为,标的价格在上轨线和下轨线围成的范围内浮动,即使短期内突破上下轨,但长期内仍然会回归到布林带之中。因此,一旦突破上下轨,即形成买卖信号。
我们可构建策略1:
当股价由下向上穿过上轨的时候,做空;然后由上向下穿过中轨的时候,平仓。
当股价由上向下穿过下轨的时候,做多;然后由下向上穿过中轨的时候,平仓。
def calculate_strategy1_position(df): '''策略1:均值回归策略当收盘价由下向上穿过上轨的时候,做空;然后由上向下穿过中轨的时候,平仓。当收盘价由上向下穿过下轨的时候,做多;然后由下向上穿过中轨的时候,平仓。''' xs = (df.Observation - df.RollingMean) / (df.Observation.shift(1) - df.RollingMean.shift(1))df['position'] = np.nan df['position'] = np.where(df.Observation<df.LowerBound, 1,df['position']) df['position'] = np.where(df.Observation>df.UpperBound ,-1,df['position']) df['position'] = np.where(xs<0, 0, df['position'])df['position'] = df['position'].ffill().fillna(0) #买入开仓long_entry_condition = (df['position']==1) & (df['position'].shift(1)!=1)df.loc[long_entry_condition,'signal_long'] = 1#卖出平仓long_exit_condition = (df['position']!=1) &(df['position'].shift(1)==1)df.loc[long_exit_condition,'signal_long'] = 0#卖出开仓short_entry_condition = (df['position']==-1) & (df['position'].shift(1)!=-1)df.loc[short_entry_condition,'signal_short'] = -1#买入平仓short_exit_condition = (df['position']!=-1) & (df['position'].shift(1)==-1)df.loc[short_exit_condition,'signal_short'] = 0return df
(2)趋势性交易策略
布林线趋势性交易策略略认为,标的价格在上轨线和下轨线围成的范围内浮动,如果突破上轨,通常认为产生上涨趋势,做多;如果突破下轨,通常认为产生下跌趋势,做空。因此,一旦突破上下轨,即形成买卖信号。
我们可构建策略2:
当股价由下向上穿过上轨的时候,做多;然后由上向下穿过上轨的时候,平仓。
当股价由上向下穿过下轨的时候,做空;然后由下向上穿过下轨的时候,平仓。
策略3:
当股价由下向上穿过上轨的时候,做多;然后由上向下穿过中轨的时候,平仓。
当股价由上向下穿过下轨的时候,做空;然后由下向上穿过中轨的时候,平仓。
def calculate_strategy2_position(df): '''-------策略2:当收盘价由下向上穿过上轨的时候,做多;然后由上向下穿过上轨的时候,平仓。当收盘价由上向下穿过下轨的时候,做空;然后由下向上穿过下轨的时候,平仓。'''#position : 持仓头寸,多仓为1,不持仓为0,空仓为-1#siganal : 交易信号,做多为1,平仓为0,做空为-1df['position'] = np.where(df.Observation > df.UpperBound, 1, 0) df['position'] = np.where(df.Observation < df.LowerBound, -1, df['position']) #买入开仓long_entry_condition = (df['position']==1) & (df['position'].shift(1)!=1)df.loc[long_entry_condition,'signal_long'] = 1#卖出平仓long_exit_condition = (df['position']!=1) &(df['position'].shift(1)==1)df.loc[long_exit_condition,'signal_long'] = 0#卖出开仓short_entry_condition = (df['position']==-1) & (df['position'].shift(1)!=-1)df.loc[short_entry_condition,'signal_short'] = -1#买入平仓short_exit_condition = (df['position']!=-1) & (df['position'].shift(1)==-1)df.loc[short_exit_condition,'signal_short'] = 0return dfdef calculate_strategy3_position(df): '''策略3:当收盘价由下向上穿过上轨的时候,做多;然后由上向下穿过中轨的时候,平仓。当收盘价由上向下穿过下轨的时候,做空;然后由下向上穿过中轨的时候,平仓。''' xs = (df.Observation - df.RollingMean) / (df.Observation.shift(1) - df.RollingMean.shift(1))df['position'] = np.nan df['position'] = np.where(df.Observation>df.UpperBound, 1,df['position']) #做多 df['position'] = np.where(df.Observation<df.LowerBound ,-1,df['position']) #做空 df['position'] = np.where(xs<0, 0, df['position']) #平仓df['position'] = df['position'].ffill().fillna(0) #买入开仓long_entry_condition = (df['position']==1) & (df['position'].shift(1)!=1)df.loc[long_entry_condition,'signal_long'] = 1#卖出平仓long_exit_condition = (df['position']!=1) &(df['position'].shift(1)==1)df.loc[long_exit_condition,'signal_long'] = 0#卖出开仓short_entry_condition = (df['position']==-1) & (df['position'].shift(1)!=-1)df.loc[short_entry_condition,'signal_short'] = -1#买入平仓short_exit_condition = (df['position']!=-1) & (df['position'].shift(1)==-1)df.loc[short_exit_condition,'signal_short'] = 0return df
四、计算策略收益
我们可编制函数,计算市场收益率、策略收益率及策略超常收益率。注意我们的买卖信号出现后,第二天才能进行交易。
def calculate_returns(df):# 计算市场对数收益率、策略对数收益率、策略超常收益率df['market_log_returns'] = np.log(df['Observation']/df['Observation'].shift(1))df['strat_log_returns'] = df['position'].shift(1)* df['market_log_returns'] #交易信号出现后第二天交易df['abnormal_returns'] = df['strat_log_returns'] - df['market_log_returns']# 计算市场累积收益率、策略累积收益率、策略累积超常收益率df['market_cum_returns'] = np.exp(df['market_log_returns'].cumsum()) - 1df['strat_cum_returns'] = np.exp(df['strat_log_returns'].cumsum()) - 1df['abnormal_cum_returns'] = df['strat_cum_returns'] - df['market_cum_returns']# 绘图ret = df[['market_log_returns','strat_log_returns','abnormal_returns']]ret.plot(title='Market,Strategy,and Abnormal Returns')cum_returns = df[['market_cum_returns','strat_cum_returns','abnormal_cum_returns']]cum_returns.plot(title='Cumulative Returns')return df
五、绘制交易信号
我们可编制函数,将买卖信号标注在布林带中。
def plot_bands_with_signal(df):# 绘制交易图表#买入开仓long_entry = df.loc[df['signal_long']==1]['Observation']#卖出平仓long_exit = df.loc[df['signal_long']==0]['Observation']#卖出开仓short_entry = df.loc[df['signal_short']==-1]['Observation']#卖出平仓short_exit = df.loc[df['signal_short']==0]['Observation']fig, ax = plt.subplots(1, figsize=(15, 10), sharex=True) ax.plot(df['Observation'], label='Observation')ax.plot(df['RollingMean'], label='RollingMean')ax.plot(df['UpperBound'])ax.plot(df['LowerBound'])ax.fill_between(df.index, df['UpperBound'], df['LowerBound'],alpha=0.3, label='Bollinger Band')ax.scatter(long_entry.index, long_entry, color='r', s=100, marker='^', label='Long Entry',zorder=10)ax.scatter(long_exit.index, long_exit, color='r',s=100, marker='x', label='Long Exit',zorder=10)ax.scatter(short_entry.index, short_entry, color='b', s=100, marker='^', label='Short Entry',zorder=10)ax.scatter(short_exit.index, short_exit, color='b',s=100, marker='x', label='Short Exit',zorder=10)ax.set_title('Bollinger Band Strategy Trading Signals')ax.legend()plt.show()
我们以SPY数据为例,调用上述函数。
df = pd.read_csv(r'C:\Users\mi\Desktop\SPY.csv') df = df.set_index('Date')df = calculate_bollinger_bands(df, 10, 2, 'Adj Close') #计算布林带# 策略1df1 = calculate_strategy1_position(df.copy()) df1 = calculate_returns(df1)plot_bands_with_signal(df1)# 策略2df2 = calculate_strategy2_position(df.copy()) df2 = calculate_returns(df2)plot_bands_with_signal(df2)# 策略3df3 = calculate_strategy3_position(df.copy()) df3 = calculate_returns(df3)plot_bands_with_signal(df3)
可得到策略1的收益率、累积收益率、交易信号如下图所示:
可得到策略2的收益率、累积收益率、交易信号如下图所示:
可得到策略3的收益率、累积收益率、交易信号如下图所示:
欢迎关注:
Python for Finance微信公众号
如果觉得《【Python量化】布林带策略》对你有帮助,请点赞、收藏,并留下你的观点哦!