How to Do Backtesting: A Worked Beginner Tutorial for Trading Strategies

Table of Contents

Disclaimer

All articles are for education purposes only, and not to be taken as advice to buy/sell. Please do your own due diligence before committing to any trade or investments.

Disclaimer

All articles are for education purposes only, and not to be taken as advice to buy/sell. Please do your own due diligence before committing to any trade or investments.

Table of Contents

You have a trading rule, perhaps a moving-average cross or something you read about, and you want to know whether it would have worked on past prices. Staring at a chart will not tell you. A backtest will, provided you run it honestly.

This page runs a full backtest in the open, from written rules to limitations, and shows the answer it produced rather than the answer it was hoping for. The rule, a 50/200-day moving-average crossover on SPY (a US-listed S&P 500 ETF), made money: with 0.10% assumed costs per side and dividends excluded, USD 10,000 became USD 19,571.62 between the first trade in April 2019 and the last close in September 2026. Over the same stretch, simply buying and holding the ETF turned USD 10,000 into USD 26,490.81, and the rule’s whole result rests on 4 trades. That combination of a positive number, a worse result than doing nothing and a sample too small to prove much is what a first backtest should teach you to read.

Everything below is a historical simulation on past prices, run for education. It is not a recommendation or a strategy endorsement, and past results do not predict future results.

What is backtesting in trading?

Backtesting means applying a fixed set of trading rules to past prices and recording what those rules would have done. In their 2015 paper on backtest overfitting, Bailey, Borwein, López de Prado and Zhu define a backtest as “a historical simulation of how an algorithmic strategy would have performed in the past”. The definition keeps the scope tight. A backtest reports what fixed rules would have done on past data, and nothing more.

In practice, traders use a backtest for 4 things: turning a vague idea into a countable set of trades, seeing how much those trades cost in fees, measuring how deep the losses went along the way, and producing something concrete to forward test later. It cannot tell you whether you would have followed the rules under pressure, and it cannot prove an edge. Step 1 sets out that boundary.

What you need to backtest a stock or ETF

You need 4 things, and none of them costs much:

  • Daily price data with an open and a close for the instrument you want to test.
  • A spreadsheet, or a backtest tool if you prefer one.
  • A written rule set, frozen before you look at any result.
  • Patience for the audit step, which is the easiest part to skip.

If your question is how to do backtesting of stocks, the answer is the same 6 steps. They apply to a US stock, an SGX stock or an ETF alike; you use that instrument’s own price history and its own trading costs. The example in this article uses SPY, quoted in USD, because its full daily history was publicly available from Nasdaq, which makes every figure reproducible. The SPY figures demonstrate the method. They say nothing about how the rule would behave on the STI or on any individual share.

2 method warnings matter if you test single stocks. First, use prices that are adjusted for splits, or a 2-for-1 split will appear as a 50% crash and your signals will be nonsense. Second, if you test a group of stocks, include the ones that were delisted or went bankrupt during the period. Picking only the companies still listed today is survivorship bias, and it flatters the result.

Step 1: Decide what this test can and cannot answer

Before you touch any data, write down the boundary.

A well-built backtest can answer this: would these exact rules, applied to this data, with these costs, have produced these trades, and what were the returns, the fees and the worst drawdown along the way?

It cannot tell you whether the rule has a real edge, whether it will work next year, or whether you would have executed it. Nor can it tell you whether you got lucky, especially with few trades. A rule that made money is not the same as a rule with an advantage over the market, and no single historical run separates the two. If that distinction is new to you, our guide to finding your edge in trading covers it in more depth.

Keep this boundary visible while you work. It stops you from reading 4 trades as proof of anything.

Step 2: Freeze the rules and data settings before you run anything

This is the step that decides whether the exercise is a test or a story you tell yourself afterwards. Write the rules down, date the file, and do not edit it once you have seen a result. Changing rules after seeing results is curve-fitting: you are no longer testing an idea, you are describing the past. It is also why we teach rules before results. A written rule set takes the in-the-moment emotion out of each decision, and a frozen one keeps you honest about what you actually tested.

Here is the rules sheet for the worked example, frozen before the single run.

