Backtrader: Live trading shutdown

When your algorithm graduates from a backtest environment to trading with a live account (be it demo or practice), there are a number extra things that need to be considered. For example, how do you want to monitor the performance of the algorithm? During backtesting, it is likely that you generate your analysis reports at the end of a run. However, during live trading, you might want to create daily reports. Another consideration is how will you shutdown the algorithm? Given that live data does not to have a set endpoint, when the time comes to shut it down, it would be better to do so gracefully rather just killing it! Finally, when money is on the line,  it would be wise to take a look at how to handle unexpected failures (like a power outage). These are just a few examples, I am sure BTR readers will be able to think of many more.

This post cannot cover all of the topics described above. Instead, we shall just take a look at one way to manually shut down a live algorithm.

Signals

Signals are going to form the foundation of the shutdown code. As such, it is worth spending a short paragraph to give some background on them so the code can be better understood. Signals are operating system events that are sent to a program to notify it of something important that must be addressed before anything else can continue. Once sent, the signal interrupts whatever process/program is running and forces it to handle the signal immediately. There are a number of different signals that can be sent. Each one has its’ own meaning and default behaviour that is executed when the signal is received. If the default behaviour is not desired, a program can contain code within it to handle the signal in a different way. Rather aptly, the code to handle a signal is called a handler.

So now we have a bit of background, you might be wondering which signal shall we use and how do we send it? In addition to the operating system sending signals, they can also be sent manually by a program or end user. In fact, you have likely done this countless times before without realizing it. CTRL + C sends a SIGINT (interrupt) signal to a  program. Usually, when we do this on a running python script, a KeyboardInterrupterror is raised. This is the default behavior. We are going to overwrite this default behaviour to shutdown the script. In an ideal world, we would send SIGINT via some other method to the script running as a background process (or daemon). However, for simplicity and just to lay the foundations, we will keep it simple and hit CTRL + C.

Python Docs

Working with signals in Python is a breeze thanks to a handy built-in Python module. We will import this module in our code below. For further information regarding the module, a link to the module documentation is provided below.

https://docs.python.org/3/library/signal.html

Now we are able to catch an incoming signal, we need to think about what the handler will do. Luckily, Backtrader has a handy method to help us out.

Backtrader shutdown

As mentioned above, Backtrader has a built-in method that helps us shutdown the algorithm. Calling runstop()from within the strategy will stop all threads of execution as soon as possible. See the documentation here. During my testing, I have found this allows me to stop cerebro and plot a resulting chart.

https://www.backtrader.com/docu/cerebro.html#backtrader.Cerebro.runstop

So now all we need to do is put the two together and we are done!

The Code

The code example below was written to work with Backtrader’s Oanda store. However, there is no reason why it cannot be adapted easily to the IB store. When copying the code, please be sure to update the API key and Account number with your own. Otherwise, it will not work. Also if you are new to trading live with Oanda, it is worth pointing out that Backtraders Oanda store uses the old Oandapy API. This means that you will need to use a legacy Oanda account with Backtrader algorithms.

Commentary

The code above is deliberately simple. It will do nothing other than print OHLC data on each call of next(). This allows us to focus on the shutdown. The first thing we need to do (apart from import the signal module) is create a method to handle the signal in the strategy. This method is executed when a SIGINT signal is received. You can name the method whatever you like and it can contain any steps you wish. The key to stopping the algorithm is to call self.env.runstop()at the end of it.

The only thing to do after that is to bind the method to the signal. This is done during strategy initialization. The signal.signal()function is called and inside it, we pass two arguments. The first argument is the signal number to listen for. The second is the handler to call when the signal is received. It is as simple as that.

A word of warning

Take care when working with signals. It is possible to end up in a state where you cannot kill the program because have overridden the default behaviour and not terminated the program.