Backtest

[backtest] defines the global environment in which your strategy runs.

It sets the test period, the symbols and timeframes to load, the initial capital, fees and slippage, the entry sizing rules, and the parameters related to margin, leverage, and pyramiding.

A strategy file can contain only one [backtest] block.

See the Exchanges, Symbols and Timeframes page for symbol and timeframe interpretation.

The logic for margin, leverage, account equity, sizing price, execution price, and liquidation is described in the Using Margin and Leverage in Whale‑E page. The [backtest] block only exposes the configuration options needed by that logic.

How numeric ranges with .start, .stop and .step are combined with indicator ranges is explained in the Hyperparameter Combinations page.

Block declaration

A strategy can contain only one [backtest] block.

Examples

The following examples show complete configurations you can adapt to your own strategies. The detailed behaviour of default_qty_type, default_qty_value, margin_*, and the size multipliers is described in Using Margin and Leverage in Whale‑E.

Minimal setup

This minimal configuration defines a single symbol, a single timeframe and a test period. All other settings use their default values.

[backtest]
symbol          = "BINANCE:BTCUSDT"
timeframe       = "240"
start_date      = 2024-01-01
end_date        = 2025-01-01
initial_capital = 1000

Backtest without explicit leverage in terms of exposure

This block configures a backtest where orders are sized as a percentage of account equity. Margin parameters remain at their defaults, and allocation stays below 100% to keep a safety buffer for fees and sizing-to-fill price gaps in the default 1x frame.

[backtest]
symbol            = "BINANCE:BTCUSDT"
timeframe         = "240"
start_date        = 2024-01-01
end_date          = 2025-01-01
initial_capital   = 1000
default_qty_type  = "percent_of_equity"
default_qty_value = 95

Backtest with margin and asymmetric multipliers

This block shows a configuration where positions are opened with a limited share of equity, margin is below 100%, and size multipliers differ on the long and short side.

[backtest]
symbol                = "BINANCE:BTCUSDT"
timeframe             = "240"
start_date            = 2024-01-01
end_date              = 2025-01-01
initial_capital       = 1000
default_qty_type      = "percent_of_equity"
default_qty_value     = 30
margin_long           = 50     # 50 % margin on long positions
margin_short          = 50     # 50 % margin on short positions
long_size_multiplier  = 5      # ×5 size multiplier for longs
short_size_multiplier = 2      # ×2 size multiplier for shorts

Exploring capital allocation

The default_qty_value range defines a series of equity allocations from 10 % to 95 % in steps of 5. With default_qty_type = "percent_of_equity", this key is the global exposure base before any side multiplier is applied.

[backtest]
symbol                  = "BINANCE:BTCUSDT"
timeframe               = "240"
start_date              = 2024-01-01
end_date                = 2025-01-01
initial_capital         = 1000
default_qty_type        = "percent_of_equity"
long_size_multiplier    = 4
default_qty_value.start = 10
default_qty_value.stop  = 95
default_qty_value.step  = 5

Exploring the long multiplier with fixed allocation

Capital allocation is fixed at 40 % of equity with default_qty_value = 40. The long_size_multiplier range then defines a set of size multipliers for long positions. This pattern is useful in grid search because it keeps a shared base and varies only long-side exposure.

[backtest]
symbol                     = "BINANCE:BTCUSDT"
timeframe                  = "240"
start_date                 = 2024-01-01
end_date                   = 2025-01-01
initial_capital            = 1000
default_qty_type           = "percent_of_equity"
default_qty_value          = 40
long_size_multiplier.start = 1
long_size_multiplier.stop  = 10
long_size_multiplier.step  = 0.5

Exploring allocation and size multipliers together

Equity allocation and both the long and short size multipliers are explored at the same time. Each combination of these parameters produces a separate backtest run.

This example is mainly relevant for strategies that can open both long and short positions. In that case, default_qty_value defines a shared base, while long_size_multiplier and short_size_multiplier adjust each side separately. On a one-sided strategy, these parameters largely collapse into the same thing on the active side, so the value of this joint optimisation becomes much more limited.

[backtest]
symbol                      = "BINANCE:BTCUSDT"
timeframe                   = "240"
start_date                  = 2024-01-01
end_date                    = 2025-01-01
initial_capital             = 1000
default_qty_type            = "percent_of_equity"
# Equity allocation range
default_qty_value.start     = 10
default_qty_value.stop      = 50
default_qty_value.step      = 5
# Long‑side size multipliers
long_size_multiplier.start  = 1
long_size_multiplier.stop   = 10
long_size_multiplier.step   = 0.5
# Short‑side size multipliers
short_size_multiplier.start = 1
short_size_multiplier.stop  = 10
short_size_multiplier.step  = 0.5

Parameters of the [backtest] block

The table below lists all parameters available in the [backtest] block. When the description mentions other documentation pages, those pages contain the detailed explanations. For everything related to sizing, margins, and multipliers, the reference page remains Using Margin and Leverage in Whale‑E.