Field Setting
Instrument SPY, US-listed S&P 500 ETF, priced in USD
Data source Nasdaq public historical quote data, daily open/high/low/close, 2,514 rows covering 2016-09-26 to 2026-09-25
Data treatment Price only; dividends excluded, not adjusted for distributions
Signal 50-day and 200-day simple moving averages of the daily close
Entry When flat, a fresh cross of SMA50 above SMA200 on close of day t → buy at the open of day t+1
Exit A cross of SMA50 below SMA200 on close of day t → sell at the open of day t+1
Direction Long only
Sizing Whole shares, fully invested, compounding
Starting capital USD 10,000
Costs 0.10% per side (commission plus slippage proxy); a 0% run kept for comparison
Open trades Marked at the final close
Development period Before 2023-01-01
Held-out period 2023-01-01 onward
Parameters Textbook defaults, not optimised. The run was executed once.

A simple moving average is the average of the last N closing prices, recalculated each day. The 50-day average reacts faster than the 200-day average, so when the 50 crosses above the 200, shorter-term prices have moved above the longer-term trend.

The line that carries the most weight is the entry and exit timing. The signal is read from the close of day t, and the fill happens at the open of day t+1. Reading a signal and filling on the same day’s close is look-ahead bias. In live trading you do not know today’s close until today is over, so a same-day fill quietly hands the strategy information it would never have had. The next-open rule closes off that common way for a beginner backtest to flatter itself.

Sizing deserves the same discipline. Our position sizing guide covers the risk side. Here, the example keeps sizing deliberately blunt (whole shares, all available cash, no leverage) so the arithmetic stays checkable.

If the crossover rule itself is new to you, our moving average crossover strategy guide explains the mechanics.

Step 3: Run the backtest

A spreadsheet handles a daily rule like this without any programming. The worked example was computed with a short script from the same public daily prices, but every step below can be reproduced in spreadsheet columns, in this order.

  1. Date, open, close. 1 row per trading day, oldest first.
  2. SMA50 and SMA200. Average the last 50 and last 200 closes. The first 199 rows have no SMA200 value; leave them blank. A signal cannot exist before the averages do.
  3. Cross detection. Compare today’s SMA50-versus-SMA200 relationship with yesterday’s. An up-cross is SMA50 above SMA200 today after being at or below it yesterday. A down-cross is the reverse.
  4. Fill at the next open. When the up-cross appears on the close of day t, the buy price is the open of day t+1. The same applies to exits.
  5. Shares. For a 0.10% per-side cost, shares = floor(cash ÷ (open × 1.001)). Rounding down to whole shares keeps the cash balance honest.
  6. Fees. Cost percentage × trade value, charged on the buy and again on the sell.
  7. Daily equity. Cash plus the value of any open position at that day’s close. This column becomes your equity curve, and you need it to calculate drawdown later; trade-by-trade profits alone cannot show it.

Completion check: you should now have a list of trades and a daily equity column. If you have one without the other, you cannot measure risk, and Steps 4 and 5 will not work.

A note on tools: backtest platforms automate all of this and are faster once your rules are fully mechanical. The trade-off is that automation can bury a mistake in the output. Whatever runs the numbers, you still have to audit them, which is Step 4.

Step 4: Audit the actual trade log

Here is the full trade log from the run, at 0.10% per side.

# Signal (close) Buy (next open) Shares Exit signal Sell (next open) Fees USD P&L USD Return Status
1 2019-04-01 2019-04-02 @ 286.04 34 2020-03-30 2020-03-31 @ 260.56 18.58 −884.90 −9.10% closed
2 2020-07-09 2020-07-10 @ 314.31 28 2022-03-14 2022-03-15 @ 419.77 20.55 +2,932.33 +33.32% closed
3 2023-02-02 2023-02-03 @ 411.59 29 2025-04-14 2025-04-15 @ 539.67 27.59 +3,686.88 +30.89% closed
4 2025-07-01 2025-07-02 @ 617.24 25 none marked 2026-09-25 @ 771.35 15.43 +3,837.32 +24.87% open

