VEEMANDocs
DocumentationSupportOpen Dashboard

Getting started

  • Introduction
  • Quick start
  • Core concepts

Importing data

  • Supported formats
  • How import works
  • Splitting a file
  • Troubleshooting

Building your portfolio

  • Workspace & equity
  • Weights & capital
  • Weekday filter
  • Keyframes
  • Currencies & FX
  • Library
  • Strike guard
  • Variants & comparison
  • History (undo/redo)
  • Shared spaces

Analytics

  • Metrics reference
  • Charts (deep-dive)
  • Monthly P&L
  • Correlations
  • Comparison
  • Monte Carlo
  • Equity Control
  • Optimization
  • IBKR reconciliation
  • Veeman AI

Research

  • Research overview
  • Define
  • Composing a backtest
  • How the engine trades
  • Results & archive
  • Parameter study
  • Rewind
  • Tactics
  • Indicators

Reference

  • Keyboard & command palette
  • Exporting data
  • Settings

Technical

  • Architecture
  • API reference
  • Security
  • Your data & privacy
  • Risk disclosure
← PreviousHow the engine tradesNext →Parameter study

Backtest results & archive

When a run finishes, the Backtest page switches to the results view: one surface that reads from top to bottom, from what ran to what it produced to every single trade.

The results bar

At the top:

Run name
A descriptive name derived from the recipe (structure, time, target/stop). Click it to rename: this is the name the backtest gets in the archive. A name you chose survives re-runs; a derived one is recomputed. Hover it to see when the run happened (or reopened for a saved backtest opened without re-running).
Saved as
After saving, the archive name and a link to the archive.
Run history
Appears from the second run on, with how many runs there are. Opens the run history in a panel over the page.
New backtest
Reopens the recipe with this run's parameters, ready to be varied. It never resets: resetting is an explicit action inside the recipe.
Save backtest
Stores the run in the archive.

The recipe band