ParameterDescription
start_date
 Date‑Time
 Required
Start date of the backtest. Dates may include a numeric offset. The engine always runs internally in UTC, but it first interprets both start_date and end_date using a fixed inferred offset, then converts them to UTC.

Offset inference and validation rules:
  • If start_date and end_date both have the same explicit offset (for example +02:00), that offset is used.
  • If only one of the two dates has an explicit offset, the other date is interpreted with that same offset.
  • If neither date has an explicit offset, both dates are interpreted in UTC.
  • If start_date and end_date have different explicit offsets, the configuration is rejected.

Accepted formats:
  • ISO 8601 string with Z (UTC) or an explicit ±HH:MM offset (for example "2024-06-01T12:30:45Z", "2024-06-01T12:30:45+02:00").
  • ISO 8601 string with a space separator and no offset (for example "2024-06-01 12:30:45").
  • Date‑only ISO 8601 string without offset (for example "2024-06-01", interpreted as local midnight).
  • TOML offset-date-time, local-date-time or local-date types, following the same rules.
Named timezones are not supported. The offset remains fixed for the whole backtest.
end_date
 Date‑Time
 Required
End date of the backtest. It uses the same formats and offset rules as start_date.
price_history_start_date
 Date‑Time
 Optional
Explicit start date for the price history fetch window. This key only controls how much upstream data is loaded and does not change the business backtest window (start_date/end_date). It follows the same date formats and offset rules as start_date and end_date.

If omitted, Whale‑E keeps the current automatic lookback-based behaviour. If provided too late to satisfy the minimum required lookback, Whale‑E automatically clamps it backward to the required minimum and emits a warning.
Default: automatic calculation.
symbol
 String
 or Array
 Required
Main symbol of the simulation. Can be a single string (for example "BINANCE:BTCUSDT") or an array of symbols. The exchange prefix is required in the form EXCHANGE:SYMBOL. When several symbols are provided, Whale‑E builds a grid for each symbol/timeframe combination. The Exchanges, Symbols and Timeframes page describes the supported formats in detail.
timeframe
 String
 or Array
 Required
Main timeframe of the backtest. Can be a single string (for example "60", "240", "D", "W") or an array of timeframes. When several timeframes or symbols are given, Whale‑E creates a separate grid for each symbol/timeframe combination. The way indicators override their own timeframe is described in the Exchanges, Symbols and Timeframes page.
auto_slippage_enabled
 Boolean
 Optional
Enables automatic slippage based on one‑minute candles. If false, slippage is defined only by slippage.
Default: false.
auto_slippage_ratio
 Decimal
 Optional
Ratio applied to the one‑minute highlow range when computing automatic slippage. Ignored when auto_slippage_enabled is false.
Default: 0.25.
slippage
 Integer
 Optional
Number of price ticks added manually as slippage to the execution price. Used only when auto_slippage_enabled is false.
Default: 0.
backtest_fill_limits_assumption
 Integer
 Optional
Minimum overrun, in ticks, required to consider a LIMIT order as filled. A value of 0 means a simple touch. This parameter applies to LIMIT entries and to the LIMIT leg of STOP_LIMIT entries.
Default: 0.
use_bar_magnifier
 Boolean
 Optional
Enables intrabar inspection using a lower timeframe to determine the actual order of events inside an aggregated candle (for example “entry then stop” on the same bar). When disabled, the intrabar order is inferred only from OHLC data at the main timeframe.
Default: false.
process_orders_on_close
 Boolean
 Optional
Controls when orders submitted on a bar close become eligible for execution. When false, an order created on a bar close can only be executed starting from the next bar open (the first available tick in historical backtests). When true, orders can be processed on the current bar close tick.
Default: false.
max_blocks_on_same_candle
 Integer
 Optional
Maximum number of blocks executed on the same candle without advancing to the next candle. Used to detect and stop infinite loops. Set to 0 to disable.
Default: 1024.
commission_value
 Decimal
 Optional
Commission value, interpreted according to commission_type. In percent mode it is a percentage and must remain strictly below 100. In cash_per_contract or cash_per_order mode it is a fixed amount in quote currency.
Default: 0.1.
commission_type
 String
 Optional
Commission mode. Possible values are percent, cash_per_contract and cash_per_order.
Default: "percent".
initial_capital
 Decimal
 Optional
Initial capital of the backtest, in the quote currency of the main symbol.
Default: 1000000.
default_qty_type
 String
 Optional
Global mode used to compute entry size: fixed, cash, or percent_of_equity.
Default: "percent_of_equity".
default_qty_value
 Decimal
 or Range
 Optional
Public global sizing value used by entry blocks when the block does not define qty or qty_percent. In fixed mode, this value is an absolute quantity. In cash mode, it is a monetary budget. In percent_of_equity, it is the global percentage base before any long_size_multiplier or short_size_multiplier is applied. A single value is accepted in every mode. .start, .stop and .step variants are accepted only in percent_of_equity for grid search.
Default: 100 in percent_of_equity. In fixed and cash, if default_qty_value is absent and no local qty or qty_percent is provided, the order is rejected.
margin_long
 Decimal
 Optional