Now check it line by line. Here are 6 checks, with what each one found in this run.

  • Is every fill the day after its signal? Yes. Every buy and sell date is the trading day immediately after the signal date, so there is no look-ahead.
  • Did the first trade start when the averages first existed? No, and that is correct. SMA200 first has a value on 2017-07-12, but SMA50 was already above SMA200 that day. The rules require a fresh up-cross, so the strategy stays flat until the up-cross on 2019-04-01. A backtest that bought on 2017-07-12 would be trading a signal the rules never defined.
  • Were down-crosses while flat ignored? Yes. A down-cross on 2018-12-07 appears while the strategy holds no position, and it produces no trade. The run’s signal audit logs all 8 crossings between 2018 and 2025, and none of them is a whipsaw (a cross that reverses within days).
  • Are fees charged on both sides? Yes for every closed trade: trades 1 to 3 each carry a fee on the buy and a fee on the sell. Trade 4 is still open, so its USD 15.43 is the buy-side fee only; a sell fee will apply when it closes.
  • Is the open trade handled explicitly? Trade 4 has no exit signal. It is marked at the last close, 2026-09-25 at 771.35, and that mark produces the +24.87%. The mark moves with the market, so the trade’s result is not final.
  • Do the signals match the moving-average values? Yes. The audit re-read SMA50 and SMA200 on the day before and the day of every signal. On 2019-04-01, for example, SMA50 moved from 275.20, below SMA200 at 275.33, to 275.65, above SMA200 at 275.37.

If any fill in your own log lands on the same day as its signal, stop. You have look-ahead bias, and every number downstream is inflated. Fix it and rerun before you read a single result.

Step 5: Compare costs, the held-out period and doing nothing

This step turns a trade log into a judgement, using 3 comparisons from the same run. Start with 2 definitions. Profit factor is gross profit divided by gross loss: how many dollars the winners produced for every dollar the losers took. Maximum drawdown is the deepest fall from an equity peak to the following trough, measured on the daily equity column. It tells you what you would have had to sit through.

Buy-and-hold starts at the open on 2019-04-02, the day the rule made its first purchase, so both are measured over the same stretch of market with the same cost model.

Metric Strategy (0.10%/side) Strategy (0%) Buy & hold SPY from 2019-04-02 open (0.10%)
End equity from USD 10,000 19,571.62 (+95.72%) 19,759.24 (+97.59%) 26,490.81 (+164.91%)
Trades / wins / losses 4 / 3 / 1 (1 still open) 4 / 3 / 1 n/a
Average win / average loss +29.69% / −9.10% +29.88% / −8.91% n/a
Profit factor (USD) 11.82 12.27 n/a
Maximum drawdown (daily close equity) −33.34% (2020-02-19 → 2020-03-23) −33.31% −33.34% (same dates)
Development window, 2019-04-02 → 2022-12-30 +20.62%, max drawdown −33.34% (2 trades, PF 3.31) +21.95% +32.84%, max drawdown −33.34%
Held-out window, 2023-01-03 → 2026-09-25 +62.45%, max drawdown −18.89% (2 trades, 0 losses, PF undefined) +62.07% +100.49%, max drawdown −18.76%
Time in market from first entry 1,535 of 1,882 trading days (≈81.6%) same 100%

Read the 3 comparisons separately, because they say different things.

Costs. The 0% run ends at 19,759.24 against 19,571.62 with costs, a gap of 1.87 percentage points over 4 trades. The bill is small here only because the rule traded 4 times. A rule that trades monthly pays the per-side cost far more often, so the cost model deserves as much care as the signal. The table also contains an oddity worth checking rather than ignoring: in the held-out window the 0% run returned slightly less (+62.07%) than the 0.10% run (+62.45%). That comes from whole-share rounding. Both runs bought 29 shares for trade 3, but the 0% run entered the window with more cash, so a larger share of its account sat uninvested. Costs did not help; the percentage is measured on a bigger base.

The held-out period. The rules were frozen and the split was declared in advance: everything before 2023-01-01 was development, everything after was held-out. The strategy returned +62.45% in the held-out window, and buy-and-hold returned +100.49%. The held-out period contains 2 trades and no losing trades, so its profit factor cannot be calculated: there is no gross loss to divide by. That is the honest reading of a held-out result this small, and it is why a single split is a check rather than a verdict. Bailey and colleagues put it more bluntly. They write that standard hold-out techniques “tend to be unreliable and inaccurate” in investment backtests, and they describe hold-out as clearly inadequate for small samples. Their paper on the probability of backtest overfitting is worth reading once you start testing more than 1 rule.

Doing nothing. This is the comparison that is easiest to leave out, and here it is the most uncomfortable. Buying SPY on 2019-04-02 and holding ended at 26,490.81, against 19,571.62 for the rule. The rule made money, yet it lagged the simplest available alternative in both the development window (+20.62% versus +32.84%) and the held-out window (+62.45% versus +100.49%), while being in the market about 81.6% of the time anyway. That lag is the finding, and the test did its job by exposing it.

