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)
http://papers.ssrn.com/sol3/papers.cfm?abstract_id=2759734
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 context.safe = [sid(23870)] #IEF