GitHub:https://github.com/enigmampc/catalyst 官方文档:https://enigma.co/catalyst/index.html 系统环境:macOS High Sierra 10.13.6
官方没有RSI策略的示例文件,我们很容易通过TA-Lib实现。
举个栗子(详见百度https://baike.baidu.com/item/RSI/6130115?fr=aladdin):
如果最近14天涨跌情形是:第一天升2元,第二天跌2元,第三至第五天各升3元;第六天跌4元 第七天升2元,第八天跌5元;第九天跌6元,第十至十二天各升1元;第十三至十四天各跌3元。
那么,计算RSI的步骤如下: (一)将14天上升的数目相加,除以14,上例中总共上升16元除以14得1.143(精确到小数点后三位); (二)将14天下跌的数目相加,除以14,上例中总共下跌23元除以14得1.643(精确到小数点后三位); (三)求出相对强度RS,即RS=1.143/1.643=0.696(精确到小数点后三位); (四)1+RS=1+0.696=1.696; RS/(1+RS)=0.696/(1+0.696)=0.41038 (五)RSI=100*0.41028=41.038. 结果14天的强弱指标RS1为41.038。 不同日期的14天RSI值当然是不同的,连接不同的点,即成RSI的轨迹。 RSI的变动范围在0—100之间,一般来说,RSI>70是超买状态,可以做空;RSI<30是超卖状态,可以做多。
用TA-Lib很容易得到RSI:
rsi_value = talib.RSI(history_data, timeperiod=RSI_PERIOD)其中history_data是历史收盘价dataframe,timeperiod是统计周期。
注意:这里if context.i < RSI_PERIOD + 2与前面两个策略不同,请看下图,我们将均线(或布林带)和RSI的计算周期都设置成14天,两条线出现的时间相差一天,那是因为均线(或布林带)计算的14天是包括了当天的,而RSI是计算前面14天,也就是说RSI值是从第15天才有的,因此RSI的观察窗口要比均线或布林带增加1天:
def handle_data(context, data): """ 策略 """ # 经历过的交易周期大于周期窗口才开始计算 context.i += 1 if context.i < RSI_PERIOD + 2: return # 获取历史数据,返回dataframe history_data = data.history(context.asset, 'close', bar_count=RSI_PERIOD + 2, frequency="1D", ) # 获取当前持仓数量 pos_amount = context.portfolio.positions[context.asset].amount # 计算RSI rsi_value = talib.RSI(history_data, timeperiod=RSI_PERIOD) # 策略逻辑 # RSI值上穿超卖阈值,买入 if (rsi_value[-3] <= RSI_OVER_SOLD_THRESH) and (rsi_value[-2] >= RSI_OVER_SOLD_THRESH) and pos_amount == 0: # target买入百分比,1代表买入100%,0.5代表买入50%,0代表卖出 order_target_percent(asset=context.asset, target=1) # 设置交易信号为买入 context.signal = SIGNAL_BUY print(rsi_value) exit() # RSI值下穿超买阈值,卖出 if (rsi_value[-3] >= RSI_OVER_BOUGHT_THRESH) and (rsi_value[-2] <= RSI_OVER_BOUGHT_THRESH) 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, # 价格变化率 rsi_value=rsi_value[-1], # RSI值 signal=context.signal) # 交易信号 # 输出信息 print('日期:{}, 价格:{:.4f}, RSI值:{} 资产:{:.2f}, 持仓量:{:.8f}, {}'.format( data.current_dt, price, rsi_value[-1], context.portfolio.portfolio_value, pos_amount, context.signal )) # 重置交易信号 context.signal = SIGNAL_INIT也只是图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:输出资产货币价格、RSI和买卖点 ax2 = plt.subplot(412, sharex=ax1) perf.loc[:, ['price', 'rsi_value']].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()第一个图是持有BCH资产的价值走势 第二个图中绿色三角形代表买入点,红色三角形代表卖出点 第三个图是策略收益与基准收益的对比 第四个图是现金变动情况