The drawdown row needs its own explanation. The strategy’s −33.34% drawdown is identical to buy-and-hold’s because the exit signal came on the close of 2020-03-30, so the sell filled on 2020-03-31, after the 2020-03-23 low. The rule sat through the entire COVID crash and left the position 8 calendar days after the bottom. This is exit lag, and it comes with any rule that waits for a moving-average cross to confirm a turn. Our guide to how drawdown affects portfolio returns is useful here, because a fall of this size is what you would have had to sit through to earn the return.

After these 3 comparisons, the headline numbers look far less impressive. A profit factor of 11.82 looks exceptional. It comes from 3 winners against 1 loser, and the largest winner is the open trade, marked at a single day’s close. With this few trades, the figure describes 4 events, not a rule’s long-run behaviour.

Step 6: Write down the limitations and a forward-test plan

Limitations come first. List the ones specific to this run:

  • 4 trades over 10 years, 1 of them open. This is the binding constraint. Nothing here separates a real edge from a favourable stretch of a rising market.
  • 1 instrument, SPY only: a US ETF with US market hours, US liquidity and USD pricing. Singapore traders should rerun the same method on the market they actually trade, with their own broker’s cost schedule. We have no verified Singapore broker fee figure to offer, and costs vary enough between brokers that any single number would mislead.
  • Price only. Dividends are excluded from both the strategy and the benchmark. The strategy would have collected dividends only while it held SPY, about 81.6% of the time after its first entry, while buy-and-hold would have collected them throughout. Buy-and-hold’s lead would therefore most likely widen rather than shrink if dividends were included. That is a direction, not a quantity we measured.
  • An assumed cost model. 0.10% per side is a placeholder for commission plus slippage. Real costs, FX conversion and any withholding tax on US dividends are not modelled.
  • 1 date split and 1 set of default parameters. There is no walk-forward test (repeating the develop-then-test split across successive windows) and no sensitivity testing across other moving-average lengths. Trying many parameter sets and picking the winner is how overfitting starts, and this run avoids it by running once.

Then the forward test. The point is to test the same rules on data they have never seen, the market as it unfolds, with the pass or fail condition decided in advance.

Use the identical frozen rules from Step 2. Trade on paper, or at a small size you are comfortable losing, and log every trade with the same detail as the backtest log so the 2 can be compared line by line. Our guide to trading journals covers how to keep that record. Before you start, write down what would make you stop or revise: a drawdown deeper than the backtest’s, a sequence of trades that does not resemble the log, or a failure to execute the rules as written. When you have enough forward-test trades to review, evaluate the whole plan (rules, results and process) using our guide to evaluating your trading plan. This page covers running the test; that guide covers judging the plan.

How many trades is enough?

We cannot support a universal number with evidence, and the fixed minimums quoted in some trading guides are rules of thumb presented without supporting data.

What can be said is directional: the more independent trades a test contains, the less room there is for luck to explain the result. 4 trades over 10 years cannot do that job. A single large winner, an open position marked at one day’s close, and a held-out period with zero losses are all signs that the sample describes events rather than behaviour. A small sample is a reason to forward test before you trust the result.

What to do next

Rerun this method on the market you actually trade. Pick 1 instrument you know, write the rules down, date the file, run it once, and audit the log before you look at the return. An audited pass on your own market will tell you more about your rule than the SPY figures here can, and it needs little more than price data, a spreadsheet and an afternoon.

If you would like structured guidance on building and testing trading rules, our trading course in Singapore is where we teach our systematic approach.

This article is educational. All figures come from a historical simulation on past prices and are not a recommendation to buy or sell any instrument. Past results do not predict future results.

Share this post:

Facebook
Twitter
WhatsApp
Pinterest
Telegram

Leave a Reply

Your email address will not be published. Required fields are marked *

Share this post:

REACH YOUR HIGHEST TRADING PERFORMANCE

Copy My No Brainer Trading Strategy

REACH YOUR HIGHEST TRADING PERFORMANCE

Copy My No Brainer Trading Strategy

Get Started HERE With Our FREE Market-Timing 101 Video Course

X

Copy My No-Brainer Trading Strategy