df=pd.read_csv(src_dir+'SH#600036.txt',sep='\t',parse_dates=True,skiprows=1,skipfooter=1,encoding='gbk',engine='python')
df.columns=['date','open','high','low','close','volume','amount']
df['date']=pd.to_datetime(df["date"])
df.set_index('date',inplace=True)
df.head()
数据显示如下图所示,后续我们选取2020年后的数据来进行交易策略的回测。
有了股票的交易数据后接下来就是技术指标的计算了,这里以布林线指标为例进行说明。布林指标实际就是移动平均线加/减2个标准差。因此首先使用前面Python金融数据分析系列1中计算简单移动平均的方法写一个sma函数来进行简单移动平均的计算,代码如下:
df['sma_20'] = sma(df['close'], 20)
df.tail()
现在我们已经有了20日均线数据,接下来再加上一个上轨和下轨,同样的写一个函数bb来完成布林上下轨计算,代码如下:
df['upper_bb'], df['lower_bb'] = bb(df['close'], df['sma_20'], 20)
df.tail()
通过上述代码我们得到的数据如下图所示:
进一步将该数据可视化如下所示:
完成了数据准备,技术指标的计算,下一步就是根据交易规则产生交易信号。本例中的交易规则很简单:
股价下穿布林下轨后买入
股价上穿布林上轨后卖出
基于该规则,编写布林轨道交易函数bb_strategy如下:
def 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 = bb_strategy(df['close'], df['lower_bb'], df['upper_bb'])
这段代码虽然有点多,但是基本思路却非常简单,如果股价下穿布林下轨后由于需要买入,因此代码需要将买入价格记录下来(buy_price),同时将signal标记为1,反之则记录卖出价格sell_price,同时将signal标记为-1。之后将以上信息分别记录到3个列表buy_price,sell_price,bb_signal中。具体买入,卖出信号可视化如下图所示:
有了交易信号之后,下一步就是根据交易信号记录当前的仓位信息,具体代码如下:
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(df['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 = df['upper_bb']
lower_bb = df['lower_bb']
close_price = df['close']
bb_signal = pd.DataFrame(bb_signal).rename(columns = {0:'bb_signal'}).set_index(df.index)
position = pd.DataFrame(position).rename(columns = {0:'bb_position'}).set_index(df.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)
上述代码仓位信息记录在了position这一列表中,之后将仓位,信号等数据都合并保存在strategy这个DataFrame。有了上述信息,我们就可以开始计算策略收益,具体代码如下:
df_ret = pd.DataFrame(np.diff(df['close'])).rename(columns = {0:'returns'})
bb_strategy_ret = []
for i in range(len(df_ret)):
try:
returns = df_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/df['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('策略收益: {}'.format(total_investment_ret), attrs = ['bold']))
print(cl('策略收益率:{}%'.format(profit_percentage), attrs = ['bold']))
其中代码math.floor(investment_value/df['close'][-1])完成了买入数量计算,当然这里没有按照100股来进行计算,如果需要你只需要简单的取整就可以了。具体的收益计算主要由这一段代码完成:
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)
利用以上代码作为框架你就可以快速完成各种交易想法的验证,基于多个指标的交易策略无非就是多几次计算而已。