avatarMr. Q

Summary

This article outlines a method for backtesting a trading strategy using Python, focusing on the application of Keltner Channels (K-Band) to a long-short trading strategy with FTSE 100 ETF (ISF.L) for the year 2019.

Abstract

The article, part of a series on Python for financial analysis, demonstrates how to backtest a trading strategy using Python's financial and technical analysis libraries. It details the process of setting up the necessary Python packages, yfinance for data retrieval, and ta for technical indicators, to test the efficacy of trading signals generated by Keltner Channels on the FTSE 100 ETF. The author explains the importance of defining trading signals for entering and exiting positions, simulating trades, and analyzing the strategy's performance against a buy-and-hold benchmark. The backtesting results indicate that the strategy could have yielded a 41.3% return in 2019, significantly outperforming the buy-and-hold strategy's 14.25% return, with insights into the number of trades, their quality, and potential areas for strategy improvement, such as incorporating stop-loss mechanisms.

Opinions

  • The author believes that backtesting is a crucial step before executing real-world trades.
  • There is an emphasis on the practical application of Python tools and libraries for financial analysis.
  • The author suggests that the Keltner Channels strategy is not overly volatile and has the potential to enhance returns.
  • The article posits that refining the strategy with additional features like stop-loss could further optimize performance.
  • The author is of the opinion that the strategy's success is not attributable to a few outlier trades, indicating a robust signal quality.
  • There is a suggestion that the strategy could be improved by considering the impact of trading costs, which were not included in the backtest.

We could have got 41% from FTSE, here’s how — Python Backtesting #1

Backtesting of Trading Strategy with Technical Indicator #1

Want to trade? Better to backtest the idea first. With this series, I want to extend Python Financial Series into practical tasks. We will use all we have learnt from the previous Python series to backtest trading strategy based on technical indicators. If you haven’t gone through the previous Python series, please check the following series.

The Goal of the Series

I am planning to cover the following topics.

  • A simple long-short example: ONE technical indicator for ONE security
  • Add stop loss into our strategy
  • Re-factor the scripts into re-usable tools
  • Apply tools to generate trade ideas
  • Automate the trade signal with Cloud

I hope the topics sound exciting to you and let’s get started.

The Goal of the Session

In this session, we will use Keltner Channels (K-Band) as an example to test the long-short trading strategy with FTSE 100 ETF (ISF.L) for the year 2019. We will use the most vanilla to draft the scripts and in the future, we will improve it to more generic tools. Let’s get started!

1. Packages

Two essential things:

  • Data: we will use Yahoo Finance package, yfinance
  • Technical Analysis Tool: we will use Python package, ta

I am using Google Colab, which is one of the best online Jupyter Notebook environment (in my own opinion), so I will install the packages with “!” following with pip install command. If you are using your local environment, just need to install two packages above accordingly.

Except for yfinance and ta, we need Pandas and datetime.

2. Data

We need the data for backtesting, but beforehand, let’s set up some basic context variables (It is good practice using less magic string/numbers and using variables instead).

To find the ticker, you may search within Yahoo Finance. In general, it is very similar to what we see from any of the trading platform symbols.

All technical indicators need historical series, so if we want to test from the beginning of the year 2019, we need to some buffer. In general, a one-year data buffer should be good enough.

Now, we can download the data using yfinance.

3. K-Band

It is very easy to compute the common technical indicators using the package ta. If you would like to see more time-series operations with Pandas and Numpy, please check the following article.

To learn more about K-Band, ChartSchool can be a good resource.

4. Trading Signals

To backtest the trading strategy, we need trading signals, i.e. the date to enter the long or short position and the date to exit the position. With K-Band, we can do the following.

Enter Long: when close cross below the K-Band lower bound

Enter Short: when close cross above the K-Band upper bound

Exit Position: when there’s an opposite signal

To do so, we first shift the close by one day, so that we can compare the previous close against current close. Then four columns are generated for the signals. In real-world, when we see the trading signals, we will only be able to trade the next day, so the trades will happen the day after, i.e. we need to shift the signals by one day.

5. Trade Simulation

Once we have the signals, we can start to simulate the trading. Let’s get the data needed to simulate the trades in the year 2019.

Three things to set up:

Initial Context: Start account balance, PnL (Profit and Loss) and positions.

