CPPI backtest: methodology
The CPPI backtest tests a portfolio insurance strategy on real prices: a multiple of the cushion above a lower limit, the floor, is always invested in equities, and the rest is held safely in bonds and cash. This methodology describes what the code calculates: the rule, the floor, review dates, costs, gap risk and the comparison strategies. The idea and the research behind it are covered in the article CPPI.
The rule: cushion times multiplier
Black and Jones (1987) described the rule as a simplified form of portfolio insurance, and Black and Perold (1992) worked out the theory behind it. It needs two numbers: the floor F, the value that should not be undercut, and the multiplier m. The distance between the portfolio value V and the floor is called the cushion. On each review date, m times the cushion is invested in equities, and the rest is held safely:
E = min(max(m × (V − F); 0); leverage limit × V); S = V − E; B = bond share × S; C = V − E − B- V
- portfolio value
- F
- Floor
- V − F
- cushion
- m
- multiplier, default 4 (allowed 0.5 to 20)
- leverage limit
- maximum equity share, default 100% (allowed 10 to 300%)
- E, B, C
- amounts in the equity, bond and cash parts; S is the safe remainder
- bond share
- share of the safe remainder held in bonds, default 50%; the rest is held in cash
If m × cushion is greater than leverage limit × V, the equity position is capped there; with the default of 100%, the whole portfolio is then in equities. If the cushion is zero or negative, E = 0 and everything is held safely. With a leverage limit above 100%, E can become larger than V: the cash part turns negative, i.e. becomes a loan, and costs the cash return plus a spread per period (default 1% p.a., converted to the period by calendar days).
Three parts: equities, bonds and cash
Each part is a value series. The equity part, i.e. the risky part, is a portfolio from the grid or a single ticker or asset class. The bond part is likewise a portfolio or a ticker (by default the asset class 10-year German government bonds) or none, in which case the entire safe remainder is held in cash. The code calculates portfolios from the grid as in the backtest, with the chosen rebalancing within the portfolios: none, monthly (default), quarterly, semi-annually or annually, each on the last trading day of the period (quarterly in March, June, September and December), or with a tolerance band (default ±5 percentage points, allowed 1 to 50). With a tolerance band, the code checks every period and resets all weights as soon as one deviates from its target by more than the band. It calculates the costs for this at the same rate as for shifts between the parts, as rate × amount traded, and deducts them from the part's return; the purchase at the start costs nothing. For the cash part, there are three options:
- Money market, time-varying (default): the money market rate of the base currency over time; for the US dollar (the default), the 3-month Treasury bill rate; for the euro, €STR, before that EONIA and before that overnight money in Frankfurt. Before the rate series begins, or without rate data, the fixed fallback rate from the settings applies.
- Fixed rate: a rate p.a. (default 2%), converted per period by calendar days: (1 + rate)^(days / 365.25) − 1.
- Ticker: the value series of a money market fund.
All parts are brought onto their common history and the data frequency of the settings, i.e. month-ends or daily prices. Asset classes only provide monthly values; if one is included, the page calculates monthly. At least 13 common periods are needed. The return of the first period does not count, because that is where every strategy starts with 10,000.
The floor: start, growth and ratcheting
The floor starts at floor share × starting value (default 80%, allowed 0 to 99%). After that, it develops according to one of three rules:
| Setting | Floor per period | Idea |
|---|---|---|
| Fixed (default) | stays the same | fixed amount in the base currency |
| With the cash rate | F × (1 + cash return for the period) | like a zero-coupon bond that accrues at the money market rate |
| Fixed rate | F × (1 + rate)^(days / 365.25) | lower limit with a minimum interest rate |
In addition, the floor can be ratcheted up so that gains are locked in. It never falls in the process, except when a guarantee period restarts:
- TIPP (time invariant portfolio protection after Estep and Kritzman (1988)): the floor is never lower than a share of the highest portfolio value so far (default 80%). This applies from the start and after every restart.
- Lock-in: if the value has risen by one step since the last ratchet or since the start (default 10%), the floor rises to the chosen share of the then current value. Gains are thus locked in step by step.
- Guarantee period: after the chosen number of years, a new period begins. The floor is set to floor share × current value (with TIPP, at least to the TIPP share), and the high and the lock-in reference value start afresh. 0 years means continuous.
Rebalancing between the parts: review dates, tolerance band and costs
Money is only shifted between the equity, bond and cash parts on review dates: every period of the data, weekly, monthly (default), quarterly, semi-annually or annually, each on the last trading day of the week, month, quarter, half-year or year; the start day does not count. On the page, this is called “Rebalancing between the parts”. With monthly data, “weekly” becomes “every period”, i.e. monthly. Between review dates, the three parts grow with their own returns; the code nevertheless updates the floor, the high and the ratchet every period.
On a review date, the code recalculates the target split and only trades if the target equity position deviates from the one held by more than the tolerance band (default 5% of V, allowed 0 to 50%), or if V is at or below the floor and equities are still held. It then sets all three parts to the target.
trade if |E_target − E| / V > band or (V ≤ F and E > 0); costs = cost rate × (|E_target − E| + |B_target − B|)- cost rate
- per amount traded in equities and bonds, default 0.1% (allowed 0 to 2%); cash movements cost nothing
- costs
- are paid from the cash part and reduce V; the purchase at the start is free for all strategies
Gap risk, floor breach and cash lock
Cont and Tankov (2009) show that with continuous trading and no price jumps, the strategy would carry no risk of falling below the floor; in real markets, this risk is not negligible and grows with the multiplier. If the equity part falls by the fraction d between two review dates, the cushion shrinks to (1 − m × d) times its size, provided the equity position matched the target beforehand and the safe part stays the same. From d = 1/m onwards, it is used up.
cushion after the crash = cushion × (1 − m × d); used up from d = 1 / m- d
- price decline of the equity part up to the next review date
| Multiplier m | Crash that wipes out the cushion |
|---|---|
| 2 | 50% |
| 3 | 33.3% |
| 4 | 25% |
| 5 | 20% |
| 6 | 16.7% |
The code counts every period in which V is below F (measured before rebalancing) as a floor breach, and consecutive periods as one episode, and reports the largest gap as the smallest value of V / F − 1. After a breach, everything is held safely. If the floor is fixed, the strategy only gets back into equities once the safe part has lifted the value above the floor. If the floor grows with the cash rate, this only happens if bonds return more than cash. If the safe part is held entirely in cash, it never happens. This state without equities is called a cash lock; the page shows the share of periods with an equity share below 1%.
With monthly data, crashes within a month remain invisible: the page only sees the month-end price and underestimates the gap risk. With daily prices (settings) and daily or weekly review dates, it shows up more accurately.
Comparison strategies
Alongside the CPPI, the page calculates three strategies with the same parts, all with a starting value of 10,000 and a free purchase at the start:
- Constant mix: the CPPI's starting split (with the defaults, 80% equities, 10% bonds, 10% cash), reset to these weights on every review date without a tolerance band, with the same cost rate on the equities and bonds traded.
- Buy-and-hold of the equity part: 100% in the risky part, never rebalanced, without costs.
- Bond benchmark, named after the bond part (without a bond part, cash benchmark): the safe part on its own, i.e. bonds and cash in the chosen ratio, reset on the review dates, with costs.
The comparison with the constant mix shows the core of the strategy. Perold and Sharpe (1988) distinguish linear strategies (buy-and-hold), concave ones (constant mix) and convex ones (portfolio insurance). CPPI is convex: it comes out ahead in long trends, upwards as well as downwards, and loses in markets that swing back and forth without a direction. There, the constant mix wins. The calendar years in the results make this visible.
Results and path metrics
For all four strategies, the page shows the final value, return p.a., volatility, maximum drawdown, Sharpe ratio and the other metrics as in the backtest, with buy-and-hold of the equity part as the comparison index. In addition, there is the value over time with the floor, drawdowns and calendar-year returns, as well as:
- Allocation: the shares of equities, bonds and cash in the value after rebalancing; equities above 100% appear as a negative cash share. The page shows series with more than 3,000 points at weekly intervals.
- Cushion and equity share: cushion = (V − F) / V and equity share = E / V per period; the equity share is roughly m × cushion, capped.
- Path: current shares, cushion, floor and value, average equity share with its range, share of periods without equities, number and costs of the rebalancing trades, how often the floor was ratcheted (with TIPP every increase, with lock-in every step), restarts, floor at the beginning and at the end, floor breaches in periods and episodes, and the largest gap.
Limitations
- No guarantee: the floor is a calculated quantity. A real guarantee depends on the creditworthiness of whoever gives it. In the backtest, there is no such party.
- Monthly data hide gaps: with monthly values, the page does not see price crashes within a month.
- Trading at the closing price: rebalancing takes place at the closing price of the review date, without any price impact from your own trading. In periods of stress, this is optimistic.
- No taxes: in practice, sales at a profit would trigger taxes and shrink the cushion; the page does not calculate them.
- Path dependence: the result depends heavily on the start date. A different start can trigger or avoid a cash lock.
Frequently asked questions
Why is the value sometimes below the floor?
Because money is only shifted on review dates. If the equity part falls by more than 1/m in between, the cushion is used up before the rule can sell. The page counts these periods as floor breaches and shows the largest gap.
What does cash lock mean?
After a crash to the floor, everything is in the safe part. If the floor grows with the interest rate, the strategy can hardly get back into equities on its own and misses the recovery. The page shows in how many periods the equity share was below 1%.
What is the difference between TIPP and lock-in?
TIPP ratchets the floor up to a fixed share of every new high. Lock-in only ratchets it up when the value has risen by one step since the last ratchet, say 10%. Neither floor ever falls, except when a guarantee period restarts.
Why does CPPI buy after price gains?
When the value rises, the cushion above the floor grows, and with it the m-fold amount in equities. After losses it shrinks, and the rule sells. This makes CPPI the opposite of a constant mix, which sells after gains.
How does the page calculate trading costs?
The cost rate applies to the amount traded in equities and bonds; cash movements are free. The costs are deducted from the cash part. The same rate applies to rebalancing within the portfolios from the grid; these costs reduce the return of the part. The purchase at the start costs nothing for any strategy.
Literature
- Black, Fischer; Jones, Robert W. (1987): Simplifying portfolio insurance. The Journal of Portfolio Management 14 (1), pp. 48–51. doi:10.3905/jpm.1987.409131
- Black, Fischer; Perold, André F. (1992): Theory of constant proportion portfolio insurance. Journal of Economic Dynamics and Control 16 (3-4), pp. 403–426. doi:10.1016/0165-1889(92)90043-E
- Cont, Rama; Tankov, Peter (2009): Constant Proportion Portfolio Insurance in the Presence of Jumps in Asset Prices. Mathematical Finance 19 (3), pp. 379–401. doi:10.1111/j.1467-9965.2009.00377.x
- Estep, Tony; Kritzman, Mark (1988): TIPP: Insurance without complexity. The Journal of Portfolio Management 14 (4), pp. 38–42. doi:10.3905/jpm.1988.409172
- Perold, Andre F.; Sharpe, William F. (1988): Dynamic Strategies for Asset Allocation. Financial Analysts Journal 44 (1), pp. 16–27. doi:10.2469/faj.v44.n1.16
This page describes how Portfolio Lab calculates; past results are not a forecast. All terms in the glossary.