Backtesting Concepts

How the Simulation Works

The candle-by-candle execution loop, how positions open and close, and how the equity curve is built.

How the Simulation Works

A backtest replays your strategy against historical data. But what actually happens inside the engine? This article walks through the candle-by-candle process that turns your entry and exit rules into an equity curve and a set of performance metrics.

The engine processes one candle at a time, from the first candle in your date range to the last. At each candle it reads the price data, decides whether to enter or exit based on your rules and the current position state, then records the portfolio value. The engine never looks ahead -- it only knows what has happened up to the current candle.

The Candle-by-Candle Loop

Every backtest follows the same loop. The engine runs this sequence once per candle, from the start of your date range to the end:

Read candle1Position?NoYesCheck entry2aCheck exit2bManage position3Update equity4repeat for each candle
1. Read candle
The engine loads the open, high, low, and close prices for the current candle. These four values are the raw data that everything else is built from.
2a. Check entry conditions (no open position)
If the strategy has no open position, the engine evaluates your entry conditions. Are all conditions true (AND logic)? Is at least one true (OR logic)? If the entry check passes, the engine knows a trade should open on this candle.
2b. Check exit conditions (position open)
If the strategy already has an open position, the engine evaluates your exit conditions using the same AND/OR logic instead. If the exit check passes, the engine knows the position should close on this candle.
3. Manage position
Based on the result of step 2a or 2b, the engine either opens a new position, closes the current one, or does nothing. This is also where stop-losses (a price level that automatically exits a losing trade to limit losses) and take-profits (a price level that locks in gains) are checked -- if the candle's high or low breaches a threshold, the position is closed at that price.
4. Update equity
The engine records the portfolio value at the end of this candle. If a position is open, the value reflects the unrealized profit or loss based on the current close price. If no position is open, the value carries forward from the last realized result.

After the last candle, the engine has a complete equity curve and trade log. These are passed to the metrics calculator, which produces the full set of performance metrics you see in your results.

One loop, one candle interval

Notice that the loop steps through one candle interval. A strategy where every condition uses the same timeframe is the simple case -- the engine reads that timeframe's candle at step 1 and checks every condition against it. That is what most backtests are.

A multi-timeframe strategy runs the exact same loop. The engine still steps one candle at a time at the fastest timeframe any condition uses, and at each step a condition that references a higher timeframe is checked against that higher timeframe's value, rebuilt from only the candles that have closed so far. Single-timeframe is just the special case where every condition happens to share the loop's interval -- nothing about the candle-by-candle mechanism changes.

The Equity Curve

The equity curve is a line that tracks your portfolio value over time. It is the most fundamental output of a backtest -- every other metric is derived from it.

position openposition openposition openStarting capitalPeakTroughdrawdownFinal value

Simula normalizes the starting capital to 1.0, so the equity curve shows relative growth rather than a dollar amount. A final value of 1.15 means the strategy returned 15%. A value of 0.90 means it lost 10%.

The shaded regions above represent candles where a position was open. Between positions, the equity curve stays level because the strategy is not exposed to price changes. The peak is the highest point the equity curve reaches, and the trough is the lowest point after a peak. Max drawdown is the largest peak-to-trough decline across the entire curve.

Leverage and the equity curve

When you run a backtest with multiple leverage levels, the engine tracks a separate equity curve for each one. The loop runs once, but at step 4 it updates multiple equity values -- one per leverage factor. Each leverage level amplifies both gains and losses proportionally.

Position Lifecycle

A position is the period between an entry and an exit. The engine tracks one position at a time -- it does not stack multiple positions on the same asset.

Position openNo positionNo positionEntryExit

Opening a position

When entry conditions pass and the strategy has no open position, the engine opens a trade at the next candle's open price by default -- you can switch a backtest to fill at the triggering candle's close instead (see Execution timing below). The full spread is applied on the round trip -- you always buy at the ask (the higher price) and sell at the bid (the lower price). For a long trade, this means the entry price is the ask and the exit price is the bid. For a short trade, the directions are reversed. Slippage further worsens the execution price by a percentage on each side. Commission is calculated on the trade value at each end.

