Quant from Scratch by QuantWright

Introduction to Quant Finance · Lesson 21

What is a backtest?

One rule, five made-up markets. What a backtest does, and the three things to look at in one.

Know the basics? Read the lesson notes

A market and a rule

A market is anything with a price you can buy and sell, like a share in a company. Each day the price ends a little higher or a little lower than the day before. A day it ends lower is a down day. A day it ends higher is an up day.

A trading rule is a fixed instruction for when to buy and when to sell. Here is the one we'll use:

The ruleAfter 3 down days in a row, buy at the end of the third one. Sell at the end of the 5th day after the buy. While a trade is open, don't start another.

Below are the first 24 days of a market we made up, called market A. Tap the day the rule first buys.

Made-up market A, days 1 to 24 (simulated, not a real market)

Each square is one day. Filled: a down day. Empty: an up day.

Days 18, 19 and 20 are all down, so the rule buys at the end of day 20. Earlier on, days 1 and 2, 12 and 13, and 15 and 16 were down too, but only two in a row each time.

One trade

The buy and the sell together make one trade. Each trade spends $10,000 buying at the buy and gets back whatever that has become at the sell. What came back minus what went in is the trade's result.

This trade bought at the end of day 20 and sold at the end of day 25. Of the 5 days it held, 4 were down. A square shows which way a day went, not how far.

Made-up market A, days 18 to 25 (simulated)

Filled: down day. Empty: up day. Ringed: the buy and the sell. Orange bar underneath: the 5 days the trade is held, 21 to 25.

Did this trade make money or lose money?

The squares can't tell you that: one big up day can outweigh four small down days.
Likely, but the squares can't settle it: one big up day can outweigh four small down days.
Right: the squares show which way each day went, not how far.
Four down days out of five makes a loss likely, but only the sizes settle it. Here $10,000 went in and $9,708 came out: $9,708 − $10,000 = −$292. (There are no fees in this lesson: fees are small charges the company that places your trades takes on each one. A later lesson adds them.)

The backtest walks on, day by day

A backtest checks a rule on past days before you risk real money. Here we invent the history, so we know exactly what is in it: random days with a tiny steady rise built in, nothing the rule could know in advance. A backtest runs the rule over past days as if you had traded back then. It moves forward one day at a time, using only the days so far, and writes every trade into a list: the trade list.

Press Play to run the first 48 days. Watch days 21 to 23: that's the rule's last part, one trade at a time, at work.

The rule on made-up market A, days 1 to 48 (simulated)

Filled: down day. Empty: up day. Ringed: a buy or a sell. Orange bar underneath: the days a trade is held, from the day after the buy to the sell day.

Day 0
TradeBought (day)Sold (day)Result
No trades yet

Three trades in 48 days, and all three lost. Days 21 to 23 were three more down days in a row, but a trade was already open, so the rule waited.

A sell day can also be a down day: day 25 ended the first trade and counts toward the next run of three (25, 26, 27).

The backtest doesn't stop at day 48. Our made-up market runs for 10 years: 2,520 trading days.

Will this account end up or down?

Now give the rule an account that keeps score. It starts at $10,000. Each time a trade closes, the trade's result is added. After the three trades you just watched, it's at $9,295: $10,000 − $292 − $296 − $117.

Every trade puts in the same $10,000, whatever the account shows, so the account is only a running score: it adds up the results. The backtest will now run all 10 years. Where do you think the account ends?

Keep that guess. On the next screen you run it.

The account line

Press Play. As each trade closes, its result is added to the account, and the chart draws the account after every trade. That line is the account line.

Made-up market A, 10 years: the account after each trade (simulated)

Account in dollars. The dashed line is the $10,000 start. A made-up market, not a real one.

TradeBought (day)Sold (day)ResultAccount
Press Play
Trades0
Made money0
Lost money0
Account$10,000

The end number alone would hide that early dip. The account line shows the whole way there.

One market, or five?

So far, one made-up market. We made four more, B to E, in exactly the same way, and ran the same rule on each: 3 down days in a row, sell 5 days later.

