Skip to content
Course contents
From backtest to live strategy

Forward-testing before a rupee

Between a backtest on old data and live trading with real money sits forward-testing, running the strategy on live or recent data through the sandbox, with no money at risk. This chapter explains why this step catches problems a backtest cannot, timing, data gaps, order rejections, and treats a clean forward test as a requirement before going live, not an optional nicety.

9 min readChapter 16 of 28
What you will learn
  • Define forward-testing and explain what it catches that a backtest cannot
  • Run the strategy through the simulated broker as a forward test and read the result
  • Set a passing forward test as a precondition for any live trading

A backtest tells you how a strategy would have done on old data. It does not tell you whether your program actually works: whether the orders go out correctly, whether the timing is right, whether a data gap or a rejected order breaks it. That is a different question, and there is a step designed to answer it before any money is at risk. Forward-testing runs your real strategy, through your real order code, against the sandbox, on recent or live data, and watches what happens. In this course's terms from the very first part: the backtest tested the idea, and forward-testing tests the machinery.

What forward-testing catches

Between a backtest on old data and live money sits forward-testing in the sandbox on live data, which catches timing, data gaps, and rejections a backtest cannot.
Between a backtest on old data and live money sits forward-testing in the sandbox on live data, which catches timing, data gaps, and rejections a backtest cannot.

A backtest runs on a clean, finished spreadsheet of history, so it never meets the problems that live trading is full of. Your data feed hiccups and a bar arrives late or not at all. An order is rejected because of a size or fund limit. Your timing is subtly off and you act a bar later than you meant to. The strategy holds a position through a restart. None of these show up in a vectorised backtest, because a backtest is arithmetic on a table, not a running program placing orders. Forward-testing, because it runs the actual program against a broker, surfaces exactly these plumbing problems while they are still free to fix.

Here is the same crossover strategy, run not as arithmetic but through the broker, order by order, with costs charged on every fill, against the sandbox.

ExampleRunning the real order path through the sandbox, with costsch16/forward_test.py
# Forward-testing: run the SAME strategy through the broker, order by order, with
# real fills and costs, but against the sandbox so no money is at risk. This
# exercises the actual order path a backtest never touches, and reports the
# account result the way a live account would show it.
import pandas as pd
from paper_broker import PaperBroker
from strategy import Crossover

df = pd.read_csv("sample_prices.csv", parse_dates=["Date"], index_col="Date")
closes = df["Close"].tolist()

start_cash = 1_000_000
# Costs turned on: the broker charges 0.1% (10 basis points) on every fill.
broker = PaperBroker(cash=start_cash, prices={"RELIANCE": closes[0]}, cost_bps=10)
strategy = Crossover(fast=20, slow=50, quantity=100)

trades = 0
for i in range(len(closes)):
    price = closes[i]
    broker.feed_price("RELIANCE", price)
    for side, quantity in strategy.on_bar(closes[:i + 1]):
        broker.place_order("RELIANCE", side, quantity, "MARKET")
        trades += 1

# Account value = cash left plus the value of any open position at the last price.
last_price = closes[-1]
position_value = sum(p["quantity"] * last_price for p in broker.get_positions())
cash = broker.get_funds()["available_cash"]
equity = cash + position_value

print(f"Forward test over {len(closes)} bars, {trades} trades, costs on")
print(f"Start cash:          {start_cash:,.2f}")
print(f"End cash:            {cash:,.2f}")
print(f"Open position value: {position_value:,.2f}")
print(f"Account value:       {equity:,.2f}  ({(equity / start_cash - 1) * 100:+.2f}%)")
print("This ran the real order path (orders, fills, costs), not just return arithmetic.")
Output
Forward test over 180 bars, 5 trades, costs on
Start cash:          1,000,000.00
End cash:            847,692.30
Open position value: 141,768.00
Account value:       989,460.30  (-1.05%)
This ran the real order path (orders, fills, costs), not just return arithmetic.

Read the result. Over 180 bars the strategy placed its 5 trades through the broker, paying real costs on each fill, and the account finished at 9,89,460, down about 1.05% from 10,00,000. That percentage is smaller than the backtest's 8.11% loss for a simple reason: this run put a fixed 100 shares to work, roughly a seventh of the account, rather than the fully invested position the backtest measured. But the direction is the same, a loss, and the point is not the number. The point is that this ran the real order path, orders, fills, and costs, and it worked from end to end. A backtest could never have told you that.

A clean forward test is a gate, not a nicety

Treat a passing forward test as a hard precondition for going live, in the same way you treat a passing backtest as a precondition for forward-testing. The order is deliberate: prove the idea has an edge on history, then prove the machinery runs correctly in the sandbox, and only then consider real money. Skipping the forward test is how people discover, with real rupees, that their order sizing was wrong or their program crashes at the open. Run it for long enough, on recent data, to see the strategy trade several times and handle a normal day without drama. A forward test that runs clean for a while is not proof the strategy will make money, nothing is, but it is proof the program will not embarrass you the first time it meets the market.

Take it to the sandbox. Practice this with no money at risk.Forward-test a strategy in the sandbox before going near real money

What to carry forward

Forward-testing runs the actual program, strategy plus order code, against the sandbox on recent data, so it catches the plumbing failures a backtest never can: late data, rejected orders, timing slips, restarts. You saw the crossover run through the broker with real fills and costs, finishing down about 1.05% on fixed sizing, the same losing direction as the backtest but now proven to run end to end. Make a clean forward test a required gate before going live, after a passing backtest and before any real money. The next chapter is the crossing itself, going live, and it is the most cautious chapter in the course.