How does one go about properly backtesting and visualising their strategy using their trading signals and historical prices where the trading signals are 1 for long, 0 for no position -1 for short?

Obviously the end result should look something like this, this visual originates from a simple moving average strategy from "Python for Finance" enter image description here

My strategy is not the same however since the trading signals are just 1s and -1s I would expect to be able to get a similar result, however when I try using the following code, I get the following graph, and I have absolutely no idea why.

data['XONRETURNS'] = np.log(data['XON'] / data['XON'].shift(1))  
data['XONSTRATEGY'] = (data['POSITIONXON'].shift(1)) * (data['XONRETURNS'])
ax = data[['XONRETURNS', 'XONSTRATEGY']].cumsum().apply(np.exp).plot(figsize=(10, 6))

XON is simply the raw price data and XON strategy is using the trading signals i.e. POSITIONXON. enter image description here

My suspicion is that either the returns or something relating to taking the log(or not) is causing this issue?

General answers on backtesting from trading signals will also be very helpful so that I can start from scratch if need be.

Many thanks!

  • $\begingroup$ 1. Debug by looking at simple cases. For example, make every data['POSITIONXON'] equal to 1, what happens then? 2. Have you checked that every POSITIONXON is 1,0 or -1? I strongly suspect you have some other values in there 3. Looks like the green line plunges to 1 (which is exp(0)) at every calendar month end. Which suggests a data/input issue of some kind. Look at the data and krank through some calculations manually. $\endgroup$
    – nbbo2
    Apr 22, 2022 at 9:48

1 Answer 1


There's plenty of open source code out there that can point you in the right direction.

  • Moonshot is a vectorized backtester developed by QuantRocket that uses 1, -1, and 0 for signals. The base.py module has functions that turn DataFrames of signals into positions and positions into returns.
  • Moonchart is an accompanying visualization library. Check out the utils.py module for an example of turning a Series or DataFrame of returns into cumulative returns.
  • Empyrical is another library with similar utility functions as Moonchart for calculating cumulative returns, Sharpe ratio, CAGR, etc. It was developed by the now-defunct company Quantopian. Check out the stats.py module for most of the core functions.
  • Empyrical is used as a helper library by Pyfolio, a visualization library that was also developed by Quantopian.

All of these packages are based on standard Python data science libraries (pandas, numpy, matplotlib, etc). You probably don't need to install the packages themselves but can just lift relevant snippets of code that show how to calculate the various performance metrics.

  • $\begingroup$ Yes, but my actual question should be able to solved with just matplotlib and pandas. This answer is pretty irrelevant to my actual issue and is just introducing more complexity to what should be a fairly simple fix. $\endgroup$
    – ffff22222
    Apr 21, 2022 at 18:56
  • 4
    $\begingroup$ Your own words: "General answers on backtesting from trading signals will also be very helpful." $\endgroup$ Apr 22, 2022 at 0:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.