Thin wrapper around the canonical engine path.
Usage
ledgr_backtest(
snapshot = NULL,
strategy,
universe = NULL,
start = NULL,
end = NULL,
initial_cash = 1e+05,
strategy_params = list(),
features = list(),
fill_model = NULL,
execution_mode = "audit_log",
checkpoint_every = 10000L,
persist_features = TRUE,
db_path = NULL,
control = list(),
run_id = NULL,
data = NULL
)Arguments
- snapshot
A
ledgr_snapshotobject, or a data frame for the data-first convenience path.- strategy
Strategy function or object with
$on_pulse(ctx)method. Functional strategies must usefunction(ctx, params).- universe
Character vector of instrument IDs. If
NULL, it is inferred from the snapshot or data frame.- start
Start timestamp (NULL = snapshot start).
- end
End timestamp (NULL = snapshot end).
- initial_cash
Starting capital. Must be a finite numeric scalar > 0.
- strategy_params
JSON-safe list passed to
function(ctx, params)strategies and stored as part of run provenance.- features
List of ledgr indicator definitions (optional).
- fill_model
Fill model config.
NULLuses ledgr's default next-open model with zero spread and zero fixed commission. Forfill_model$spread_bps, ledgr applies the full value on each fill leg: buys fill atopen * (1 + spread_bps / 10000)and sells fill atopen * (1 - spread_bps / 10000). A buy/sell round trip therefore costs approximately2 * spread_bpsbasis points before commissions.- execution_mode
Execution mode ("db_live" or "audit_log").
- checkpoint_every
Flush interval for audit_log mode.
- persist_features
If FALSE, skip persisting per-pulse features to DuckDB.
- db_path
Database path for the run ledger (NULL = snapshot DB).
- control
Optional list of engine overrides (e.g., execution_mode).
- run_id
Optional run identifier to resume or reuse.
- data
Optional data frame/tibble or
ledgr_snapshot. Exactly one ofsnapshotanddatamay be supplied.
Details
v0.1.7 introduces the experiment-first public workflow:
ledgr_experiment() plus ledgr_run(). ledgr_backtest() remains available
as a compatibility wrapper around the same canonical runner path.
Strategies return target holdings. The default fill model is next_open: a
target decided at pulse t is filled at the next available bar. Targets on
the final pulse therefore cannot be filled unless another bar exists after
end.
spread_bps is a per-leg execution adjustment, not a quoted bid/ask spread
split across the buy and sell legs. With spread_bps = 5, a buy fills five
basis points above the next open and a sell fills five basis points below the
next open, for an approximate ten basis-point round-trip cost before fixed
commissions.
v0.1.x does not provide a supported broker-style short-selling contract. Strategy authors should treat negative target quantities as outside the supported public workflow until explicit shorting semantics are specified.
Articles
Strategy authoring:
vignette("strategy-development", package = "ledgr")
system.file("doc", "strategy-development.html", package = "ledgr")
Metrics and accounting:
vignette("metrics-and-accounting", package = "ledgr")
system.file("doc", "metrics-and-accounting.html", package = "ledgr")
Examples
bars <- data.frame(
ts_utc = as.POSIXct("2020-01-01", tz = "UTC") + 86400 * 0:3,
instrument_id = "AAA",
open = c(100, 101, 102, 103),
high = c(101, 102, 103, 104),
low = c(99, 100, 101, 102),
close = c(100, 101, 102, 103),
volume = 1000
)
strategy <- function(ctx, params) {
targets <- ctx$flat()
targets["AAA"] <- if (ctx$close("AAA") > 100) 1 else 0
targets
}
bt <- ledgr_backtest(data = bars, strategy = strategy, initial_cash = 1000)
print(bt)
#> ledgr Backtest Results
#> ======================
#>
#> Run ID: run_1d019e9e180b970c
#> Universe: AAA
#> Date Range: 2020-01-01T00:00:00Z to 2020-01-04T00:00:00Z
#> Execution Mode: audit_log
#> Initial Cash: $1000.00
#> Final Equity: $1001.00
#> P&L: $1.00 (0.10%)
#>
#> Use summary(bt) for detailed metrics
#> Use plot(bt) for equity curve visualization
close(bt)