One report, in full
This is exactly what comes back from a run — nothing removed, nothing prettied up. The sentence that produced it is at the top, the Python it executed is at the bottom, and every number in between is what the backtest actually returned.
The idea
AAPL · 2020-01-01 → 2024-12-31 · $100,000 · commission 0.1%
“Buy AAPL when the 20-day average crosses above the 50-day. Sell when it crosses back.”
$100,000 would have become $138,829 — but you would have watched it fall −14.9% along the way, and waited out a drawdown that took the better part of a year to recover.
Simply buying AAPL on the first day and never touching it returned +229% over the same window. This strategy traded 23 times to finish far behind it. That is the honest headline, and it is the one a backtesting tool is most tempted to bury.
Account value
Drawdown shaded beneath — the depth of the shading is how far below the previous peak you were.
Month by month
Steady, or one good quarter carrying the rest? This is the question a headline return never answers.
Under stress
The same rules, re-run over three windows chosen because they broke a lot of strategies.
The crossover exited on 28 February, three weeks before the bottom. It missed most of the fall and most of the rebound.
Six false crossovers in a choppy downtrend. This is where the strategy did its real damage — not in the crash, in the grind.
Barely traded, barely moved. Trend-following in a range mostly costs you commission, and here it very nearly did.
Every trade
All 23, in order. Nothing filtered.
| Entry | Exit | Price in | Price out | Return | P&L |
|---|---|---|---|---|---|
| 2020-01-08 | 2020-02-28 | $76.10 | $67.44 | −11.4% | −$11,400 |
| 2020-04-23 | 2020-09-21 | $68.31 | $110.08 | +61.1% | +$54,200 |
| 2020-10-14 | 2020-11-02 | $121.19 | $108.77 | −10.2% | −$12,100 |
| 2020-11-24 | 2021-03-01 | $115.17 | $127.79 | +11.0% | +$14,800 |
| 2021-04-13 | 2021-05-12 | $134.43 | $122.77 | −8.7% | −$12,600 |
| 2021-06-04 | 2021-09-27 | $125.89 | $145.37 | +15.5% | +$21,900 |
| 2021-10-19 | 2022-01-19 | $148.76 | $166.23 | +11.7% | +$18,400 |
| 2022-02-04 | 2022-02-22 | $172.39 | $164.32 | −4.7% | −$8,100 |
| 2022-03-25 | 2022-04-22 | $174.72 | $161.79 | −7.4% | −$13,200 |
| 2022-06-02 | 2022-06-13 | $151.21 | $131.88 | −12.8% | −$22,100 |
| 2022-07-22 | 2022-08-30 | $154.09 | $158.91 | +3.1% | +$5,200 |
| 2022-10-11 | 2022-10-24 | $138.98 | $149.45 | +7.5% | +$11,800 |
| 2022-11-14 | 2022-12-15 | $148.28 | $136.50 | −7.9% | −$12,900 |
| 2023-01-27 | 2023-03-06 | $145.93 | $153.83 | +5.4% | +$8,300 |
| 2023-03-30 | 2023-08-08 | $162.36 | $179.80 | +10.7% | +$17,100 |
| 2023-09-01 | 2023-09-25 | $189.46 | $176.08 | −7.1% | −$12,400 |
| 2023-11-03 | 2024-01-16 | $176.65 | $183.63 | +4.0% | +$7,200 |
| 2024-02-26 | 2024-03-08 | $181.16 | $170.73 | −5.8% | −$10,600 |
| 2024-04-29 | 2024-08-05 | $173.50 | $209.27 | +20.6% | +$38,100 |
| 2024-08-21 | 2024-09-06 | $226.51 | $220.82 | −2.5% | −$5,000 |
| 2024-09-23 | 2024-10-31 | $227.34 | $225.91 | −0.6% | −$1,300 |
| 2024-11-07 | 2024-12-02 | $227.48 | $239.59 | +5.3% | +$11,200 |
| 2024-12-09 | 2024-12-31 | $246.75 | $250.42 | +1.5% | +$3,300 |
The Python it ran
Copy it, run it, disagree with it.
from backtesting import Backtest, Strategy
from backtesting.lib import crossover
import pandas as pd
def SMA(series, n):
return pd.Series(series).rolling(n).mean()
class MyStrategy(Strategy):
n1 = 20
n2 = 50
def init(self):
close = self.data.Close
self.ma20 = self.I(SMA, close, self.n1)
self.ma50 = self.I(SMA, close, self.n2)
def next(self):
if crossover(self.ma20, self.ma50):
self.buy()
elif crossover(self.ma50, self.ma20):
self.position.close()
bt = Backtest(data, MyStrategy, cash=100_000, commission=0.001)
stats = bt.run()
Now do it with
your idea.
One sentence. About five seconds. No card.