数字货币量化之 Catalyst 相对强弱指数 (RSI) 策略
策略原理
- 根据一定时期内(通常为14个周期,针对股票)
上涨点数之和
与下跌点数之和
的比率制作出的一种技术曲线 - 任何市价的大涨或大跌,均在0-100之间变动,根据常态分配,认为RSI值多在 30-70之间变动
- 当价格低跌至30以下即被认为是
超卖状态
,价格即将出现上涨。 - 当价格升至70以上即被认为是
超买状态
,价格即将出现下跌。
上边的计算方法简单来讲就是一定周期内,假设为过去14天,我们把这14天内上涨的点数加起来,把下跌的也加起来,然后根据这两个值,就可以算出RSI了。
策略逻辑
- 空仓状态下,RSI值上穿(大于)超卖阀值,且该数字货币可以交易,满仓买入。
- 持仓状态下,RSI值下穿(小于)超买阀值,且该数字货币可以交易,满仓卖出。
计算公式
开发准备
在jupyter notebook中使用虚拟环境
- 启用虚拟环境
- windows: activate catalyst
- Mac OS: source activate catalyst
- pip install ipykemel
- python -m ipykemel install --user --name=catalyst
- jupyter kemelspec list
安装TA-Lib(Technical Analysis Library)
- Ta-Lib:提供了200多种金融指标,开源,支持C/C++, Perl, Python...
- Windows
-
- pip install [.whl文件]
- Mac OS
-
- brew install ta-lib
-
- pip install TA-Lib
-
代码实战
rsi_alg.py
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import talib
from catalyst import run_algorithm
from catalyst.api import record, symbol, order_target_percent
from catalyst.exchange.utils.stats_utils import extract_transactions
# 需要先加载数据
# catalyst ingest-exchange -x binance -i btc_usdt -f daily
NAMESPACE = 'relative_strength_index'
SIGNAL_BUY = 'buy' # 买入信号
SIGNAL_SELL = 'sell' # 卖出信号
SIGNAL_INIT = '' # 观望信号
RSI_PERIODS = 7 # RSI计算周期,如果周期比较短,对价格比较敏感
RSI_OVER_SOLD_THRESH = 25 # 超卖阈值 30,20
RSI_OVER_BOUGHT_THRESH = 75 # 超买阈值 70, 80
def initialize(context):
"""
初始化
"""
context.i = 0 # 经历过的交易周期
context.asset = symbol('btc_usdt') # 交易对
context.base_price = None # 初始价格
context.signal = SIGNAL_INIT # 交易信号
context.set_commission(maker=0.001, taker=0.001) # 设置手续费
context.set_slippage(slippage=0.001) # 设置滑点
def handle_data(context, data):
"""
在每个交易周期上运行的策略
"""
context.i += 1 # 记录交易周期
if context.i < RSI_PERIODS + 3:
# 如果交易周期过短,无法计算RSI,则跳过循环
return
# 获得历史价格
hitory_data = data.history(context.asset,
'close',
bar_count=RSI_PERIODS + 3,
frequency='1D',
)
# 获取当前持仓数量
pos_amount = context.portfolio.positions[context.asset].amount
# 计算RSI
rsi_vals = talib.RSI(hitory_data, timeperiod=RSI_PERIODS)
# RSI 交易策略
if (rsi_vals[-3] <= RSI_OVER_SOLD_THRESH) and (rsi_vals[-2] >= RSI_OVER_SOLD_THRESH) and pos_amount == 0:
# RSI值上穿超卖阈值,买入
order_target_percent(context.asset, 1)
context.signal = SIGNAL_BUY
if (rsi_vals[-3] >= RSI_OVER_BOUGHT_THRESH) and (rsi_vals[-2] <= RSI_OVER_BOUGHT_THRESH) and pos_amount > 0:
# RSI值下穿超卖阈值,卖出
order_target_percent(context.asset, 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
# 记录每个交易周期的信息
# 1. 价格, 2. 现金, 3. 价格变化率, 4. 快线均值, 5. 慢线均值
record(price=price,
cash=context.portfolio.cash,
price_change=price_change,
rsi=rsi_vals[-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
def analyze(context, perf):
# 保存交易记录
perf.to_csv('./rsi_performance.csv')
# 获取交易所的计价货币
exchange = list(context.exchanges.values())[0]
quote_currency = exchange.quote_currency.upper()
# 图1:可视化资产值
ax1 = plt.subplot(411)
perf['portfolio_value'].plot(ax=ax1)
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[['price', 'rsi']].plot(ax=ax2)
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)
if not transaction_df.empty:
buy_df = transaction_df[transaction_df['amount'] > 0] # 买入点
sell_df = transaction_df[transaction_df['amount'] < 0] # 卖出点
ax2.scatter(
buy_df.index.to_pydatetime(),
perf.loc[buy_df.index, 'price'],
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[['algorithm_period_return', 'price_change']].plot(ax=ax3)
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.tight_layout()
plt.show()
if __name__ == '__main__':
run_algorithm(
capital_base=1000,
data_frequency='daily',
initialize=initialize,
handle_data=handle_data,
analyze=analyze,
exchange_name='binance',
algo_namespace=NAMESPACE,
quote_currency='usdt',
start=pd.to_datetime('2019-02-01', utc=True),
end=pd.to_datetime('2019-12-22', utc=True)
)
输出打印:
[2019-12-23 13:12:57.347171] INFO: exchange_algorithm: initialized trading algorithm in backtest mode
日期:2019-01-12 23:59:00+00:00,价格:3583.1300,资产:1000.00,持仓量:0.00000000,
日期:2019-01-13 23:59:00+00:00,价格:3476.8100,资产:1000.00,持仓量:0.00000000,
日期:2019-01-14 23:59:00+00:00,价格:3626.0900,资产:1000.00,持仓量:0.00000000,
日期:2019-01-15 23:59:00+00:00,价格:3553.0600,资产:1000.00,持仓量:0.00000000, buy
日期:2019-01-16 23:59:00+00:00,价格:3591.8400,资产:997.98,持仓量:0.28144754,
日期:2019-01-17 23:59:00+00:00,价格:3616.2100,资产:1004.84,持仓量:0.28144754,
日期:2019-01-18 23:59:00+00:00,价格:3594.8700,资产:998.83,持仓量:0.28144754,
...
日期:2019-12-17 23:59:00+00:00,价格:6623.8200,资产:1736.18,持仓量:0.26638699,
日期:2019-12-18 23:59:00+00:00,价格:7277.8300,资产:1910.40,持仓量:0.26638699,
日期:2019-12-19 23:59:00+00:00,价格:7150.3000,资产:1876.42,持仓量:0.26638699,
日期:2019-12-20 23:59:00+00:00,价格:7187.8300,资产:1886.42,持仓量:0.26638699,
通过对交易周期,超买,超卖的参数调整,可以看到RSI策略收益还不错。
为者常成,行者常至
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)