Temporary Variables: the last signal indicating how to compute PnL, last price computing PnL and counter recording the days of trade.

Data to Analyze the Strategy: Trade dates, side, days, PnL, return and cumulative PnL.

We assume we will start with one million cash with no PnL and no existing position.

To simulate the trading, we will loop through the rows in the DataFrame (i.e. day by day) and simulate the daily operations according to the signals.

With DataFrame function “iterrows”, we can loop through the days. It provides the index of the row and the row itself, where we can use the column name to access the data within the row.

Within the loop, we will simulate the daily operations. Three operations we need to do.

Exit Position if there’s a signal to exit.

Enter Position if there’s a signal to enter

Compute daily PnL, count trade days and record it

Exit Position

There are two possibilities when we need to exit the existing position.

  1. If we are in a long position and we have the signal of exit long.
  2. If we are in a short position and we have the signal of exit short.

We will record the last signal with the Temporary Variable “last_signal” so that we can use it checking the conditions.

No matter which situation we are in, we need to do three things.

  1. Compute the PnL of the trade and cash balance
  2. Record trade stats such as the end date, days of trading and PnL
  3. Reset the Temporary Variables such as trading day counter, position and last signal

The way to compute the PnL under either situation is the same. We also assume that we will use the Open price for trading (we will have the signal one day before). Notice, we used the Temporary Variables “last_price”, which we will record when entering the previous position.

The way to calculate the cash position will be different. For a long position, we sell the shares and take in the cash. We use the position and Open price to compute the market value and add that into the balance.

For a short position, we borrowed the shares and sold when entering the position, so we need to buy the shares back when exiting. In this case, we just need to update the balance with PnL.

In reality, we can leverage up dramatically, i.e. we could burn out all of our cash. Here we assume we will short with the fully funded approach.

Enter Position

There are two possibilities to enter a position.

  1. We enter a long position if we have long signal and we were not in a long position before.
  2. We enter a short position if we have short signal and we were not in a short position before.

For both situations, we need to record trade information, such as the last signal, last price, start date and trade side. We also need to reset the day counter to zero.

For long, we compute the possible number of share we can buy and compute the cost to deduct from the current balance.

For short, we just need to compute the number of shares we could borrow (we assume we can only borrow up to the cash balance we have). Because we borrow the shares, the position is negative.

Compute Daily Stats

Finally, we will compute the daily stats, such as daily PnL and trading day counts.

There are three possible situations.

  1. We are not in any position, nothing changes. Market value will be the cash balance we have.
  2. If we are in a long position, we then increase the day count by one and compute the market value. We use the position times the Close price plus the existing cash balance.
  3. If we are in a short position. we will increase the day count by one too. To compute the market value, we will calculate the PnL (difference of the Close price and last trading price times the positions). It will then increase or decrease the existing balance accordingly.

We also record the cumulative PnL by adding daily market value to the list we prepared at the beginning.

Put Thing Together

6. Backtest Results

Two things we may want to see.

  • Comparing with buy and hold strategy (i.e. do nothing), is our strategy getting us much more returns?
  • Is our strategy feasible? Will we have too many trades (i.e. increasing the trading cost)? Is the outperformance coming from one or two single trades (i.e. quality of the signal)?

Because we recorded the trades and cumulative PnL, we can answer those questions easily.

We can see in 2019, our K-Band trading strategy worked well for ISF.L, which is ETF for the FTSE 100 index. We had an annual return of 41.3% comparing with the buy and hold 14.25%. From the chart we, we can feel the trading strategy we have is not too volatile, which is a good sign, although, in the early days of the year, we had trades, so the PnL was flat.

Look into the trade stats, we will see more details. We can create a DataFrame to put all trade stats into one table.

From the table above, we can compute the following stats.

In total, we have 20 trades, 10 long and 10 short. All long trades yield positive returns and 80% of the short trades getting us wins. Due to the 2 loss trades of short, the average return of short trades is lower than long trades and the standard deviation is higher than long trades. However, within short trades, the average return of the winning trades is larger than the average loss, so in general, the signal is good for short trades too.

Can We Improve It?

We may, but need to try. In the next session, we will incorporate stop loss in our strategy. We may try to do a long-only strategy too and compare the strategies.

Project Git Link

Data Science
Investing
Python
Business
Programming
Recommended from ReadMedium