Right under the bar, the recipe that produced these numbers, in plain words: Structure (the legs as a small table: side, type, quantity and criterion; a leg placed at an offset from another leg sits indented under it, with its signed distance, +35 pt above that leg's strike and −30 pt below; an offset from spot says from spot), Period, Sizing, Entry, Exit and Costs. Each cell is a shortcut: clicking it reopens the recipe with this run's parameters and the matching settings of the plan open (Period opens the period, Sizing With, Entry the entry time, Exit the target, Costs the costs; Structure takes you to the legs). It always describes the run on screen, not what you may be editing.

Headline KPIs

The first band describes the whole run, whatever period the charts show.

Net P&L
What the strategy made over the whole run, without the starting capital: ending equity − starting capital. Underneath: the total return in % (net P&L ÷ starting capital) and the CAGR = (ending ÷ starting)^(1 ÷ years) − 1, with years = days between the first and last date of the daily series ÷ 365.25.
Max drawdown
The deepest fall of the daily equity from its running peak, in % of that peak (the starting capital counts as the first peak). Underneath: MAR = CAGR ÷ |max drawdown %|.
Sharpe
Annualised Sharpe of the daily series net of the risk-free rate (the period-average 3-month US T-bill), computed by the same engine as Analysis. Underneath: Sortino, same basis. Definitions in Metrics.
Win rate
Winning positions ÷ positions. Underneath: Profit F. = gross profit ÷ gross loss of the positions (— when there are no losing positions).

Positions, not rows

Every per-trade figure counts positions. A position closed in three pieces (partial exits, leg groups) is one trade with the sum of its P&L. Adjustments opened by a Tactic are not trades of their own: their P&L is in the equity and in the net P&L, but not in win rate, profit factor or the per-lot averages.

The filter funnel

When at least one filter excluded something, a thin bar under the KPIs answers the first question of every backtest: why so few trades? It reads N of M days traded, and the bar shows how the days of the period were spent. The ⓘ gives the full cascade:

  • the days in the period, minus the days each day filter removed (in cascade order; each day is counted once, at the first filter that excluded it), down to the days with trades and the number of trades. Economic event rules appear as economic event (a Skip rule) and not an event day (an Only rule); custom indicators as no indicator data that day and, with entries that follow an indicator signal, no indicator signal that day;
  • the entry attempts refused at the clock, by reason (economic event around the release, intraday move, VIX not open yet, VIX at entry, ORB, custom indicator condition, custom indicator still warming up, chain missing, strikes not quoted, spread too wide, premium out of range, not enough margin, open-position limit…). These are attempts, not days: a day with three entry times can refuse three.

When no day traded at all, the most restrictive step is shown in plain text. If the days were lost to refused entries, it names the reason that refused the most attempts (for example no entry: premium out of range).

Equity and drawdown

Two charts share the time axis: the equity (starting capital + cumulative daily P&L, with a dashed reference at the starting capital) and the drawdown in dollars below it.

The period selector (1M · 3M · 6M · YTD · 1Y · ALL) zooms both. On a window, the equity keeps its level (it continues from the cumulative P&L before the window) while the drawdown is re-anchored to the start of the window: the peak is reset there, so you read the drawdowns within that window. The KPIs keep describing the whole run, as the note under the selector reminds you.

Run history and ghost curves

The page remembers your last 6 runs of this browser tab. The Run history button in the results bar shows how many there are; click it to open a panel with one row per run. The panel stays open while you pin runs, and closes when you click outside it, press Esc, scroll the page or open a run. From the keyboard, focus moves into the panel when it opens and leaving it closes it:

Overlay
Pin a run to draw it on the equity chart as a dashed ghost curve (up to 4), in the same colour as its row.
Run
Number and name. The run on screen is tagged on screen; a run with an identical recipe is tagged same recipe. Click a row to show that run's results.
Differences
What changed against the run on screen, computed on the frozen recipes: structure, entry, target, stop, period, filters, costs…
P/L · Δ vs on screen · Max DD · Trades
The headline numbers, and the P&L difference against the run on screen.

The runs overlaid on the chart are listed right above the equity, each with its dash and colour; the × next to a name takes it off the chart without reopening the history.

The history survives moving to other pages of the app, not a reload: what matters, you save.

Run metrics

A second band of compact figures:

Net P/L
The total, and the average per lot per trade (mean of each position's P&L ÷ its contracts).
Premium collected
Σ entry credit × contracts × the contract multiplier (100 on SPX) over the positions (debits count negative). Underneath: capture = net P/L ÷ |premium collected|, the share of the premium the strategy kept.
Avg winner · Avg loser
Mean per-lot P&L of winning and losing positions, with the best and the worst per lot.
Trades
Number of positions, with the number of winners.
Avg duration
Mean minutes from entry to the position's last exit.

Warnings

If the engine had to approximate or skip something, the Warnings box lists it before the detail (up to eight lines, each aggregated by type with the dates involved). The full list of what can appear is in How the engine trades.

Detail tabs

Annual metrics

One row per calendar year: the return on the capital at the start of that year (the equity carries over from year to year) and the worst drawdown within the year. Both columns share one scale, so a year's return can be weighed against the dip it cost. The first and last years may be partial.

Detailed metrics

The full metrics ledger of Analysis, computed by the same engine as the Metrics module on the daily series of the backtest, with the backtest's starting capital: capital (initial, final, net profit, %, plus the average per trade), ratios (CAGR, Sharpe, Sortino, Calmar, K-ratio), drawdown and risk (max drawdown % and $, longest and average drawdown duration, annual volatility, VaR and CVaR 95%, the risk-free rate used) and the daily distribution (win rate, profit factor, best and worst day, 5th percentile day, average and median daily win and loss, longest winning and losing streaks).

The average per trade is the one row on a per-trade basis: net P/L ÷ number of trades, the average result of a whole position with all its contracts (the per-lot average is the one under Net P/L in the headline KPIs).

The other rows are, to the cent, the numbers you will read in Analysis after saving the backtest. Their basis is the day, while the headline KPIs other than Sharpe and Sortino are per position: with several entries per day, win rate and profit factor can differ between the two, by construction. Backtests saved before this tab existed show a note asking to re-run them.

Trade log

Every position, partial exit and adjustment, one row each:

Opened
Date and entry time.
Open price
The index at entry.
Strategy
The run name, or for an adjustment a Tactic badge with the Tactic's name and the rule that fired (shown only when the run has Tactics).
Legs
Each leg as quantity, strike, STO (sold to open) or BTO (bought to open) and its entry fill.
Premium
The entry credit (cr) or debit (db) per structure, in $ as a broker quotes it ($16.40 db).
Close price · Closed
The index and the time at exit.
Close cost
What it cost to close (db) or what closing brought in (cr), per structure, in $ like the premium, slippage included.
Close reason
Target hit, Stop loss, Leg stop (the per-leg stop: one leg hit its level and the whole position closed), Settlement, Early exit, Economic event (the close before an economic release), Underlying move, Position delta, Short tested, Minutes in trade, Trailing stop, Technical indicator, Custom indicator, Short/long ratio, VIX move, VIX9D / VIX ratio, Profit action, Timed action, Closed at position limit, or a Tactic exit. A piece of a position also says partial q/n and/or group X.
P/L
The booked P&L, after slippage and commissions.
Margin
The maximum loss at expiration of the row's legs × contracts, the same definition the engine uses for sizing. Empty for undefined-risk structures.
P/L %
P&L ÷ |premium × contracts × the contract multiplier|.
Time in market
Minutes from entry to exit (hidden by default).

Above the table: Sort (opened, P/L, premium, P/L %) and direction, an Outcome filter (all, settlement, target, stop, time exit: early exit, minutes in trade and the close before an economic release; stop also keeps the per-leg stops; target and stop appear only when the recipe can close that way: its own profit target or stop loss, its per-leg stop, a leg group's, or one set by a profit or timed action), Columns (show, hide and reorder, remembered by the browser) and Export CSV (see The exported CSV). A timeline scrubber under the toolbar moves through the trades over time; the table pages 25 rows at a time.

The ▶ button on each row opens that trade in Rewind: from a saved backtest through a permanent link, otherwise by handing the trade over directly (same fills, same costs, no need to save first). Rewind keeps the log at hand: it steps to the previous or next trade in the log's current sort and filter, and Trade log brings you back here (Moving through the list).

The exported CSV

Export CSV always writes the standard options trade log layout: the same 28 columns, in the same order and units, as the trade logs that Import reads. A backtest can therefore be compared row by row with a log from another backtester, or imported into Analysis as a strategy with its legs (replayable in Rewind). The rows follow the log's current sort and Outcome filter; the Columns choice only affects the table on screen.

Date / Time Opened · Closed
Entry and exit, US Eastern time. An expired position closes at the session close.
Opening / Closing Price
The index at entry and at exit.
Legs
Quantity (ratio × contracts), expiration, strike, P/C, STO/BTO and the leg's entry mid. With position slippage the mid is the engine's nickel-rounded mid; the difference between the legs and the Premium is the entry slippage.
Premium
The entry credit per contract in dollars, after slippage (negative for a debit).
Days in Trade
Calendar days from entry to exit (0 for 0DTE).
Avg. Closing Cost
What closing cost per contract in dollars, worked out so that P/L = (Premium − Avg. Closing Cost) × contracts − commissions holds on every row. It therefore includes exit slippage, and an exit booked at its target or stop level. 0 when the position expired worthless.
Reason For Close
Expired, Profit Target, Stop Loss, or the log's own label for any other exit.
P/L · P/L %
As in the log.
Funds at Close
The recipe's starting capital plus the P/L of every trade closed up to this one, in closing order (all trades of the run, whatever the filter).
Margin Req.
The log's Margin: maximum loss at expiration × contracts; empty for undefined risk.
Underlying · Strategy
The recipe's underlying and the run name.
Opening / Closing Commissions + Fees
Commissions paid to open and to close. Settlement pays nothing to close.
Opening / Closing Short/Long Ratio
Mid premium of the short legs ÷ mid premium of the long legs, at entry and at exit. 1 when both are worth nothing (expired worthless); empty with no long legs.
Opening / Closing VIX
The VIX at entry and at exit, read like the entry filters: the value at a minute is the previous bar's close, never a later one. Empty on days without minute VIX in the dataset.
Gap · Movement
In index points: the day's open minus the prior close, and the index at entry minus the day's open.
Max Profit · Max Loss
The best and worst open P&L while the trade was on, as a % of the entry premium, at mid marks (no closing spread), up to the row's exit; an expired position also counts its value at settlement, never the quote of the closing bell. Max Profit is never below 0, Max Loss never above 0.

Backtests saved before these columns existed leave the commission split, ratios, VIX, gap, movement and Max Profit/Loss empty: run them again to fill them in.

The page remembers where you were while you move around the app (not across a reload): the open tab, the log's sort, direction, Outcome filter and page. Coming back from Rewind, the results reopen on the run you were reviewing, on the page of the last trade you viewed, with its row marked and scrolled into view.

Economic events

An analysis not everyone needs, so it sits in the More menu at the end of the tabs, not in a tab of its own. It answers the question to ask before adding an economic event rule: does this strategy really behave differently on those sessions? It is computed when you open it, on the run on screen, with the event calendar of the day.

At the top choose the sessions to look at: Day before, Event day or Day after (the choice is remembered). For every event type, against the other sessions of the backtest:

Sessions
The sessions of the period hit by the event, and how many of them traded. Sessions outside the dates known for that event (for example ISM before 2021) are left out of the comparison, and an info icon next to the event says how many.
Avg per traded session
The average P&L of the traded event sessions, with the average of the other traded sessions under it. Averages are per traded session, so a strategy that trades only some days isn't diluted by the days it stays out.
Win rate
Share of traded event sessions that closed in profit, against the others.
Difference (90%)
The event average minus the others' average, with its 90% band from a block bootstrap of the daily rows (whole runs of days are resampled together, so the real autocorrelation stays).
Sessions are
Worse or Better only with two signs: the band excludes zero, and a placebo test agrees. The placebo moves the event's dates to other sessions of the same period (keeping their pattern: spacing, clusters) and recomputes the difference a thousand times; the real dates must give a difference that only 5% of the moved ones reach. A few sessions of a lopsided P&L (many small gains, rare large losses) easily look better by chance, which the bootstrap band alone doesn't catch. No clear difference otherwise; Too few to tell below 10 traded sessions on either side, where the numbers are shown without a verdict.
If skipped
What happens with those sessions at zero and every other session unchanged: the change in P&L and the change in Sharpe, with its 90% band. It holds for same-day strategies without carry-over; for the exact run, add the rule and run it.

The verdict and the If skipped column answer two different questions. The Sharpe here is computed on the daily P&L (annualized, without the risk-free rate), and skipping ordinary sessions moves it too (for a profitable strategy it drops a little, because fewer days trade): a small negative change doesn't mean those sessions are good. Read the verdict to know whether the sessions differ, and If skipped to see what a rule would do.

Above the table, a check for chance. With eighteen event types tried at once, one always looks different. A White Reality Check (the empirical max test also used by the Study) measures how often luck alone would produce a difference as large as the most different type's from the strategy's average session (over the dates known for that type), given how many types were compared: below 5% it says the difference goes beyond chance, otherwise it reminds you to read the single verdicts with care.

Saving

Save backtest stores the run (recipe, dataset version, daily P&L, trade log, statistics, warnings) under the run name. Inside a shared space it is saved in the space; the "Saved as" note only appears while you are in the scope where it was saved.

Names in the archive are unique: two backtests never share one. Names are compared ignoring letter case and extra spaces, so "Iron Fly 30" and "iron fly 30" count as the same name. If the run name already belongs to a saved backtest, saving asks what to do:

Overwrite
Replaces that backtest with this run: recipe, results and trades are the new ones, while its tags, note and hidden mark carry over. The replaced backtest is removed as if you had deleted it: a portfolio that already contains it keeps the series it loaded, but loses the Rewind button on those trade log rows. Inside a shared space the replaced backtest goes to the trash and can be recovered.
Save under this name
Saves this run as a new backtest under the name you type, and the run on screen takes that name. It stays off until the name is free.

Saving again a run that is already saved under that name does nothing: its results can't have changed. Backtests saved before this rule may still share a name: rename one with Edit name, note & tags.

A saved backtest is reopened without re-running (the historical data doesn't change): from the archive, from the ⌘K palette (Backtests), from the Overview, or from a link. Its recipe is loaded into the composer, so it can be varied and re-run like any run, or used as the starting recipe of a study.

The backtest archive

Backtest archive lists every saved backtest. Open it from the Research sidebar or from Archive, next to the Compose · Study · Results switch at the top of the Backtest page (the runs of the tab are still there when you come back). It shows them as cards or as a dense list (the toggle on the right of the toolbar; the choice is remembered on this device). On a phone the archive always shows cards. A header above the toolbar counts the backtests (filtered/total while a filter is on). Each item shows its name with the Veeman mark (the same sign the backtest carries wherever it appears in Analysis), the period of its data, the number of trades, when it was saved, its tags, its note and the key figures of its run. Cards add a sparkline of the equity. In the list the figures sit right next to the name and the actions line up on the right: Open, Rewind, Save as strategy and the ⋯ menu. When the list is too narrow for their labels they become icons, and hovering one names it.

The figures are the run's own statistics, the same ones its results page shows (Sharpe and Sortino included, with the same risk-free rate). By default you see P/L, CAGR, Max DD, Sharpe, Win rate and Profit F.; the Metrics picker in the toolbar lets you choose between two and six of P/L, MAR, CAGR, Max DD, Sortino, Profit factor, Sharpe, Win rate and Volatility. Backtests saved before a figure existed show a dash for it.

The toolbar works like the Analysis library toolbar:

  • Search by name or by the text of the note.
  • Sort by Date, Name, P/L, CAGR, Max DD, Sortino or Profit factor, ascending or descending.
  • Filter by structure: one chip per structure in the archive (Iron Condor, Bull Put Spread, Buy Put…), with how many backtests use it. The structure is read from the legs of the recipe, not from the name, so a renamed backtest stays in its group. The row appears once the archive holds at least two structures; All turns the filter off.
  • Filter by underlying: the same, per underlying, once the archive holds more than one.
  • Filter by tag: pick one or more tags to show only the backtests carrying any of them. Clicking a tag on an item filters by it too.

Clear filters, next to the count and in the "no matches" message, resets the search and every filter at once.

Notes

A note is free text attached to a saved backtest: why you kept it, what it showed, what to try next. Up to 1,000 characters, line breaks included. Cards show the first three lines (hover for the rest); the list shows the first line under the name. Click a note to edit it, or use Add a note (on a card, or in the ⋯ menu). The note travels with the backtest in a shared space, but not into the strategy copy made by Save as strategy.

In the edit form, ⌘↵ (Ctrl+Enter) saves from any field and Esc cancels; if you changed something, Esc asks before discarding it.

Tags

Tags are free labels (0dte, iron condor, live…), normalized like the library's: lowercase, up to 24 characters each and 12 per backtest. They share one vocabulary with the Analysis library, and the tag field suggests the ones you already use (see Tag suggestions). Each item offers:

Open in Backtest
Reopens the backtest on the Backtest page (clicking its name does the same): the saved results, without re-running, and its recipe in the composer, ready to change and run again or to start a study from. In the list view it reads Open.
Save as strategy
Writes a permanent copy into the Analysis strategy library (see below). The copy takes the backtest's tags with it.
Rewind
Opens Rewind on this backtest, to pick a trade to replay.
Edit name, note & tags
Renames the backtest or changes its note and tags, in place. Recipe, results and trades are untouched. A name that another backtest in the archive already has is refused: the form says so and Save stays off until you pick another one.
Add a note / Edit note
Opens the same form with the cursor in the note.
Delete
Removes the backtest from the archive, after confirmation. Strategies already saved from it keep their own copy of the series.

In a shared space the ⋯ menu also offers versions, comments and copying, and an edit made while someone else saved the same backtest is stopped with a conflict instead of overwriting their change.

Into Analysis

A saved backtest is a strategy for Analysis, through two doors:

  • Automatically. Every saved backtest appears in the Analysis library as a strategy row marked with the Veeman mark next to its name, without any copy being made. You can add it to a session, combine it with other strategies, run Monte Carlo, size it. In the workspace trade log each of its trades shows its entry time, its premium and its margin (the maximum loss at expiration, as above), per backtest position: for a backtest leg one contract is one position of the backtest.
  • Save as strategy. Makes the copy explicit: a library strategy with the daily P&L series, the per-trade detail (used by Risk Sizing and Veeman AI), the backtest's starting capital as the initial capital, the research tag and the provenance (recipe and dataset version). The copy keeps the Veeman mark in the library.

The metrics never change across the bridge: Analysis recomputes them with the same engine and the same capital the detailed metrics tab used. From a library strategy born from a backtest, Reopen in Research loads its frozen recipe into the Backtest console and runs it again.

When a portfolio holds several backtests that trade the same strike at the same time, the strike guard asks what each strategy should do (shift the structure, shift the leg, or skip the entry) and the portfolio uses the backtests re-run with that rule. The archived backtest is never changed by it.

Updated to the latest data

A saved backtest stops at the last day of market data that existed when it ran. From a portfolio, Update data re-runs its Veeman backtests on today's data, and each new run replaces the backtest in the archive the way Overwrite does: same name, tags, note and hidden mark, the earlier run removed. A recipe that ran to the end of the data has its end date moved to the latest day; a recipe with no end date keeps none; a recipe that ends on a date chosen before the data did (an in-sample, a study period) is extended only if you ask.

Every run records the last day of market data available when it ran. That is how an update tells a recipe that follows the data from one that stops on purpose. The new run also remembers which run it replaced, so a portfolio still on the earlier run finds it the next time it is updated, and a strategy saved from the backtest with Save as strategy follows it onto the new run.

A backtest with economic event rules (or a close before economic events) also records the version of the event calendar it was resolved on, and every update resolves the rules again on the calendar of the day: a release added or rescheduled since the earlier run is taken into account. A backtest that is already at the latest day but was resolved on an older calendar is run again too; if its trades don't change, only the record of the calendar is refreshed.