Margin percentage applied to long positions. Required margin for a long is the notional value multiplied by margin_long / 100. A value of 0 disables the margin system for long positions. This option also supports .start, .stop and .step suffixes for grid search. The full margin and liquidation behaviour is described in Using Margin and Leverage in Whale‑E.
Default: 100.
margin_short
 Decimal
 Optional
Margin percentage applied to short positions. Required margin for a short is the notional value multiplied by margin_short / 100. A value of 0 disables the margin system for short positions. As for margin_long, .start, .stop and .step variants can be used for grid search.
Default: 100.
long_size_multiplier
 Decimal
 Optional
Multiplier applied to the global base defined by default_qty_value for long orders in percentage-based sizing modes. A value of 1 leaves the size unchanged. This option can be set as a single value or as a range (.start, .stop, .step) for grid search. It is ignored for entry sizing in fixed and cash modes.
Default: 1.
short_size_multiplier
 Decimal
 Optional
Multiplier applied to the global base defined by default_qty_value for short orders in percentage-based sizing modes. A value of 1 leaves the size unchanged. As with the long side, .start, .stop, .step variants are available for grid search. It is ignored for entry sizing in fixed and cash modes.
Default: 1.
pyramiding
 Integer
 Optional
Maximum number of entries allowed in the same direction for a position. A value of 1 disables pyramiding and limits the position to a single entry. A value N allows up to N cumulative entries before additional entry signals are ignored.
Default: 1.
close_entries_rule
 String
 Optional
Rule used when a [[close]] block consumes entries that are already open. In this context, order_id always references the order_id value of a [[entry]] block. With fifo, the engine closes the oldest open entries first, even when the [[close]] block targets a specific entry through order_id. With any, it closes the entry targeted by order_id first, then falls back to the oldest open entries if some quantity still needs to be closed.
Default: "fifo".
close_open_position_at_end
 Boolean
 Optional
Controls how a position that is still open at end_date is handled. When true, Whale‑E automatically closes the position at the end of the backtest so the result stays bounded to the selected window. When false, the position remains open in the engine and Whale‑E values it at end_date for the final calculation. No explicit closing trade is added at the end of the window. Default: true.

Additional notes

Automatic slippage and 1‑minute data

When auto_slippage_enabled is true, the engine applies slippage to each order based on the one‑minute candle in which the execution occurs. It takes that minute’s highlow range, multiplies it by auto_slippage_ratio, then shifts the execution price by that amount in an unfavourable direction.

The one‑minute candles required for this calculation are loaded automatically, whatever the main timeframe of the backtest is. When auto_slippage_enabled is false, slippage is defined only by slippage, and the engine does not simulate intrabar slippage.

Order size modes (default_qty_type)

The pair default_qty_type / default_qty_value defines the global method used to compute entry size for [[entry]] and [[order]] blocks, as long as no local qty or qty_percent override is present.

In fixed mode, entry size is an absolute quantity. If no local qty or qty_percent is provided, Whale‑E uses [backtest].default_qty_value. If that value is absent, the order is rejected.

In cash mode, entry size is a monetary budget. If no local qty or qty_percent is provided, Whale‑E uses [backtest].default_qty_value as the global fallback value.

In percent_of_equity mode, entry size is determined from a percentage of equity. default_qty_value defines that global base, then side multipliers can adjust it. In this mode, default_qty_value can be provided as a single value or as a range.

For the exact semantics of each mode, the reference page remains Using Margin and Leverage in Whale‑E.

Pyramiding

The pyramiding parameter sets the maximum number of entries that can be accumulated in the same direction for a single position.

A value of 1 disables pyramiding. Once an initial entry has been executed, no additional entry can increase the position until it has been fully closed or reversed.

A value N > 1 allows up to N successive entries in the same direction. The counter is reset when the position is fully closed or when it changes sign (from long to short or the opposite).

Timestamps and storage

Internally, the engine runs strictly in UTC. Interpretation of start_date and end_date, as well as formatting of timestamps in logs and database records, uses the fixed offset inferred from the dates you provide. This offset is constant for the full backtest.

Timestamps stored in the database include this offset in a dedicated context field (for example UTC+02:00).

End-of-backtest handling for open positions (close_open_position_at_end)

The close_open_position_at_end setting decides whether a position that is still open at end_date is closed or only valued.

With close_open_position_at_end = true, Whale‑E automatically closes the position at the end of the backtest. The result is then strictly bounded by the selected window, which is the most straightforward way to analyze a finished run.

With close_open_position_at_end = false, Whale‑E keeps the position open in the engine and values it at end_date for the final result. This keeps the terminal exposure visible, but some final values change because no explicit close is added at end_date.