Market A ended at $14,662. How many of the five markets end above $10,000?

Run them on the next screen and see.

Five markets

Each small chart is one market's account line over the same 10 years, drawn to the same scale. Press Run.

The same rule on five made-up markets (simulated)

Account after each trade, 10 years. Dashed: the $10,000 start.

Ended above $10,000–
Best–
Worst–

The catch: we made these markets random

We built each market by drawing every day's move at random, like a roll of dice, with a small rise built in: 0.03% a day on average. A typical day moves about 1.2% up or down, 40 times that rise. Today's move has nothing to do with yesterday's, so three down days in a row say nothing about the next five. There is no pattern here for any rule to find.

Then why did four end higher? Every day a trade is open, it collects that built-in rise: $10,000 × 0.03% × 5 days ≈ $15 a trade. Over about 140 trades a market on average, that is about 140 × $15 = $2,100. Press the button to compare it with what the five made.

Five made-up markets, one chart (simulated)

Grey: each market's account line. The dashed line is the $10,000 start.

The rise alone, average of the five?
What they made, average of the five?

The rule found nothing. It collected the rise, and each market's own random days pushed it up or down from there.

So why did B lose half?

Market B ended at $4,923, about half of its $10,000 gone. Market C ended at $16,302. Why so different?

All five ran the same rule with the same setting. The only difference between them is which random days each one drew.
C was made the same way as the others, with no pattern in it. The only difference between the markets is which random days each one drew.
Same rule, same setting, markets made the same way. A day's move swings about 1.2% either way, 40 times the rise, so the random days each market drew after its buys decide most of its result: B drew more falling ones, C more rising ones.
B was the unluckiest of the five. One market alone can make a rule look great or terrible, with nothing there. That's why a test runs on many markets, and you read them together.
Theory

The recipe of every backtest

Every backtest has the same parts:

Two formulas follow. The first is the result of one trade, r: a dollar amount, not a percentage. The second is the account after k trades, Ak: the start plus every result so far. It just adds results, with no compounding, because S stays fixed. The part Psell ÷ Pbuy − 1 is the trade's percentage return: how much the price moved, as a share of the buy price.

r = S × (Psell ÷ Pbuy − 1) − c
Ak = A0 + r1 + … + rk
r
the result of one trade, in dollars (not a percentage)
S
the position size: dollars put into the trade
Pbuy, Psell
the price at the buy and at the sell
c
the costs of that trade (zero in this lesson)
A0
the account at the start
r1 … rk
the first trade's result, the second's, and so on up to the k-th
Ak
the account after k trades: one point of the account line
Worked example

Market A's first trade: S = $10,000 and $9,708 came back, so Psell ÷ Pbuy = 9,708 ÷ 10,000 = 0.9708 (results are rounded to whole dollars). With c = 0: r = 10,000 × (0.9708 − 1) − 0 = −$292.

After three trades: A3 = 10,000 − 292 − 296 − 117 = $9,295.

With real prices and costs (made-up numbers): S = $2,000, buy at $50, sell at $52, c = $4. The percentage return is 52 ÷ 50 − 1 = 0.04 (4%), so r = 2,000 × 0.04 − 4 = 80 − 4 = $76.

Holds when
  • each trade could really fill at the price shown;
  • each trade puts in the same S, however the account stands;
  • the costs are what they would really be;
  • the rule uses only what was known on that day, nothing from later.
Breaks when

The rule uses information from later days (look-ahead bias, lesson B2). Real trading costs are higher than the backtest set (Costs (lesson A16)). A good result came from luck, or from trying many versions and keeping the best (The best of many (lesson B7)).

The situationA friend describes their backtest: "Daily prices of one company's shares over the past ten years. Buy when the price rises above its average price over the last 20 days; sell when it falls back below. No fees and no other costs. Here's my trade list and account line."

Which part of the recipe is missing?

The data is there: ten years of daily prices of one company's shares.
The exit is there: sell when the price falls back below its average.
Nothing says how much each trade puts in. Without S, the same price moves could mean a tiny gain or a huge one, so the account line can't be checked.
Costs are set: to none ("no fees and no other costs"). That may be too kind (the costs lesson, A12, is about real trading costs), but it is stated.
The missing part is the position size. Data, entry, exit and costs are all there.

What to look at in any backtest

Every backtest you'll ever see comes down to three things. Turn them over one at a time.

  1. The trade list.

    Every trade: when it bought, when it sold, what it made or lost. Everything else is added up from it. It belongs to one exact rule: change one setting, such as the 3, and you get a different list.

Everything later in this course questions one of these three.

Practice 1 of 3

A friend's backtest

The situationA friend ran a rule on one market's last 10 years. The account went from $10,000 to $16,302. They're sure the rule has found something.

What's the most useful thing to ask?

One market can look great by luck alone. Market C in this lesson ended at exactly $16,302, and we built it random, with nothing to find. Other markets show whether a result repeats.
Market C in this lesson ended at $16,302 too, and it had no pattern at all: we made it random. One market's result can be luck. Ask how the rule did on other markets.
A backtest replays the same past days, so running it again gives the same trades and the same end. It adds nothing. Other markets do.
Practice 2 of 3

One trade, with costs

The situationAnother backtest puts S = $5,000 into each trade and charges costs of c = $6 a trade. One trade buys at $40 and sells at $42.

What is that trade's result r? Type it in dollars.

Hint: first the percentage return, 42 ÷ 40 − 1. Multiply it by S, then take away c.

r = 5,000 × (42 ÷ 40 − 1) − 6 = 5,000 × 0.05 − 6 = 250 − 6 = $244.
The percentage return is 42 ÷ 40 − 1 = 0.05 (5%). So r = 5,000 × 0.05 − 6 = 250 − 6 = $244. Leaving out the costs gives $250.
Practice 3 of 3

Check it by hand

The situationYou check a backtest by hand. Same rule: after 3 down days in a row, buy; sell 5 days later; one trade at a time. Here are days 108 to 122 of made-up market D (simulated).

On which days does the rule buy?

Day 114 does end 3 down days in a row, but the trade bought on day 111 is open until day 116. One trade at a time, so the rule waits. The next run of three ends on day 120.
Days 109, 110 and 111 are the first three down days in a row. That trade is open until day 116, so days 112 to 114 don't count. The next run of three ends on day 120.
Each of those days ends 3 down days in a row, but the rule holds one trade at a time. After buying on day 111 it waits for the sell on day 116; the next run of three ends on day 120, and then that trade is open past day 122.
✓

Lesson done

A backtest replays a rule on past days, trade by trade, as if you had traded back then. It leaves three things to look at: the trade list, the account line, and every market it ran on. Every later lesson questions one of those three.

Key ideas

Market
anything with a price you can buy and sell
Down day / up day
a day the price ends lower / higher than the day before
Trading rule
a fixed instruction: an entry (when to buy) and an exit (when to sell)
Trade and result
one buy and one sell; what came back minus what went in
Position size
how much each trade puts in ($10,000 here)
Costs
fees and worse-than-shown prices; zero in this lesson
Percentage return
Psell ÷ Pbuy − 1: the price move as a share of the buy price
Backtest
a rule run over past days as if you had traded then, using only the days so far
Trade list
every trade the backtest took
Account line
the account after each trade (traders call it the equity curve)
Set of markets
every market the rule ran on, read together

r = S × (Psell ÷ Pbuy − 1) − c

Ak = A0 + r1 + … + rk

Lesson notes

A backtest runs a fixed trading rule over past days, as if you had traded then, one day at a time, using only the days so far. It leaves three things to look at: the trade list, the account line, and every market the rule ran on.

A rule and one trade

A market is anything with a price you can buy and sell. A day it ends lower than the day before is a down day, a higher one an up day. The rule: after 3 down days in a row, buy at the end of the third one. Sell at the end of the 5th day after the buy. While a trade is open, start no other.

In made-up market A, days 18, 19 and 20 were all down, so the rule bought at the end of day 20 and sold at the end of day 25. A trade spends $10,000 at the buy and gets back what that has become. What came back minus what went in is the result: $9,708 came back, so the result was −$292. The trade was held for days 21 to 25. Days 21, 22, 23 and 25 were down, but a down day shows which way the price went, not how far.

Walking forward, day by day

The backtest writes each trade into the trade list. In A's first 48 days it made 3 trades, and all three lost. The trade bought on day 20 was open until its sell on day 25, so no buy could come on days 21 to 25. Days 21, 22 and 23 were three more down days in a row, but the rule waited. Day 25 counts towards the next run: days 25, 26 and 27. The market runs 10 years: 2,520 trading days.

The account line

The account starts at $10,000; each closed trade adds its result. After the first three trades it was 10,000 − 292 − 296 − 117 = $9,295. Trade 2 was bought on day 27 and sold on day 32, trade 3 on day 37 and sold on day 42. Every trade puts in the same $10,000.

Over 10 years A made 147 trades: 79 made money and 68 lost. It ended at $14,662. The account line, the account after every trade, shows the way there (the dollar figures here are read from the lesson's simulation): down to $8,817 in the first year, up to $15,971 a little after year 6, back to $12,589 about a year later.

Five markets, not one

Markets B to E were made the same way, with the same rule. 4 of the 5 ended above $10,000. Market B ended at $4,923, about half gone, and C at $16,302. One market can make a rule look great or terrible, so read many together.

Why they differ: luck

Every day of every market was drawn at random, with a small rise built in: 0.03% a day on average. A typical day moves about 1.2% up or down, 40 times the rise. Each day's move is unrelated to the last: no pattern to find. Four markets still ended higher: each day a trade is open it collects the rise, $10,000 × 0.03% × 5 days ≈ $15 a trade. Over about 140 trades a market, that is 140 × $15 = $2,100. The rise alone averages $2,118 across the five, and they made $2,207. The rule found nothing. B and C differ by the random days each drew. The rule (buy after 3 down days, sell 5 days later) and the $10,000 a trade were the same.

The parts of every backtest

Every backtest has historical data (past prices), a rule with an entry (when to buy) and an exit (when to sell), a position size (how much each trade puts in), and costs (fees, and the small loss from trading at a slightly worse price than shown). Its results are the trade list, the account line (the equity curve) and summary numbers such as the trade count.

Formula: the result of one trade, and the account

The part Psell ÷ Pbuy − 1 is the trade's percentage return: how much the price moved, as a share of the buy price.

r = S × (Psell ÷ Pbuy − 1) − c
Ak = A0 + r1 + … + rk
r
the result of one trade, in dollars (not a percentage)
S
the position size: dollars put into the trade
Pbuy, Psell
the price at the buy and at the sell
c
the costs of that trade (zero in this lesson)
A0
the account at the start
r1 … rk
the first trade's result, the second's, and so on up to the k-th
Ak
the account after k trades: one point of the account line
Worked example

Market A's first trade: S = $10,000 and $9,708 came back, so Psell ÷ Pbuy = 9,708 ÷ 10,000 = 0.9708 (results are rounded to whole dollars). With c = 0: r = 10,000 × (0.9708 − 1) − 0 = −$292.

After three trades: A3 = 10,000 − 292 − 296 − 117 = $9,295.

With real prices and costs (made-up numbers): S = $2,000, buy at $50, sell at $52, c = $4. The percentage return is 52 ÷ 50 − 1 = 0.04 (4%), so r = 2,000 × 0.04 − 4 = 80 − 4 = $76.

Holds whenBreaks when

The rule uses information from later days (look-ahead bias, lesson B2). Real trading costs are higher than the backtest set (Costs (lesson A16)). A good result came from luck, or from trying many versions and keeping the best (The best of many (lesson B7)).

One more worked example

Made-up round numbers

A trade puts in S = $8,000, buys at $25, sells at $24, and costs c = $5.

Percentage return: 24 ÷ 25 − 1 = −0.04 (−4%).

Result: r = 8,000 × (−0.04) − 5 = −320 − 5 = −$325.

Put it in an account that starts at $10,000, after earlier results of +$180 and then this one, and a later +$60: 10,000 + 180 = 10,180. Then 10,180 − 325 = 9,855. Then 9,855 + 60 = $9,915.

Common mistakes

Check yourself

  1. An account starts at $10,000. Three trades close with results +$120, −$450 and +$90. Where does it stand?
    Answer

    Results add: 10,000 + 120 − 450 + 90 = $9,760.

  2. A trade puts in S = $4,000, buys at $20, sells at $21, and costs c = $3. What is its result?
    Answer

    21 ÷ 20 − 1 = 0.05, so r = 4,000 × 0.05 − 3 = 200 − 3 = $197.

  3. A friend's rule made $6,302 on one market in ten years. What do you ask?
    Answer

    How it did on other markets. Market C made the same, and was random.

Try it yourself

Run the simulation. Every square, line and number in this lesson comes from one Python script with a fixed random seed (below). Change the setting, the 5-day hold or the built-in rise and see what moves.

Do one by hand. Toss a coin 30 times and call heads an up day, tails a down day. Mark where the rule buys and sells, one trade at a time. A coin has no rise built in and no sizes, so you get a trade list of days, not dollars: it's practice in reading a rule exactly.

About QuantWright

QuantWright, which publishes this course, sells backtesting software. You describe a strategy in plain English (or paste Pine Script); it writes the code and backtests it on licensed historical data with commission (the fee for placing each trade), slippage (filling at a slightly worse price than expected) and next-bar fills (a trade fills in the next day or period after its signal), all of which this lesson left out. Every result states its data window, data source and costs. quantwright.com

The code behind every number (Python, seed 2026110900)
Loading…

As a 130-second video: Backtesting from Scratch, Part 0, "what a backtest is". Same markets, same numbers.

Try it: change one setting

The 3 in the rule is a setting: a number you choose. Change it, and the backtest replays the same 10 years of market A with the new rule, so the whole trade list changes. Trying many settings and keeping whichever did best brings a trap of its own: The best of many (lesson B7) is about it.

Made-up market A, the same 10 years, one setting changed (simulated)

Coloured: the account line with your setting. Grey: the rule you ran before (3 in a row).

Buy after
down days in a row
TradeBought (day)Sold (day)Result
Trades–
Made money–
Lost money–
Ended at–

Going further: how far luck spreads a random market

Each trade here gives a small random amount. On average it's +$15.01, give or take about $269. That "give or take" is the standard deviation: roughly the usual distance of one trade's result from its average.

Take market A, which made 147 trades. Add up 147 independent trades and the average adds up 147 times, to about +$2,206. The give-or-take grows more slowly, with the square root of the count: √147 × $269 ≈ $3,258. So in a market made like ours, the rule ends within $3,258 of +$2,206 about two times in three, and within twice that about 19 times in 20. The shaded bands show that spread over the 10 years.

Five made-up markets against the spread luck allows (simulated)

Dashed: the rise alone. Darker band: within one standard deviation of it. Lighter band: within two.

Market B ended 2.2 standard deviations below the rise alone: for one market that's about 1 chance in 79, but among several markets, one that unlucky turns up now and then. Market C ended 1.3 above. None of it is the rule: buying after down days can't change these numbers, because the days before a buy say nothing about the days after it.

For the preciseA trade's result is 10,000 × (Pexit / Pentry − 1), the product of 5 independent daily factors (1 + r), r ~ normal(0.0003, 0.012). Mean: 10,000 × ((1.0003)5 − 1) = $15.01. Standard deviation: 10,000 × √(((1.0003)2 + 0.0122)5 − (1.0003)10) = $268.7. Trades never overlap and each depends only on its own 5 days, so a market's total is a sum of independent trades. Standard deviations from the rise alone, per market: A 0.8, B −2.2, C 1.3, D −0.1, E 0.4. All 706 trades: 365 made money (51.7%), average result $15.63. The bands use the average count, 141.2 trades a market, spread evenly over the 10 years. Seed 2026110900.

Honest notes

Where this comes from