Back to Community
Implementation of Keller and Keunig's Protective Asset Allocation (PAA)

Motivated by Simon Thornington's "Trading Strategy Ideas thread"I took the time to implement the following paper.

"Protective Asset Allocation (PAA): A simple momentum-based alternative for term deposits" based on Keller and Keuning (April 25, 2016)

The overall strategy and some mods that I made are described below.

Strategy goal:
- Average, unleveraged return better than SP500 (achieved)
- Significantly reduced drawdown vs SP500 (achieved)
subject to constraints:
- Monthly rebalancing

PAA strategy summary
1. consider a proxy set of N assets
2. select a protection factor (see below) and maximum number of assets to hold (TopN)
3. count the number (n) of the proxy assets with positive prior month MOM (see MOM definition below)
4. compute the bond fraction (BF): BF = (N-n)/(N-n1). (see n1 definition below)
5. Invest a fraction BF of the portfolio into the safe set (bonds)
6. From a set of equities (may be same as proxy set) invest the remaining fraction (1-BF) in the top n_eq equities sorted on MOM
7. Hold for one month and then repeat to rebalance

Definition of terms used by Keller and Keunig
- momentum (MOM): to be MOM = (last month's close)/(SMA over lookback period) - 1
- lookback period (L): L is measured in months
- protection factor (a): a = [0, 1, or 2] is used to adjust the BF gain: n1 = a*N/4
- number of equities to be purchased (n_eq): n_eq = min(n,topM)

Significant changes vs Keller and Keunig:
a) bond fraction is forced to fall on n_levels discrete values from 0.0 to 1.0
b) safe set = [IEF, TLT]
c) the separate equity sets are defined for the proxy and investing functions

Lingering concerns
This strategy (like all monthly rotation strategies that I've tried) has two problems:
- periods of greater than one year in which there is no net return
- significant sensitivity to day of month used to form the investment set or to trade

Note: If you want to approximate the author's original results then
- set context.n_levels to a large value, perhaps 100,
or comment out "bond_fraction = np.floor(bond_fraction*n_steps)/n_steps"
- set context.equities = context.proxies
- set = [sid(23870)] #IEF

Clone Algorithm
Backtest from to with initial capital
Total Returns
Max Drawdown
Benchmark Returns
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 57c0a9a8ba6be6100f0489b9
There was a runtime error.
3 responses

Thank you for sharing this. It seems like a great algo for relatively safe returns with little drawdown.

Its max draw down was 26%. Not sure how much I consider it a "safe" asset from that point of view. As a constant maturity scheme I guess it will be fine long term in a rising interest rate environment but a "safer" set might perhaps be IEF and SHY.

I can't argue that IEF/SHY is safer.
Given the spirit of the strategy I probably should have posted a lower draw down back test.
From my notes it is clear that I encountered some as low as 10%.

Fortunately this type of strategy allows others much freedom to adjust sets and settings.