A Trading Strategy's Search For Profits

Designing a trading strategy from scratch can be time consuming. The debugging process alone could take days, even weeks. However, an easy solution is to take someone else's trading strategy that you find might have some merit, and transform it to your own specifications. Making it do what you want.

The Quantopian website offers the ability to clone stock trading strategies that have been made public by their authors. This way, one can use such strategies as some starting point. At least, these programs are debugged, operational, and might prove to have some code that you could use.

Quantopian is searching for a low drawdown stock trading strategy. Its stated goal being to margin it as high as 6 times. The restriction being a close to zero beta and low volatility portfolio.

The presented strategy is marginally acceptable. Its beta is 0.38 compared to the stated limit of $\pm$ 0.30. Also, the drawdown is higher than wished for. However, there are attenuating circumstances.

Evidently, if you want to margin 6 times, the drawdown figure better be small. Six times a small drawdown near 0.10 (Quantopian's limit), will still be something close to 0.60. Hopefully less, but still, tending to it.

There are other ways of doing this.

For instance, the following strategy can do the job, however, in a different way.

The Spy Who Loved WVF (or Just Another Volatility Spy Strategy)

This trading strategy is not mine. People on Quantopian should recognize it. I do not know exactly who the original author is. I do not have its history. All I did was clone it, and started changing parameters to see how it behaved.

I usually go for the pressure points. Not necessarily changing the code, but to see if the trading strategy is scalable for instance. And if so, how much. The only way to find out is to make some tests.

So here is that strategy, which I consider a diamond in the rough, that can do more simply by adding some pressure to it. The first observation being that the strategy can in fact handle the added pressure.

For sure, if you want more profits, you will have to take more risk. It is an understated market axiom. You want more, then you will have to do more. Evidently, all within the restrictions you might set.

I use the following strategy version: https://www.quantopian.com/algorithms/58954885a7d6014540d54cbd (log in free to have access).

This particular trading strategy is a modification of a modification. The last one of which was done by T. W. I made some minor changes. Not in the code, but for some of the parameters.

I wanted to know if it scaled upward well. That was easy to do, I simply raised the initial capital to \$ $\textbf{1,000,000}$. I also wanted to know if it could survive some leverage. Since Quantopian has for intention to leverage some of their systems. Might as well find out how far this one could go.

Leverage

I limited leverage at 2 times. It was sufficient since some of the ETFs used have 3 times leverage. Operated in this fashion, it would give the equivalemt of a 6 times leveraged portfolio.

Test Results

Test Settings: From 2011-01-03 to 2017-02-02 with \$ $\textbf{1,000,000}$ initial capital.

Total Returns: 8,642.1%

Benchmark Returns: 103.5%

Alpha: 0.78

Beta: 0.38

Sharpe: 1.91

Sortino: 2.99

Volatility: 0.43

Max Drawdown -27.5%

Those might appear as ordinary numbers, but not quite.

If Quantopian is ready to leverage 6x a less than 10% drawdown strategy. Here is one that is less than 30% and able to generate a much higher output.

Sure it might appear more risky. Maybe, and then again, maybe not. Nonetheless, this is a first draft, a preliminary exploration into what makes this strategy tick.

Here is the strategy's full tear sheet.

In [2]:
# Get backtest object
bt = get_backtest('5895445a1b4cb74460004852')

# Create all tear sheets
bt.create_full_tear_sheet()
100% Time: 0:00:01|###########################################################|
Entire data start date: 2011-01-03
Entire data end date: 2017-02-02


Backtest Months: 72
Performance statistics Backtest
annual_return 1.09
annual_volatility 0.43
sharpe_ratio 1.91
calmar_ratio 3.95
stability_of_timeseries 0.98
max_drawdown -0.27
omega_ratio 1.41
sortino_ratio 2.99
skew 0.19
kurtosis 3.33
tail_ratio 1.14
common_sense_ratio 2.38
information_ratio 0.10
alpha 0.79
beta 0.37
Worst Drawdown Periods net drawdown in % peak date valley date recovery date duration
0 27.50 2016-07-08 2016-11-14 2017-01-24 143
1 21.41 2015-02-02 2015-03-11 2015-04-10 50
2 20.26 2013-08-05 2013-10-15 2014-01-15 118
3 19.75 2013-05-02 2013-06-24 2013-07-15 53
4 17.84 2011-10-03 2011-10-14 2012-01-03 67

[-0.051 -0.099]
/usr/local/lib/python2.7/dist-packages/numpy/lib/function_base.py:3834: RuntimeWarning: Invalid value encountered in percentile
  RuntimeWarning)
Stress Events mean min max
US downgrade/European Debt Crisis 2.05% -11.68% 14.76%
Fukushima 0.24% -3.46% 4.48%
EZB IR Event 0.07% -6.52% 7.25%
Apr14 0.69% -7.81% 4.35%
Oct14 0.45% -4.82% 4.47%
Fall2015 0.02% -9.33% 6.40%
Recovery 0.45% -11.68% 14.94%
New Normal 0.27% -11.33% 13.41%
Top 10 long positions of all time max
TMF-38294 146.60%
IWM-21519 146.49%
IJH-21507 142.57%
XIV-40516 133.39%
TLT-23921 62.02%
SSO-32270 60.80%
TQQQ-39214 60.76%
UPRO-38533 56.32%
Top 10 short positions of all time max
Top 10 positions of all time max
TMF-38294 146.60%
IWM-21519 146.49%
IJH-21507 142.57%
XIV-40516 133.39%
TLT-23921 62.02%
SSO-32270 60.80%
TQQQ-39214 60.76%
UPRO-38533 56.32%
All positions ever held max
TMF-38294 146.60%
IWM-21519 146.49%
IJH-21507 142.57%
XIV-40516 133.39%
TLT-23921 62.02%
SSO-32270 60.80%
TQQQ-39214 60.76%
UPRO-38533 56.32%

CAGR

Those are impressive numbers. Total, it is a $\textbf{68.97%}$ CAGR over the 6 years trading interval. I know 6 years is not that long, but it still shows what the trading strategy can do.

$\textsf{The returns tear sheet}$ follows as if with a 37 months of out-of-sample data.

In [3]:
bt.create_returns_tear_sheet(live_start_date='2014-1-1')
Entire data start date: 2011-01-03
Entire data end date: 2017-02-02


Out-of-Sample Months: 37
Backtest Months: 35
Performance statistics All history Backtest Out of sample
annual_return 1.09 1.21 0.97
annual_volatility 0.43 0.46 0.41
sharpe_ratio 1.91 1.97 1.86
calmar_ratio 3.95 5.99 3.53
stability_of_timeseries 0.98 0.92 0.97
max_drawdown -0.27 -0.20 -0.27
omega_ratio 1.41 1.43 1.38
sortino_ratio 2.99 3.19 2.80
skew 0.19 0.41 -0.12
kurtosis 3.33 3.85 2.37
tail_ratio 1.14 1.26 1.05
common_sense_ratio 2.38 2.80 2.07
information_ratio 0.10 0.10 0.11
alpha 0.79 0.88 0.71
beta 0.37 0.12 0.75
Worst Drawdown Periods net drawdown in % peak date valley date recovery date duration
0 27.50 2016-07-08 2016-11-14 2017-01-24 143
1 21.41 2015-02-02 2015-03-11 2015-04-10 50
2 20.26 2013-08-05 2013-10-15 2014-01-15 118
3 19.75 2013-05-02 2013-06-24 2013-07-15 53
4 17.84 2011-10-03 2011-10-14 2012-01-03 67

[-0.051 -0.099]

Performance

From its \$ $\textbf{1,000,000}$ debut, the strategy reached \$ $\textbf{87,420,612}$ in six years!

There are reasons for this high level of achievement. And they were built-in the code. All I did was push on the levers, the pressure points of the strategy. I gave it some steriods. Made it follow the equation: $$ A(t) = A(0) + (1+g)^t \cdot n \cdot u \cdot \overline{PT}$$

At anytime, one could have called it quits, and receive the portfolio's net liquidating value.

The Bayesian tear sheet:

In [4]:
bt.create_bayesian_tear_sheet(live_start_date='2014-1-1')
Running T model
 [-----------------100%-----------------] 2000 of 2000 complete in 3.0 sec
Finished T model (required 35.86 seconds).

Running BEST model
 [-----------------100%-----------------] 2000 of 2000 complete in 6.8 sec
Finished BEST model (required 45.96 seconds).

Finished plotting Bayesian cone (required 0.72 seconds).

Finished plotting BEST results (required 0.88 seconds).

Finished computing Bayesian predictions (required 0.17 seconds).

Finished plotting Bayesian VaRs estimate (required 0.07 seconds).

Running alpha beta model
 [-----------------100%-----------------] 2000 of 2000 complete in 3.0 sec
Finished running alpha beta model (required 27.76 seconds).

Finished plotting alpha beta model (required 0.19 seconds).

Total runtime was 111.59 seconds.
/usr/local/lib/python2.7/dist-packages/matplotlib/axes/_axes.py:519: UserWarning: No labelled objects found. Use label='...' kwarg on individual plots.
  warnings.warn("No labelled objects found. "

Conclusion

This goes to say that if you have a working trading strategy, it can do more. And it is easy to push for more. I hope, this does illustrate my point.

Any trading strategy can be expressed as: $$ A(t) = A(0) + n \cdot u \cdot \overline{PT}$$ All I did was add some pressure: $$ A(t) = A(0) + (1+g)^t \cdot n \cdot u \cdot \overline{PT}$$

And, it was sufficient to achieve more. All that was required was to have $g>0$. You can find all this stuff, and more, in my latest book: http://www.amazon.com/dp/B01MYCRVEG

Hope it helps.