开源量化框架Catalyst中文教程(4)——布林带策略

mac2024-05-18  37

GitHub:https://github.com/enigmampc/catalyst 官方文档:https://enigma.co/catalyst/index.html 系统环境:macOS High Sierra 10.13.6

官方没有布林带策略的示例文件,不过我们很容易自己实现。 首先安装开源技术指标库TA-Lib,在Catalyst环境下

pip install TA-Lib

一. 布林带

布林带由三条线构成,分别是上轨(Upper),中轨(Middle,即均线),下轨(Lower) 布林线中轨:n天收盘价的移动平均线 布林线上轨:n天收盘价的移动平均线 + (m x n天收盘价的标准差) 布林线下轨:n天收盘价的移动平均线 - (m x n天收盘价的标准差) 其中m称为标准差,是整数,因此布林带的参数是[n, m]。 用TA-Lib很容易得到这三条线:

upper, middle, lower = talib.BBANDS(history_data, timeperiod=BOLL_N, nbdevdn=BOLL_M, nbdevup=BOLL_M)

其中history_data是历史收盘价dataframe,timeperiod是统计周期n天,nbdevdn和nbdevup就是上下轨要乘的标准差m。

二. 策略逻辑

布林带的策略逻辑有很多,为了简单起见,这里仅做如下示例:

K线上穿下轨,买入K线下穿上轨,卖出

你也可以尝试其它做法比如:

当收盘价由下向上穿过上轨的时候,做多;然后由上向下穿过中轨的时候,平仓。当收盘价由上向下穿过下轨的时候,做空;然后由下向上穿过中轨的时候,平仓。

三. 代码实现

1. 常数设置和程序初始化

NAMESPACE = 'bollinger_bands' log = Logger(NAMESPACE) SIGNAL_BUY = 'buy' # 买入信号 SIGNAL_SELL = 'sell' # 卖出信号 SIGNAL_INIT = '' # 观望信号 BOLL_N = 20 # bbands参数n BOLL_M = 2 # bbands参数m def initialize(context): """ 初始化 """ context.i = 0 # 经历过的交易周期 context.asset = symbol('bab_usd') # 交易对 context.base_price = None # 初始价格 context.signal = SIGNAL_INIT # 交易信号

2. 策略实现

def handle_data(context, data): """ 策略 """ # 经历过的交易周期大于周期窗口才开始计算 context.i += 1 if context.i < BOLL_N + 1: return # 获取历史数据,返回dataframe history_data = data.history(context.asset, 'close', bar_count=BOLL_N + 1, frequency="1D", ) # 获取当前持仓数量 pos_amount = context.portfolio.positions[context.asset].amount # 计算BBands upper, middle, lower = talib.BBANDS(history_data, timeperiod=BOLL_N, nbdevdn=BOLL_M, nbdevup=BOLL_M) # 策略逻辑 # K线上穿下轨,买入 if (history_data[-2] <= lower[-2]) and (history_data[-1] > lower[-1]) and pos_amount == 0: # target买入百分比,1代表买入100%,0.5代表买入50%,0代表卖出 order_target_percent(asset=context.asset, target=1) # 设置交易信号为买入 context.signal = SIGNAL_BUY # K线下穿上轨,卖出 if (history_data[-2] >= upper[-2]) and (history_data[-1] < upper[-1]) and pos_amount > 0: # target买入百分比,1代表买入100%,0.5代表买入50%,0代表卖出 order_target_percent(asset=context.asset, target=0) # 设置交易信号为卖出 context.signal = SIGNAL_SELL # 获取当前价格 price = data.current(context.asset, 'price') # 如果初始价格没设置,把当前的价格设置为初始价格 if context.base_price is None: context.base_price = price # 计算价格变化百分比,作为基准 price_change = (price - context.base_price) / context.base_price # 记录每个交易周期的信息 record(price=price, # 价格 cash=context.portfolio.cash, # 现金 price_change=price_change, # 价格变化率 upper=upper[-1], # 上轨 middle=middle, #中轨 lower=lower[-1], # 下轨 signal=context.signal) # 交易信号 # 输出信息 print('日期:{}, 价格:{:.4f}, 资产:{:.2f}, 持仓量:{:.8f}, {}'.format( data.current_dt, price, context.portfolio.portfolio_value, pos_amount, context.signal )) # 重置交易信号 context.signal = SIGNAL_INIT

3. 策略分析和可视化

这部分与双均线策略是一样的,只是图2的变量名做了修改

def analyze(context, perf): # 保存交易记录 perf.to_csv('performance.csv') # 获取计价货币(USDT) exchange = list(context.exchanges.values())[0] quote_currency = exchange.quote_currency.upper() # 图1:输出资产值 ax1 = plt.subplot(411) perf.loc[:, ['portfolio_value']].plot(ax=ax1) # ax1.legend_.remove() # 设置y轴 ax1.set_ylabel('Portfolio Value\n({})'.format(quote_currency)) # 设置区间 start, end = ax1.get_ylim() # 设置刻度 ax1.yaxis.set_ticks(np.arange(start, end, (end - start) / 5)) # 图2:输出资产货币价格、布林带和买卖点 ax2 = plt.subplot(412, sharex=ax1) perf.loc[:, ['price', 'upper', 'middle', 'lower']].plot(ax=ax2) # ax2.legend_.remove() ax2.set_ylabel('{asset}\n({quote})'.format( asset=context.asset.symbol, quote=quote_currency )) start, end = ax2.get_ylim() ax2.yaxis.set_ticks(np.arange(start, end, (end - start) / 5)) # 提取交易时间点 transaction_df = extract_transactions(perf) # 交易dataframe if not transaction_df.empty: buy_df = transaction_df[transaction_df['amount'] > 0] # 取到amount>0,买入点 sell_df = transaction_df[transaction_df['amount'] < 0] # 取到amount<0,卖出点 ax2.scatter( buy_df.index.to_pydatetime(), perf.loc[buy_df.index, 'price'], # 找到index marker='^', s=100, c='green', label='' ) ax2.scatter( sell_df.index.to_pydatetime(), perf.loc[sell_df.index, 'price'], marker='v', s=100, c='red', label='' ) # 图3:比较价格变化率和资产变化率(即比较策略收益率和基准收益率) ax3 = plt.subplot(413, sharex=ax1) perf.loc[:, ['algorithm_period_return', 'price_change']].plot(ax=ax3) # ax3.legend_.remove() ax3.set_ylabel('Percent Change') start, end = ax3.get_ylim() ax3.yaxis.set_ticks(np.arange(start, end, (end - start) / 5)) # 图4:现金数量 ax4 = plt.subplot(414, sharex=ax1) perf.cash.plot(ax=ax4) ax4.set_ylabel('Cash\n({})'.format(quote_currency)) start, end = ax4.get_ylim() ax4.yaxis.set_ticks(np.arange(0, end, end / 5)) plt.show()

4. 主函数

if __name__ == '__main__': # run_algorithm返回的是dataframe perf = run_algorithm( capital_base=1000, data_frequency='daily', initialize=initialize, handle_data=handle_data, analyze=analyze(), exchange_name='bitfinex', algo_namespace=NAMESPACE, quote_currency='usd', start=pd.to_datetime('2018-11-13', utc=True), end=pd.to_datetime('2019-10-16', utc=True) )

5. 输出图像

第一个图是持有BCH资产的价值走势 第二个图中绿色三角形代表买入点,红色三角形代表卖出点 第三个图是策略收益与基准收益的对比 第四个图是现金变动情况

最新回复(0)