User Tools

Site Tools


backtest_w_python

This is an old revision of the document!


Backtesting w/ Python

# coding: utf-8
import numpy as np
import pandas as pd
import talib as ta
 
df = pd.read_csv('Téléchargements/btceur-2h.csv')
#df = pd.read_csv('https://raw.githubusercontent.com/brulint/backtesting/main/btceur-2h.csv')
 
# strategy
fast = ta.EMA(df['close'], timeperiod = 20)
slow = ta.SMA(df['close'], timeperiod = 200)
 
position = fast > slow
 
# returns
returns_hodl = np.log(df.close / df.close.shift())
returns_strat = returns_hodl * (position.shift() == 1)
returns_netto = returns_strat - 0.0025 * (position != position.shift())
print('Returns: ', np.exp(returns_netto.sum()))
 
# graphs
from bokeh.plotting import figure,show
from bokeh.layouts import column,row
from bokeh.models import DatetimeTickFormatter
 
df['date'] = pd.to_datetime(df['time'], unit='s')
xformatter = DatetimeTickFormatter(hours="%H:%M", days="%d/%m", months="%m/%Y", years="%Y")
 
p0 = figure(height=325, width=800)
p0.xaxis[0].formatter = xformatter
p0.line(df['date'], df['close'])
 
p1 = figure(height=125, width=800, x_range=p0.x_range)
p1.xaxis[0].formatter = xformatter
p1.line(df['date'], returns_hodl)
 
p2 = figure(height=325, width=800, x_range=p0.x_range)
p2.xaxis[0].formatter = xformatter
p2.line(df['date'], df['close'])
p2.line(df['date'], slow, color='red')
p2.line(df['date'], fast, color='green')
 
p3 = figure(height=125, width=800, x_range=p0.x_range)
p3.xaxis[0].formatter = xformatter
p3.line(df['date'], position)
 
p4 = figure(height=325, width=800, x_range=p0.x_range)
p4.xaxis[0].formatter = xformatter
p4.line(df['date'], df['close'])
p4.triangle(df['date'], df['close'].where((position == 1) & (position.shift() == 0)), color='green', size=7)
p4.inverted_triangle(df['date'], df['close'].where((position == 0) & (position.shift() == 1)), color='red', size=7)
 
p5 = figure(height=150, width=800, x_range=p0.x_range)
p5.xaxis[0].formatter = xformatter
p5.line(df['date'], returns_hodl, color='lightgray')
p5.line(df['date'], returns_strat)
 
p6 = figure(height=325, width=800, x_range=p0.x_range)
p6.xaxis[0].formatter = xformatter
p6.line(df['date'], np.exp(returns_hodl.cumsum()), color='lightgray')
p6.line(df['date'], np.exp(returns_strat.cumsum()))
p6.line(df['date'], np.exp(returns_netto.cumsum()), color='red')
 
layout = column(p0, p1, p2, p3, p4, p5, p6)
show(layout)

Light version

# coding: utf-8
import numpy as np
import pandas as pd
import talib as ta
 
 Donwload data
# https://support.kraken.com/hc/en-us/articles/360047124832
names = ['time', 'open', 'high', 'low', 'close', 'volume', 'count']
df = pd.read_csv('XBTEUR_1440.csv', names=names) 
df = df[int(-10.5*365):] # Only the X last years
df['close'] = df.close.replace(to_replace=0, method='ffill')
 
# Strategy begin
RSI = ta.RSI(df.close, timeperiod=14)
SIG_in = (RSI.shift() < 25) & (RSI > 25)
SIG_out = (RSI.shift() > 75) & (RSI < 75)
# Strategy end
 
POS = SIG_in.astype(int) - SIG_out.astype(int)
POS = POS.replace(to_replace=0, method='ffill') > 0
r_hodl = np.log(df.close / df.close.shift())
r_strat = r_hodl * (POS.shift() == 1)
r_netto = r_strat - 0.0025 * (POS != POS.shift())
print('Return: ',np.exp(r_netto.sum()))
 
from bokeh.plotting import figure,show
df['time'] = pd.to_datetime(df.time, unit='s')
fig = figure(height=300, x_axis_type="datetime")
fig.line(df.time, np.exp(r_hodl.cumsum()), color='lightgray')
fig.line(df.time, np.exp(r_strat.cumsum()), color='blue')
fig.line(df.time, np.exp(r_netto.cumsum()), color='red')
show(fig)

https://support.kraken.com/hc/en-us/articles/360047124832

Sinon