While a position is open

On each candle where a position is open, the engine calculates the unrealized profit or loss. For a long position, this is based on how far the close price has moved above the entry price. For a short position, it is how far the close has moved below the entry price. This unrealized value is what gets recorded in the equity curve at step 4.

Closing a position

A position closes when one of these happens:

Exit conditions pass
Your exit rules evaluated to true on this candle.
Stop-loss triggered
The candle's low (for a long) or high (for a short) breached the stop-loss threshold. The exit price is the stop-loss level, not the close price.
Take-profit triggered
The candle's high (for a long) or low (for a short) reached the take-profit threshold. The exit price is the take-profit level.
The trading day ends (intraday stock backtests)
On an intraday stock backtest, the engine closes any open position on the last candle of each trading day, at that candle's close. This trade is labeled Day End. It is on by default and can be turned off. See One Day at a Time below.
The backtest reaches the end of the data
If a position is still open on the very last candle, the engine closes it there at the final close price (with the same spread, slippage, and commission a normal exit would incur). This trade is labeled Backtest End so you can tell it apart from a trade your rules closed. It is counted exactly like any other trade.

When a position closes, the engine calculates the realized profit or loss (including spread, slippage, and commission costs), updates the portfolio value, and logs the completed trade with its entry time, exit time, and return. The cumulative impact of these costs is shown in the Transaction Cost Analysis card in your results.

Once the position is closed, the strategy is free to enter again. By default a new trade can open as early as the next candle if the entry conditions are still true; you can instead make it wait for the entry conditions to turn false and then true again. See Re-entering After an Exit.

Why does my last trade say 'Backtest End'?
Historical data has to stop somewhere, and your strategy may still be holding a position when it does. Rather than throw that position away, the engine closes it at the final candle's price and counts the unrealized profit or loss like a normal trade. This keeps every number consistent: the trade count, win rate, and average return all include that final position, and they all agree with the equity curve, which was already tracking its value candle by candle. A Backtest End exit is not something your rules did -- it just marks where the data ran out. If you see one sitting on a large loss, that is real risk your strategy was carrying at the cutoff, not a rounding artifact.
Can a position open and close on the same candle?
Not through conditions alone. Because only one branch runs per candle (entry or exit, never both), a condition-based entry and exit cannot happen on the same candle. However, a stop-loss or take-profit can close a newly opened position within the same candle if the candle's price range breaches the threshold.

What the Engine Does Not Do

Understanding the engine's limitations helps you interpret results accurately:

No lookahead
The engine processes candles in order and never uses future data to make decisions. At candle 50, it has no knowledge of candle 51. Indicators are calculated from historical data only.
No partial fills
Every trade executes in full. The engine does not simulate order books, liquidity constraints, or partial order fills.
One position at a time
The engine does not open a second position while one is already open. When a position is open, the engine takes the exit branch (step 2b) and entry conditions are not acted on.
Execution timing (next-open by default)
By default, a trade that your entry or exit conditions trigger on a candle fills at the next candle's open price (adjusted for spread and slippage) -- not the close of the candle that triggered it. Conditions are confirmed on a closed candle, and the order fills on the candle that follows, mirroring how a live trader can only act once a signal has actually printed. This is the look-ahead-safe default, and it is the reason the No lookahead point above holds for trades as well as indicators. You can switch a single backtest to Trigger close fill, which executes at the close of the triggering candle itself -- simpler to reason about, but it assumes you could have transacted at a price the candle had already finished printing. Either way, stop-losses and take-profits are the exception: they are intra-candle and execute at their threshold price the moment the candle's high or low reaches it, in both fill modes.

One Day at a Time: Intraday Stock Backtests

Stock markets close. A US regular session runs from 9:30 AM to 4:00 PM Eastern, and between the closing bell and the next morning's open there is a gap where no trading happens on your chart but a great deal can happen to the price. Earnings are released after the close. News breaks overnight. A stock can open the next morning several percent away from where it closed, and you had no opportunity to react.

