Files
strategy-lab/to_explore/notebooks/BasicRSI.ipynb

16 KiB

Basic RSI strategy

Single backtest

In [ ]:
from vectorbtpro import *
# whats_imported()

vbt.settings.set_theme('dark')
In [ ]:
data = vbt.BinanceData.pull('BTCUSDT')
data
In [ ]:
data.data['BTCUSDT'].vbt.ohlcv.plot().show_svg()
In [ ]:
data.data['BTCUSDT'].info()
In [ ]:
open_price = data.get('Open')
close_price = data.get('Close')
In [ ]:
vbt.IF.list_indicators("RSI*")
In [ ]:
vbt.indicator("talib:RSI")
In [ ]:
vbt.RSI
In [ ]:
vbt.talib('RSI')
In [ ]:
vbt.ta('RSIIndicator')
In [ ]:
vbt.pandas_ta('RSI')
In [ ]:
print(vbt.format_func(vbt.RSI.run))
In [ ]:
rsi = vbt.RSI.run(open_price)
rsi
In [ ]:
rsi.rsi
In [ ]:
entries = rsi.rsi.vbt.crossed_below(30)
entries
In [ ]:
exits = rsi.rsi.vbt.crossed_above(70)
exits
In [ ]:
entries = rsi.rsi_crossed_below(30)
exits = rsi.rsi_crossed_above(70)
In [ ]:
def plot_rsi(rsi, entries, exits):
    fig = rsi.plot()
    entries.vbt.signals.plot_as_entries(rsi.rsi, fig=fig)
    exits.vbt.signals.plot_as_exits(rsi.rsi, fig=fig)
    return fig
In [ ]:
plot_rsi(rsi, entries, exits).show_svg()
In [ ]:
clean_entries, clean_exits = entries.vbt.signals.clean(exits)

plot_rsi(rsi, clean_entries, clean_exits).show_svg()
In [ ]:
clean_entries.vbt.signals.total()
In [ ]:
clean_exits.vbt.signals.total()
In [ ]:
ranges = clean_entries.vbt.signals.between_ranges(target=clean_exits)
ranges.duration.mean(wrap_kwargs=dict(to_timedelta=True))
In [ ]:
pf = vbt.Portfolio.from_signals(
    close=close_price, 
    entries=clean_entries, 
    exits=clean_exits,
    size=100,
    size_type='value',
    init_cash='auto'
)
pf
In [ ]:
pf.stats()
In [ ]:
pf.plot(settings=dict(bm_returns=False)).show_svg()

Multiple backtests

Using for-loop

In [ ]:
def test_rsi(window=14, wtype="wilder", lower_th=30, upper_th=70):
    rsi = vbt.RSI.run(open_price, window=window, wtype=wtype)
    entries = rsi.rsi_crossed_below(lower_th)
    exits = rsi.rsi_crossed_above(upper_th)
    pf = vbt.Portfolio.from_signals(
        close=close_price, 
        entries=entries, 
        exits=exits,
        size=100,
        size_type='value',
        init_cash='auto')
    return pf.stats([
        'total_return', 
        'total_trades', 
        'win_rate', 
        'expectancy'
    ])
In [ ]:
test_rsi()
In [ ]:
test_rsi(lower_th=20, upper_th=80)
In [ ]:
from itertools import product

lower_ths = range(20, 31)
upper_ths = range(70, 81)
th_combs = list(product(lower_ths, upper_ths))
len(th_combs)
In [ ]:
comb_stats = [
    test_rsi(lower_th=lower_th, upper_th=upper_th)
    for lower_th, upper_th in th_combs
]
In [ ]:
comb_stats_df = pd.DataFrame(comb_stats)
print(comb_stats_df)
In [ ]:
comb_stats_df.index = pd.MultiIndex.from_tuples(
    th_combs, 
    names=['lower_th', 'upper_th'])
print(comb_stats_df)
In [ ]:
comb_stats_df['Expectancy'].vbt.heatmap().show_svg()

Using columns

In [ ]:
windows = list(range(8, 21))
wtypes = ["simple", "exp", "wilder"]
lower_ths = list(range(20, 31))
upper_ths = list(range(70, 81))
In [ ]:
rsi = vbt.RSI.run(
    open_price, 
    window=windows, 
    wtype=wtypes, 
    param_product=True)
rsi.rsi.columns
In [ ]:
lower_ths_prod, upper_ths_prod = zip(*product(lower_ths, upper_ths))
len(lower_ths_prod)
In [ ]:
len(upper_ths_prod)
In [ ]:
lower_th_index = vbt.Param(lower_ths_prod, name='lower_th')
entries = rsi.rsi_crossed_below(lower_th_index)
entries.columns
In [ ]:
upper_th_index = vbt.Param(upper_ths_prod, name='upper_th')
exits = rsi.rsi_crossed_above(upper_th_index)
exits.columns
In [ ]:
pf = vbt.Portfolio.from_signals(
    close=close_price, 
    entries=entries, 
    exits=exits,
    size=100,
    size_type='value',
    init_cash='auto'
)
pf
In [ ]:
stats_df = pf.stats([
    'total_return', 
    'total_trades', 
    'win_rate', 
    'expectancy'
], agg_func=None)
print(stats_df)
In [ ]:
>>> print(pf.getsize())
In [ ]:
>>> np.product(pf.wrapper.shape) * 8 / 1024 / 1024
In [ ]:
stats_df['Expectancy'].groupby('rsi_window').mean()
In [ ]:
print(stats_df.sort_values(by='Expectancy', ascending=False).head())
In [ ]:
pf[(22, 80, 20, "wilder")].plot_value().show_svg()
In [ ]:
data = vbt.BinanceData.pull(['BTCUSDT', 'ETHUSDT'])
In [ ]:
open_price = data.get('Open')
close_price = data.get('Close')
In [ ]:
rsi = vbt.RSI.run(
    open_price, 
    window=windows, 
    wtype=wtypes, 
    param_product=True)
entries = rsi.rsi_crossed_below(lower_th_index)
exits = rsi.rsi_crossed_above(upper_th_index)
pf = vbt.Portfolio.from_signals(
    close=close_price, 
    entries=entries, 
    exits=exits,
    size=100,
    size_type='value',
    init_cash='auto'
)
stats_df = pf.stats([
    'total_return', 
    'total_trades', 
    'win_rate', 
    'expectancy'
], agg_func=None)
In [ ]:
stats_df.index
In [ ]:
eth_mask = stats_df.index.get_level_values('symbol') == 'ETHUSDT'
btc_mask = stats_df.index.get_level_values('symbol') == 'BTCUSDT'
pd.DataFrame({
    'ETHUSDT': stats_df[eth_mask]['Expectancy'].values,
    'BTCUSDT': stats_df[btc_mask]['Expectancy'].values
}).vbt.histplot(xaxis=dict(title="Expectancy")).show_svg()
In [ ]: