Hello there and welcome to another article, today I will get into one of the most important topics in algorithmic trading which is backtesting.
Backtesting is the process of testing your strategy on historical data to get a clear vision about how this strategy would performed and how it will perform in the live trading.
also, backtesting doesn’t guarantee that the strategy or the trading bot will perform as it performed on historical data for many reasons….
but still backtesting is a precious tool every algorithmic trader and traders in general need as it can transform the performance by manipulating and testing new strategies.
In this article we will develop a simple strategy and backtest it using backtrader library and I’ll use jupyter notebook.
let’s jump into it.
Import the backtrader library.
import backtrader as bt
Download Bitcoin data from yahoo finance
starting from 2018 we’ll get the daily time frame
import yfinance as yf
data = yf.download("BTC-USD",start='2018-01-01')
data.head()
Now it’s time to think about the Strategy.
I will develop a Buy the dip strategy which is :
If prices drop three days in a row we buy
and sell after 2 days.
create dipStrategy class and pass strategy(a built in object inside backtrader.)
class dipStrategy(bt.Strategy):
def log(self, txt, dt=None):
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))
backtrader log function *** datas[0] is the current data row.
def __init__(self):
self.dataclose = self.datas[0].close
self.order = None
Keep a reference to the “close” line in the data[0] dataseries in dataclose
set order to None as there is no order yet.
def notify_order(self, order):
if order.status in [order.Submitted, order.Accepted]:
return
if order.status in [order.Completed]:
if order.isbuy():
self.log('BUY EXECUTED,%.2f' % order.executed.price)
elif order.issell():
self.log('SELL EXECUTED,%.2f' %order.executed.price)
self.bar_executed = len(self)
elif order.status in [order.Canceled,
order.Margin,order.Rejected]:
self.log('Order Canceled/Margin/Rejected')
self.order = None
check order status if in submitted or accepted then return.
*** not completed yet but accepted by the broker.
len(self) will return day number
ex: if we bought at day 200 we sould keep track of that number as we’ll sell after 2 days at day 202
we save the order day in bar_executed
Check if an order has been completed
if buy order completed log the price isbuy() built in function in backtrader
if order in status in canceled… log this
if sell order completed log the price
set order to None as there is no pending order
def next(self):
self.log('Close, %.2f' % self.dataclose[0])
if self.order:
return
if not self.position :
if self.dataclose[0] < self.dataclose[-1]:
if self.dataclose[-1] < self.dataclose[-2]:
if self.dataclose[-2] < self.dataclose[-3]:
self.log('BUY CREATE, %.2f' %
self.dataclose[0])
self.buy()
self.order = self.buy()
else:
if len(self) >= self.bar_executed + 2 :
self.log('SELL CREATE, %.2f' % self.dataclose[0])
self.order = self.sell()
Simply log the closing price of the series from the reference
Check if there is pending order if yes, return
check if we have position in the market.
we’ll check if the price drops three days in a row
if today close less than yesterday till three previous days
*** [-1] is the preious day index and so on till [-3]
Now it’s time to buy as our conditions met log price
set buy order
set order to the buy order to keep track and avoid sending second order
self.buy() return buy order object
Sell conditon
after 2 days we sell our position
and we keep track by bar_executed variable
we’ve finished coding our strategy
Now it’s show time, let’s execute.
Backtesting
cerebro = bt.Cerebro()
cerebro.broker.setcash(100000.0)
cerebro.addsizer(bt.sizers.SizerFix, stake=2)
df = bt.feeds.PandasData(dataname=data)
cerebro.adddata(df)
cerebro.addstrategy(dipStrategy)
print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
cerebro.run()
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
cerebro is backtrader engine we’ll create an instance
set how much cash in your account is set it to 100k
set size of your order ** how much you’ll buy i set it to 2 shares (bitcoins)
data feed in our case we have pandas data dataframe
pass data feed to cerebro with adddata() method
add our strategy to cerebro with addstrategy() method
print account cash in start
run the engine start trade
print cashe at the end
Results
we get along list with all trader executed.
We started with 100k and at the end we have 141k 🔥 👌 that’s not bad isn’t it…😁
note: of course this strategy underperformed the market but the aim is to come up with your strategy, optimize and manipulate till your reach a point where you have a strategy that can outperform the market with consistent monitoring, optimization, and idea generation.
What about visualizing our trades
cerebro.plot()
what’s next
I think backtrader is a great tool for traders to test and manipulate their strategies
In my previous article we developed a crypto trading bot but without the backteting part, and today we did.
That’s it for this article I hope you enjoy.
Top comments (0)