Because of that gap, most intraday stock strategies are traded flat: the trader closes every position before the bell and starts the next morning with nothing open. So Simula backtests intraday stock strategies one day at a time by default. Each trading day is independent. This applies to stocks on the 1-minute through 4-hour timeframes only -- there is nothing to isolate on a daily chart, and forex and crypto trade continuously with no daily close.

What happens at the close

Three rules, all of which apply only while the setting is on:

Open positions are closed on the final candle
Whatever is open when the last candle of the day finishes is closed at that candle's close price, with the same commission and slippage any other exit would incur. The trade is labeled Day End so you can tell it apart from an exit your rules chose.
Entry signals on the final candle are skipped
If your entry rules turn true on the last candle of the day, no trade opens. There would be no time left to hold it, so the position would open and close on the same candle and pay a full round trip of costs for nothing. The skipped signal is not counted anywhere -- it will not appear in your condition trigger counts.
An exit condition on the final candle keeps its own name
If your exit rules fire on the last candle of the day, the position closes and the trade is reported as that exit condition, not as Day End. The price is the same either way. The label matters because it answers a real question: does this strategy exit on its own, or is the closing bell rescuing it?

Where the engine thinks the day ends

The engine uses the last candle it actually has for that day, not a fixed 4:00 PM clock time. That distinction matters on the two or three half days a year -- the day after Thanksgiving, and Christmas Eve or July 3rd when they fall on a weekday -- when US markets close early, at 1:00 PM. On those days the data simply contains fewer candles, and the engine closes your position on the last one it has. You do not need to know the exchange holiday calendar, and neither does the engine.

The same rule applies at the very end of your backtest. If your date range stops partway through a session, that final candle is treated as a day end, so a run never finishes with a position left hanging open.

This changes your results, and it is meant to
Day isolation is not cosmetic. A strategy that would have held a position for three days now takes three separate trades instead of one, so your trade count rises, your average holding time falls, and you pay commission and slippage on each of those round trips. That is the point: it is a closer match to how an intraday stock strategy is actually traded. If you compare a result against one you ran before this existed, expect the numbers to differ.

Holding positions overnight

Set Day Isolation to Hold overnight in the configuration bar above the strategy builder. Positions then carry across the gap until one of your exit conditions, a stop-loss, or a take-profit closes them, exactly as they do on a forex or crypto backtest. All three rules above switch off together, including the skipped entry on the final candle -- if you have chosen to hold overnight, an entry late in the day is a perfectly ordinary trade.

Be honest with yourself about what that result then represents. Holding overnight means holding through the gap, and a backtest cannot show you the moment you would have wanted to get out and could not. It also means your stop-loss did not protect you overnight: if the price gapped straight through your stop level while the market was closed, the simulation fills you at that stop level, which is a fill you would not have received in practice.

Why does my intraday stock backtest have so many more trades than the same strategy on forex?
Because each trading day starts fresh. The same rules on a forex chart can hold one position for a week; on an intraday stock chart that becomes five separate trades, one per day. More trades is not automatically better or worse, but it does change what the numbers mean -- and it multiplies your transaction costs, which is worth checking against your commission and slippage settings.

From Loop to Results

After the loop finishes, the engine passes two outputs to the metrics calculator: the equity curve (portfolio value at every candle) and the trade log (every entry and exit with prices, times, and returns). From these two datasets, Simula calculates every metric you see in your results -- returns, drawdown, Sharpe ratio, win rate, and everything else.

Where to Go Next

Limitations & Pitfalls -- biases beyond the engine itself, like survivorship bias, overfitting, and regime change.

Entry & Exit Conditions -- how crossovers, thresholds, and logic operators define the rules the engine evaluates at step 2.

Multi-Timeframe Analysis -- how the same loop checks conditions that reference a higher timeframe than the chart.

Spreads, Commissions & Slippage -- how transaction costs are applied during position entry and exit.

Metrics -- deep dives into every metric calculated from the equity curve and trade log.