Interactive Brokers in Python With Backtrader by Daniel Rodrig-Job 6
Interactive Brokers in Python With Backtrader by Daniel Rodrig-Job 6
Open in app
Daniel Rodriguez
Reddit’s r/algotrading seems to have a constant number of posts which revolve about the
ideas: How can I trade with Python (using frameworks or not) and Interactive Brokers?
Let’s try to see how to achieve it with backtrader .
For starters we need an environment, so let’s create one and to go with the times, we will
set it up with the formidable pipenv .
This will create a virtual environment with the aforementioned packages (yes, we have
installed directly from the GitHub master, because *IbPy* is not available on PyPi)
(Note: since backtrader was integrated with IbPy , the latter was finally added to PyPi
We of course need to have access to Interactive Brokers. For the purpose of this post,
we’ll use the full blown client but we *Faux Data*.
https://medium.com/@danjrod/interactive-brokers-in-python-with-backtrader-23dea376b2fc 1/10
3/27/2021 Interactive Brokers in Python with backtrader | by Daniel Rodriguez | Medium
If the link is broken … google it, finding the latest version of TWS isn’t such a great
deal
Username: edemo
Password: demouser
The actual trading makes no difference with Faux Data, it is just to show what you will
probably want to do before really going live.
https://medium.com/@danjrod/interactive-brokers-in-python-with-backtrader-23dea376b2fc 2/10
3/27/2021 Interactive Brokers in Python with backtrader | by Daniel Rodriguez | Medium
Under File -> Global Configuration choose Settings -> API and
Check Enable ActiveX and Socket Clients and uncheck Read-Only API
Notice that the port is 7497 , which differs from the standard 7496 which is used for
Live Trading (remember we chose Paper Trading above)
https://medium.com/@danjrod/interactive-brokers-in-python-with-backtrader-23dea376b2fc 3/10
3/27/2021 Interactive Brokers in Python with backtrader | by Daniel Rodriguez | Medium
import backtrader as bt
class St(bt.Strategy):
def logdata(self):
txt = []
txt.append('{}'.format(len(self)))
txt.append('{}'.format(
self.data.datetime.datetime(0).isoformat())
)
txt.append('{:.2f}'.format(self.data.open[0]))
txt.append('{:.2f}'.format(self.data.high[0]))
txt.append('{:.2f}'.format(self.data.low[0]))
txt.append('{:.2f}'.format(self.data.close[0]))
txt.append('{:.2f}'.format(self.data.volume[0]))
print(','.join(txt))
def next(self):
self.logdata()
def run(args=None):
cerebro = bt.Cerebro(stdstats=False)
store = bt.stores.IBStore(port=7497)
data = store.getdata(dataname='TWTR',
timeframe=bt.TimeFrame.Ticks)
cerebro.resampledata(data, timeframe=bt.TimeFrame.Seconds,
https://medium.com/@danjrod/interactive-brokers-in-python-with-backtrader-23dea376b2fc 4/10
3/27/2021 Interactive Brokers in Python with backtrader | by Daniel Rodriguez | Medium
compression=10)
cerebro.addstrategy(St)
cerebro.run()
if __name__ == '__main__':
run()
Some notes
Our strategy class, does simply print the data. Let’s see how it looks like
Server Version: 76
TWS Time at connection:20180301 10:46:18 CET
1,2018-03-01T06:46:20,33.41,33.43,33.38,33.38,11.00
2,2018-03-01T06:46:30,33.42,33.42,33.34,33.42,15.00
...
1079,2018-03-01T09:46:00,33.56,33.57,33.54,33.57,33.00
1080,2018-03-01T09:46:10,33.56,33.59,33.55,33.57,32.00
1081,2018-03-01T09:46:30,33.44,33.44,33.43,33.43,7.00
1082,2018-03-01T09:46:40,33.44,33.47,33.41,33.44,22.00
Very quickly a whooping total of 1082 bars. This is so, because backtrader has done back-
filling for us. But we don’t know where is the difference between back-filled bars and the
real-time bars. Let’s rely on notifications by extending our strategy class with this
method (and an attribute to control when data is live)
data_live = False
https://medium.com/@danjrod/interactive-brokers-in-python-with-backtrader-23dea376b2fc 5/10
3/27/2021 Interactive Brokers in Python with backtrader | by Daniel Rodriguez | Medium
Server Version: 76
TWS Time at connection:20180301 10:52:58 CET
***** DATA NOTIF: DELAYED
1,2018-03-01T06:53:00,33.43,33.44,33.43,33.43,10.00
...
1081,2018-03-01T09:53:00,33.51,33.51,33.51,33.51,6.00
***** DATA NOTIF: LIVE
1082,2018-03-01T09:53:10,33.52,33.54,33.52,33.52,31.00
Now we see it clearly. At the beginning the data is DELAYED and only after 1081 bars is
the system in a position to provide you with real-time data. Remember we are using 10-
seconds bars. When we get bar 1082, this is the summary of the last 10 seconds.
The next step is obviously doing some trading, now that we are getting some data. If you
have carefully read the code above you will have noticed that the data stream is fetched
with a: store.getdata(...) . And that before that we created the store with store =
bt.stores.IBStore(...)
backtrader offers the Store concept to provide a unified interface to access data instances
and broker instances. This post is about Interactive Brokers. If you decide to go some
other path, you simply need to change the Store. Getting the data will still be done with
data = store.getdata(...)
All this store applies to the broker and will be used now. We are going to add our broker
to the mixture
https://medium.com/@danjrod/interactive-brokers-in-python-with-backtrader-23dea376b2fc 6/10
3/27/2021 Interactive Brokers in Python with backtrader | by Daniel Rodriguez | Medium
...
cerebro.resampledata(data, timeframe=bt.TimeFrame.Seconds,
compression=10)
cerebro.broker = store.getbroker()
cerebro.addstrategy(St)
...
This simple line (after for example cerebro.resampledata ) does the magic of changing
the backtesting broker (which defaults to a broker simulation) engine to use the
Interactive Brokers facilities.
We obviously need now some buy/sell action. Rather than implementing a sensible
strategy, we will go for a dummy approach
Sell 1 unit 3 bars later ( Market order) for which we’ll issue a self.sell()
The reason: we don’t want to wait for moving averages crossing over or stochatic or rsi
indicators going overbought or oversold.
We obviously also want to see when the orders have been executed, so we’ll also look out
for order notifications.
bought = 0
sold = 0
def next(self):
self.logdata()
https://medium.com/@danjrod/interactive-brokers-in-python-with-backtrader-23dea376b2fc 7/10
3/27/2021 Interactive Brokers in Python with backtrader | by Daniel Rodriguez | Medium
if not self.data_live:
return
if not self.bought:
self.bought = len(self) # keep entry bar
self.buy()
elif not self.sold:
if len(self) == (self.bought + 3):
self.sell()
That’s the set of modifications we have made to the simple strategy we had above. Not
much. bought and sold will be used as flags to understand if we have already bought
(and when) and sold. We’ll only be executing these operations once in this example.
Server Version: 76
TWS Time at connection:20180301 11:12:56 CET
***** DATA NOTIF: DELAYED
1,2018-03-01T07:12:50,33.54,33.56,33.52,33.54,25.00
...
1081,2018-03-01T10:12:50,33.19,33.19,33.18,33.19,8.00
***** DATA NOTIF: LIVE
1082,2018-03-01T10:13:00,33.55,33.55,33.55,33.55,64.00
BUY [email protected]
1083,2018-03-01T10:13:10,33.55,33.55,33.54,33.54,17.00
1084,2018-03-01T10:13:20,33.55,33.55,33.52,33.54,9.00
1085,2018-03-01T10:13:30,33.54,33.54,33.53,33.54,33.00
SELL [email protected]
1086,2018-03-01T10:13:40,33.52,33.56,33.52,33.52,45.00
...
Incredible but true. The code we crafted above has respected our wishes and when the
data has gone live, a buy has been executed. And 3 bars later a sell has also been
executed.
We have actually lost some money because we bought at 33.55 and sold at 33.52 , but
so is the circus.
https://medium.com/@danjrod/interactive-brokers-in-python-with-backtrader-23dea376b2fc 8/10
3/27/2021 Interactive Brokers in Python with backtrader | by Daniel Rodriguez | Medium
The 3 code samples (in 1) from above have been placed in Github under
https://gist.github.com/backtrader/456cf0891a7a62ceb2bbb5e4234c01e7
This a rather dull and boring example, but it should give an insight as how easy it is to
get up and running. There are many more things you could apply, like for example
Indicators, like moving averages , stochastic , macd , rsi and many others. Over
100 are built-in in backtrader. Should that not be enough, you can also use ta-lib
with it
Observers: which are half-way between Indicators and Analyzers and are mostly
intended for plotting
Plotting: (not in real-time) You need matplotlib and you can plot with a single
command cerebro.plot() at the end of your backtesting
And many other things which you can check in the docs or you can ask about int the
community.
Docs: https://www.backtrader.com/docu
Blog: https://www.backtrader.com/blog
Community: https://community.backtrader.com
Of course and before you engage into any trading: do you backtesting, look for bugs in
your code, redo your backtesting.
Happy trading.
https://medium.com/@danjrod/interactive-brokers-in-python-with-backtrader-23dea376b2fc 9/10
3/27/2021 Interactive Brokers in Python with backtrader | by Daniel Rodriguez | Medium
https://medium.com/@danjrod/interactive-brokers-in-python-with-backtrader-23dea376b2fc 10/10