Un vieux code de 2022 (si pas plus). Chrypowatch n'existe plus, c'est dire :-)

# coding: utf-8
import requests
import numpy as np
import pandas as pd
 
import talib
 
url = 'https://api.cryptowat.ch/markets/kraken/btceur/ohlc'
ohlc = requests.get(url).json()['result'][str(12*60*60)]
columns = ['time','open','high','low','close','volume','count']
df = pd.DataFrame(ohlc, columns=columns).astype(float)
df = df.iloc[-1000:]
 
df['RSI'] = talib.RSI(df['close'], timeperiod=14)
#df['RSI'] = df.RSI.fillna(value=df.RSI.loc[14])
df['long'] = talib.SMA(df.close, timeperiod=200)
#df['long'] = df.long.fillna(value=df.long.loc[200])
df['short'] = talib.SMA(df.close,timeperiod=14)
#df['short'] = df.short.fillna(value=df.short.loc[14])
df['trend'] = df.long < df.short
# signal
df['sig_in'] = (df.RSI > 60) & df.trend
df['sig_out'] = (df.RSI < 40)# | 1-df.trend
#df['sig_in'] = (df.RSI.shift() < 70) & (df.RSI > 70)
#df['sig_out'] = (df.RSI.shift() > 30) & (df.RSI < 30)
#df['sig_in'] = (df.RSI.shift() < 25) & (df.RSI > 25)
#df['stoploss'] = df.low.rolling(5).min().where(df.sig_in==1).ffill()
#df['sig_out'] = ((df.RSI.shift() > 75) & (df.RSI < 75)) | ((df.RSI.shift()>25) & (df.RSI<25)) | (df.close < df.stoploss)
 
#df['signal'] = df.sig_in.where(df.sig_in).fillna(1-df.sig_out.where(df.sig_out)).ffill()
#df['sig_out'].loc[0] = True
#df['signal'] = (1-df.sig_out.where(df.sig_out)).fillna(df.sig_in.where(df.sig_in)).ffill()# * df.trend 
 
df['sig_0'] = df.sig_in.astype(int) - df.sig_out.astype(int)
df['sig_1'] = df.sig_0.where(df.sig_0!=0).ffill()
df['signal'] = df.sig_1 > 0
# Rendements
df['close'] = df.close.replace(to_replace=0, method='ffill')
df['r_0'] = df.close / df.close.shift()
df['r_strat'] = np.where(df.signal.shift(), df.r_0, 1)
df['r_fee'] = np.where(df.signal.shift() + df.signal == 1, 1-0.0025, 1)
# tronquage datafame
#df = df.iloc[-700:]
# Rendement cumulé
df['R_net'] = (df.r_strat * df.r_fee).cumprod()
# Graphiques
from bokeh.plotting import figure,show
from bokeh.layouts import column,row
p1 = figure(height=300,width=800)
p1.line(df.time,df.close)
#p1.line(df.time,df.long,color='green')
#p1.line(df.time,df.short,color='red')
p2 =  figure(height=100,width=800,x_range=p1.x_range)
p2.line(df.time,df.RSI)
#p3_0 = figure(height=100,width=800,x_range=p1.x_range)
#p3_0.line(df.time,df.trend)
p3_1 = figure(height=100,width=800,x_range=p1.x_range)
p3_1.line(df.time,df.sig_in,color='green')
p3_2 = figure(height=100,width=800,x_range=p1.x_range)
p3_2.line(df.time,df.sig_out,color='red')
p3_3 = figure(height=100,width=800,x_range=p1.x_range)
p3_3.line(df.time,df.sig_0)
p3_3_2 = figure(height=100,width=800,x_range=p1.x_range) 
p3_3_2.line(df.time,df.sig_1)
p3_4 = figure(height=100,width=800,x_range=p1.x_range)
p3_4.line(df.time,df.signal)
p4 = figure(height=150,width=800,x_range=p1.x_range)
p4.line(df.time,df.r_0,color='lightgray')
p4.line(df.time,df.r_strat)
p4.line(df.time,df.r_fee,color='red')
p5 = figure(height=300,width=800,x_range=p1.x_range)
p5.line(df.time,df.r_0.cumprod(),color='lightgray')
p5.line(df.time,df.r_strat.cumprod())
p5.line(df.time,df.R_net,color='red')
layout = column(p1,p2,p3_1,p3_2,p3_3,p3_3_2,p3_4,p4,p5)
show(layout)
backtest_w_python.1742695457.txt.gz · Last modified: 2025/03/23 02:04 by bruno