使用Python实现布林带的算法交易
使用Python实现布林带的算法交易
大家好,我是Lucy@FinTech社区,今天的文章将和大家分享算法交易与深度学习。欢迎添加以下微信:fintech78,加入社群,提认知,攒人脉,求职招聘!
什么是算法交易?算法交易是使计算机能够在特定条件或规则下交易股票的过程。当给定条件得到满足时,计算机将自动执行交易(这里条件是交易者给计算机编写得交易策略)。
布林带
在开始学习布林带之前,有必要知道什么是简单移动平均线(SMA)。简单移动平均线是给定时间段内股票的平均价格。而布林带指标是在特定标准差得水平下,在给定股票的SMA上方和下方绘制的趋势线。为了能更好地理解布林带,下面的图表用SMA 20计算特斯拉股票的布林带。
布林带非常适合观察给定股票一段时间内的波动性。当上下波动带之间的空间或距离较小时,可以观察到股票的波动性较低。类似地,当上下限之间的距离或空间越大,股票的波动性就越高。在观察图表时,你可以观察到一条“MIDDLE BB 20”的趋势线,它是特斯拉股票的SMA 20。计算股票上下限的公式如下:
UPPER_BB = STOCK SMA + SMA STANDARD DEVIATION * 2
LOWER_BB = STOCK SMA - SMA STANDARD DEVIATION * 2
到这里我们已经了解了什么是布林带,接下来让我们进一步探索怎样用布林带构建的交易策略。
关于交易策略:
我们将使用布林带指数实现基本得交易策略,如果前一天的股价高于前一天的最低值,且当前股价低于当天的最低值,将发出买入信号。同样,如果前一天的股价低于前一天的最高值,而当前股价高于当天的最高值,则策略将发出卖出信号。这样我们的布林带交易策略可以表示为:
IF PREV_STOCK > PREV_LOWERBB & CUR_STOCK < CUR_LOWER_BB => BUY
IF PREV_STOCK < PREV_UPPERBB & CUR_STOCK > CUR_UPPER_BB => SELL
前面我们已经了解了如何建立布林带交易策略。接下来让我们用python来实现它!
用Python实现
现在我们将使用Python实现前面讨论得布林带交易策略,并且看看它在现实交易的效果如何。
导入包
在编写交易策略之前,必须将所需的包导入到我们的python环境中。主要得程序包有Pandas、Matplotlib和NumPy。其它得还有math、requests和字体定制的Termcolor。
import pandas as pd
import matplotlib.pyplot as plt
import requests
import math
from termcolor import colored as cl
import numpy as np
plt.style.use('fivethirtyeight')plt.rcParams['figure.figsize'] = (20, 10)
从IEX cloud提取数据
在这一步,我们将使用IEX Cloud提供的API获取特斯拉的历史数据:
def get_historic_data(symbol):
ticker = symbol
iex_api_key='Tsk_30a2677082d54c7b8697675d 84baf94b'
api_url=f'https://sandbox.iexapis.com/stable/sto ck/{ticker}/chart/max?token={iex_api_key}'
df = requests.get(api_url).json( )
date = [ ]
open = [ ]
high = [ ]
low = [ ]
close = [ ]
for i in range(len(df)):
date.append(df[i]['date'])
open.append(df[i]['open'])
high.append(df[i]['high'])
low.append(df[i]['low'])
close.append(df[i]['close'])
date_df=pd.DataFrame(date).rename(columns = {0:'date'})
open_df=pd.DataFrame(open).rename(columns= {0:'open'})
high_df=pd.DataFrame(high).rename(columns = {0:'high'})
low_df = pd.DataFrame(low).rename(columns = {0:'low'})
close_df=pd.DataFrame(close).rename(columns = {0:'close'})
frames = [date_df, open_df, high_df, low_df, close_df]
df = pd.concat(frames, axis = 1, join = 'inner') return df
tsla = get_historic_data('TSLA')
tsla = tsla.set_index('date')
tsla=tsla[tsla.index>='2020-01-01']tsla.to_csv('tsla.csv')
tsla=pd.read_csv('tsla.csv').set_index('date')tsla.index = pd.to_datetime(tsla.index)
tsla.tail()
执行后得输出
计算布林带
这一步分为两部分。1)计算SMA值;2)是计算布林带。
1)计算SMA值:在这一部分中,我们将计算特斯拉的SMA值,周期数为20。
def sma(data, window):
sma = data.rolling(window = window).mean()
return sma
tsla['sma_20'] = sma(tsla['close'], 20)tsla.tail()
执行后的输出
2)计算布林带:我们将使用我们之前创建的SMA值计算特斯拉的布林带值。
def bb(data, sma, window):
std = data.rolling(window = window).std(
upper_bb = sma + std * 2
lower_bb = sma - std * 2
return upper_bb, lower_bb
tsla['upper_bb'], tsla['lower_bb'] = bb(tsla['close'], tsla['sma_20'], 20)
tsla.tail()
执行后的输出
这里对算法做一下简单介绍:首先,我们定义了一个名为“bb”的函数,它将股票价格(data)、SMA值(sma)和周期数作为参数(windows)。在函数内,我们使用“rolling”和“std”函数计算给定数据的标准差,并将计算出的标准偏差值存储到std中。接下来,我们使用各自的公式计算布林带值,最后,我们返回计算值。我们使用创建的“bb”函数将布林带值存储到“tsla”变量中。
绘制布林带
在这一步我们将绘制计算出的布林带,通过可视化,使其更有意义。
tsla['close'].plot(label = 'CLOSE PRICES', color = 'skyblue')
tsla['upper_bb'].plot(label = 'UPPER BB 20', linestyle = '--', linewidth = 1, color = 'black')
tsla['sma_20'].plot(label = 'MIDDLE BB 20', linestyle = '--', linewidth = 1.2, color = 'grey')
tsla['lower_bb'].plot(label = 'LOWER BB 20', linestyle = '--', linewidth = 1, color = 'black')
plt.legend(loc = 'upper left')
plt.title('TSLA BOLLINGER BANDS')
plt.show()
输出
制定交易策略
这里我们将用python实现所讨论的布林带交易策略。
def implement_bb_strategy(data, lower_bb, upper_bb):
buy_price = [ ]
sell_price = [ ]
bb_signal = [ ]
signal = 0
for i in range(len(data)):
if data[i-1] > lower_bb[i-1] and data[i] < lower_bb[i]:
if signal != 1:
buy_price.append(data[i])
sell_price.append(np.nan)
signal = 1
bb_signal.append(signal)
else:
buy_price.append(np.nan)
sell_price.append(np.nan)
bb_signal.append(0)
elif data[i-1] < upper_bb[i-1] and data[i] > upper_bb[i]:
if signal != -1: buy_price.append(np.nan)
sell_price.append(data[i])
signal = -1
bb_signal.append(signal)
else:
buy_price.append(np.nan)
sell_price.append(np.nan)
bb_signal.append(0)
else:
buy_price.append(np.nan)
sell_price.append(np.nan)
bb_signal.append(0)
return buy_price, sell_price, bb_signal
buy_price, sell_price, bb_signal = implement_bb_strategy(tsla['close'], tsla['lower_bb'], tsla['upper_bb'])
绘制交易列表
在这一步中,我们将绘制创建的交易列表,通过可视化效果,以使其具有意义。
tsla['close'].plot(label = 'CLOSE PRICES', alpha = 0.3)
tsla['upper_bb'].plot(label = 'UPPER BB', linestyle = '--', linewidth = 1, color = 'black')
tsla['middle_bb'].plot(label = 'MIDDLE BB', linestyle = '--', linewidth = 1.2, color = 'grey')tsla['lower_bb'].plot(label = 'LOWER BB', linestyle = '--', linewidth = 1, color = 'black')plt.scatter(tsla.index, buy_price, marker = '^', color = 'green', label = 'BUY', s = 200)plt.scatter(tsla.index, sell_price, marker = 'v', color = 'red', label = 'SELL', s = 200)
plt.title('TSLA BB STRATEGY TRADING SIGNALS')
plt.legend(loc = 'upper left')
plt.show()
输出
判断交易状况
在这一步中,我们将创建一个列表,如果我们持有该股票显示1,如果我们不持有该股票显示0。
position = []
for i in range(len(bb_signal)):
if bb_signal[i] > 1:
position.append(0)
else:
position.append(1)
for i in range(len(tsla['close'])):
if bb_signal[i] == 1:
position[i] = 1
elif bb_signal[i] == -1:
position[i] = 0
else:
position[i] = position[i-1]
upper_bb = tsla['upper_bb']
lower_bb = tsla['lower_bb']
close_price = tsla['close']
bb_signal=pd.DataFrame(bb_signal).rename(columns = {0:'bb_signal'}).set_index(tsla.index)position=pd.DataFrame(position).rename(columns = {0:'bb_position'}).set_index(tsla.index)
frames = [close_price, upper_bb, lower_bb, bb_signal, position]
strategy = pd.concat(frames, join = 'inner', axis = 1)
strategy = strategy.reset_index().drop('date', axis = 1) 0
strategy
回测
在继续下一步之前,了解什么是回测是很重要的。回测是观察我们的交易策略在给定股票历史数据上的表现如何的过程。在我们的例子中,我们将对特斯拉股票数据的布林带交易策略进行回测过程。
tsla_ret=pd.DataFrame(np.diff(tsla['close'])).rename(columns = {0:'returns'})
bb_strategy_ret = [ ]
for i in range(len(tsla_ret)):
try :
returns = tsla_ret['returns'][i]*strategy['bb_position'][i] bb_strategy_ret.append(returns)
except:
pass
bb_strategy_ret_df = pd.DataFrame(bb_strategy_ret).rename(columns = {0:'bb_returns'})
investment_value = 100000
number_of_stocks=math.floor(investment_value/tsla['close'][-1])
bb_investment_ret = [ ]
for i in range(len(bb_strategy_ret_df['bb_returns'])):
returns=number_of_stocks*bb_strategy_ret_df['bb_returns'][i]
bb_investment_ret.append(returns)
bb_investment_ret_df=pd.DataFrame(bb_investment_ret).rename(columns = {0:'investment_returns'})
total_investment_ret=round(sum(bb_investment_ret_df['investment_returns']), 2)
profit_percentage=math.floor((total_investment_ret/investment_value)*100)
print(cl('Profit gained from the BB strategy by investing $100k in TSLA :{}'.format(total_investment_ret), attrs = ['bold']))print(cl('Profit percentage of the BB strategy : {}%'.format(profit_percentage), attrs = ['bold']))
Profit gained from the BB strategy by investing $100k in TSLA : 18426.42
Profit percentage of the BB strategy : 18%
对比SPY ETF
这一步虽然不是必须的,但强烈建议您也跟着做一下,因为我们可以了解我们的交易策略相对于基准(SPY ETF)的表现。
在这一步中,我们将使用我们创建的“get_Historical_data”函数提取SPY ETF的数据,并将我们从SPY ETF获得的回报与特斯拉的布林带策略回报进行比较。
def get_benchmark(stock_prices, start_date, investment_value):
spy = get_historic_data('SPY')
spy = spy.set_index('date')
spy = spy[spy.index >= start_date]['close']
benchmark= pd.DataFrame(np.diff(spy)).rename(columns = {0:'benchmark_returns'})
investment_value = investment_value
number_of_stocks =math.floor(investment_value/stock_prices[-1]) benchmark_investment_ret = []
for i in range(len(benchmark['benchmark_returns'])):
returns = number_of_stocks*benchmark['benchmark_returns'][i] benchmark_investment_ret.append(returns)
benchmark_investment_ret_df = pd.DataFrame(benchmark_investment_ret).rename(columns = {0:'investment_returns'})
return benchmark_investment_ret_df
benchmark = get_benchmark(tsla['close'], '2020-01-01', 100000)
investment_value = 100000
total_benchmark_investment_ret = round(sum(benchmark['investment_returns']), 2)
benchmark_profit_percentage = math.floor((total_benchmark_investment_ret/investment_value)*100)
print(cl('Benchmark profit by investing $100k : {}'.format(total_benchmark_investment_ret), attrs = ['bold']))
print(cl('Benchmark Profit percentage : {}%'.format(benchmark_profit_percentage), attrs = ['bold']))
print(cl('BB Strategy profit is {}% higher than the Benchmark Profit'.format(profit_percentage - benchmark_profit_percentage), attrs = ['bold']))
输出:
Benchmark profit by investing $100k : 13270.5
Benchmark Profit percentage : 13%
BB Strategy profit is 5% higher than the BenchmarkProfit
结论
我们在本文中实现的交易策略是一个基本的策略,但是有很多基于布林带的交易策略需要应用。人们认为,布林带不太适合算法交易,但如果采用正确的交易策略,布林带是有效的。还有几种改进本文的方法:
选股:在本文中,我们随机选择了特斯拉,但在现实世界中,这不是一个明智的决定。相反,机器学习算法可以用来挑选合适的可交易股票。这一步在现实算法交易中非常重要,如果随机选择股票,结果将是灾难性的。
策略改进:正如前面所说,我们在本文中使用的交易策略是一种初级策略,在现实世界中应用时不会表现很耀眼。因此,强烈建议发现更多的布林带策略并用python中实现它们。
关注fintech社区,我们将陪伴你一起探索区块链的更多机会!