TL;DR
Use lake.backtest_runs for run statistics, but deduplicate on experiment_id before ranking or averaging performance. Exclude optimizer attempts when asking which retained strategies performed well, and compare similar assets, cadences and date windows. Keep backtest_uuid to retrieve the full rules. Baseline and alpha fields are unevenly populated, so restrict comparisons to eligible nonnull records. This page supplies an unexecuted query example and logical schema, not a finding that any strategy wins.
- Query name
- lake.backtest_runs
- Storage partition
- snapshot
- Columns
- 51
Columns and types
VARCHAR
- backtest_uuid
- portfolio_uuid
- experiment_id
- author_type
- date_range_bucket
- interval
- cadence
- asset_class
DATE
- start_date
- end_date
INTEGER
- duration_days
BOOLEAN
- has_options
Showing 12 of 51 recorded rows. The complete table is below.
Current logical schema for lake.backtest_runs
Inspect the complete lake.backtest_runs schema
Scroll sideways to compare all columns. Select a heading to sort.
| backtest_uuid | VARCHAR |
| portfolio_uuid | VARCHAR |
| experiment_id | VARCHAR |
| author_type | VARCHAR |
| start_date | DATE |
| end_date | DATE |
| duration_days | INTEGER |
| date_range_bucket | VARCHAR |
| interval | VARCHAR |
| cadence | VARCHAR |
| asset_class | VARCHAR |
| has_options | BOOLEAN |
| memory_class | VARCHAR |
| baseline_symbol | VARCHAR |
| starting_cash | DOUBLE |
| stock_fee_amount | DOUBLE |
| stock_fee_type | VARCHAR |
| crypto_fee_amount | DOUBLE |
| crypto_fee_type | VARCHAR |
| tickers | VARCHAR[] |
| n_strategies | INTEGER |
| n_comparisons | INTEGER |
| n_indicator_instances | INTEGER |
| distinct_indicator_types | VARCHAR[] |
| distinct_action_types | VARCHAR[] |
| uses_temporal_gating | BOOLEAN |
| min_temporal_threshold_days | DOUBLE |
| signal_frequency_class | VARCHAR |
| traded | BOOLEAN |
| warnings | VARCHAR[] |
| percent_change | DOUBLE |
| sharpe_ratio | DOUBLE |
| sortino_ratio | DOUBLE |
| max_drawdown | DOUBLE |
| avg_drawdown | DOUBLE |
| ulcer_index | DOUBLE |
| ulcer_performance_index | DOUBLE |
| win_rate | DOUBLE |
| profit_factor | DOUBLE |
| avg_trade_pnl | DOUBLE |
| dollars_sold | DOUBLE |
| total_dividends | DOUBLE |
| total_fees | DOUBLE |
| risk_free_rate | DOUBLE |
| baseline_percent_change | DOUBLE |
| baseline_sharpe_ratio | DOUBLE |
| baseline_max_drawdown | DOUBLE |
| alpha_pct | DOUBLE |
| alpha_sharpe | DOUBLE |
| time_elapsed_ms | BIGINT |
| created_at | TIMESTAMP |
No matching rows. Clear the filter to see all records.
Current logical schema for lake.backtest_runs
Query lake.backtest_runs using the column names and types below. The query validator and engine use this logical catalog; a field absent from an older shard returns typed NULL.
What this table contains
`backtest_uuid` identifies a run. Select it whenever strategy examples are wanted: NexusTrade hydrates the full strategy JSON from `lake.backtest_strategies` by that id. `portfolio_uuid` is a stable anonymized portfolio hash.
Summarize deduplicated non-optimizer runs
Query example, not executed here. The dates and filters define the proposed research scope; returned rows and current coverage must be checked in your workspace.
Each count is distinct experiment membership after one run is retained per experiment_id. Cohorts preserve asset class, cadence, interval and date-range bucket. Inspect the experiment count and date scope before interpreting a median; this query does not claim a winning strategy.
WITH eligible_runs AS (
SELECT *
FROM lake.backtest_runs
WHERE author_type <> 'optimizer'
QUALIFY ROW_NUMBER() OVER (
PARTITION BY experiment_id
ORDER BY created_at DESC, backtest_uuid
) = 1
)
SELECT asset_class, cadence, interval, date_range_bucket,
COUNT(*) AS experiments, MEDIAN(percent_change) AS median_return,
MEDIAN(max_drawdown) AS median_max_drawdown
FROM eligible_runs
GROUP BY asset_class, cadence, interval, date_range_bucket
ORDER BY experiments DESC
LIMIT 20;Submit the backtest_runs example and read back its parts
Run the exact SQL through the Python SDK
Save this page's SQL as query.sql and the runner below as query.py. Use a registered key with lake scope from Developers. The runner submits the displayed backtest_runs query once, saves its operation, waits on that same ID, saves the returned manifest and downloads its Parquet parts.
This submission has not been executed for the reference page. Inspect the SQL, dates and resource limits before running it. Reuse the request key only for this identical SQL and limits; use a new key when changing them.
python3 -m pip install nexustrade==1.42.0
export NEXUSTRADE_API_KEY="YOUR_LAKE_SCOPED_KEY"
python3 query.py
import json
from pathlib import Path
from nexustrade import NexusTradeClient
# Save the SQL displayed on this page as query.sql.
sql = Path("query.sql").read_text()
client = NexusTradeClient.from_environment()
operation = client.create_lake_query(
{"query": sql, "limits": {"timeoutSeconds": 30, "maxRows": 50,
"maxResultBytes": 1048576}},
idempotency_key="reference-backtest_runs-20261012-v1",
)
Path("query-operation.json").write_text(json.dumps(operation, indent=2))
finished = client.wait_for_lake_query(operation["id"])
if finished["status"] != "completed":
raise RuntimeError(finished)
manifest = client.get_lake_query_manifest(operation["id"])["result"]
Path("query-manifest.json").write_text(json.dumps(manifest, indent=2))
print(json.dumps(manifest, indent=2))
for part in manifest["parts"]:
Path(f"query-{part['part']}.parquet").write_bytes(
client.download_lake_query_part(operation["id"], part["part"], max_bytes=1048576)
)
Coverage and timing
Inspect source coverage and timing before using the rows
Anonymized backtest corpus: one row per run; other backtest_* tables join on backtest_uuid.
`backtest_uuid` identifies a run. Select it whenever strategy examples are wanted: NexusTrade hydrates the full strategy JSON from `lake.backtest_strategies` by that id. `portfolio_uuid` is a stable anonymized portfolio hash.
DEDUPLICATE ON `experiment_id` before any average, median or ranking. It hashes the strategy logic plus tickers plus window, and cloned or forked portfolios repeat one experiment under many `backtest_uuid`s (about 60% of rows are repeats), so an aggregate over raw rows measures what got cloned rather than what performed. Counting rows is fine. It is a hash: never pattern-match it.
`author_type` is 'optimizer' for genetic-search output and 'unknown' otherwise. Filter `author_type <> 'optimizer'` for any question about what performs well: a genetic search is a population of attempts, not strategies anyone chose to keep, and it is about a third of the corpus.
`tickers`, `distinct_indicator_types`, `distinct_action_types` and `warnings` are VARCHAR[]. Filter by overlap, e.g. `array_length(list_intersect(tickers, ['NVDA']::VARCHAR[])) > 0`.
`asset_class` is equity, crypto, options or mixed. `cadence` is daily or intraday. `signal_frequency_class` is unconstrained, sub_daily, daily, weekly, monthly or quarterly.
`alpha_pct` and the `baseline_*` columns are populated only for runs that carried validation statistics (nearly all options runs, very few daily-equity runs). Restrict to non-null rows before comparing them across asset classes. Return per day is `percent_change / duration_days`.
No comments yet.