Benchmark reports
The files that actually matter right now.
This page displays the key markdown reports directly from the repository. The point is to keep evidence review centered on benchmark results, correctness and repeatable commands.
Reproduction commands
pnpm bench:compare:ema:2signals-scale:correctness
pnpm bench:compare:ema:variant-scale:matrix
pnpm bench:compare:ema:freqtrade-persistent-variant-scale
pnpm bench:equivalence:complex:current-engine-export:controlled
pnpm bench:builder:production
Whitepaper documents
Start here when preparing product, whitepaper or grant material. These files explain what the numbers mean and how to avoid overclaiming.
docs/whitepaper/README.mdPresentation briefPractical presentation briefing: talk track, slide flow, key numbers, file map and Q&A.What to look for: Start here before a pitch or funding meeting. It tells you what to say, what to show and what to ignore.Open
2Signals Presentation Brief
Status: start here for presentations, funding conversations and whitepaper prep.
This file is intentionally practical. It does not replace benchmark reports or raw artifacts. It tells you what to say, which numbers to show and which files to ignore unless someone asks for technical due diligence.
One-Sentence Thesis
2Signals is building a correctness-checked, cache-aware strategy computation engine for interactive exploration of large trading-strategy spaces.
The Simple Story
- Strategy research is iterative: users do not run one backtest, they explore many nearby variants.
- The hard problem is not only speed. The hard problem is speed with correctness: same dataset, same indicators, same masks, same trades and same P/L.
- 2Signals now has controlled evidence that compares its results with Freqtrade and records timing boundaries.
- The strongest current evidence has two parts:
- a simple EMA side-by-side slice that compares correctness and timing;
- a more complex futures slice that proves correctness on a larger, non-trivial dataset.
- The next R&D step is to turn this into a canonical AST/IR and dependency invalidation engine, so strategy edits recompute only what changed.
The Numbers To Remember
| Point | Number | What it means | Caveat |
|---|---|---|---|
| EMA side-by-side correctness | 0 mismatches | 10 EMA variants matched between 2Signals and Freqtrade across indicators, masks, signals, trades and P/L. | Simple EMA fixture; not all strategies. |
| EMA 2Signals workflow | 20.25 ms | Median for 10 sequential variants in the 2Signals in-process boundary. | No UI, auth or network fetch. |
| EMA Freqtrade strategy-list workflow | 5.51 s | Median for one Freqtrade process running 10 strategies through --strategy-list. | Workflow timing, not pure engine timing. |
| EMA Freqtrade CLI workflow | 35.52 s | Median for 10 variants run as separate local Freqtrade CLI processes. | Includes repeated process startup and initialization. |
| Complex futures correctness | 123 trades, 0 mismatched fields | Fresh 2Signals and fresh Freqtrade matched on the complex futures boundary. | Controlled local frozen data, not full authenticated /builder. |
| Complex dataset | 181,447 candles | Seven USDT perpetual pairs on 5m data. | Local frozen benchmark fixture. |
| Complex 2Signals BacktestService | 2.45-2.47 s | Controlled current service boundary over frozen OHLCV/funding artifacts. | UI rendering excluded. |
| Complex Freqtrade Backtesting.start | 20.32 s | Marker around Freqtrade's backtesting phase. | Not a pure algorithm-only timer. |
Recommended 8-Slide Flow
| Slide | Title | What to say | Evidence |
|---|---|---|---|
| 1 | Problem | Strategy research is a high-iteration computation problem. Users compare many nearby strategy variants. | Product context. |
| 2 | Technical Thesis | 2Signals is not just a backtester; it is a correctness-checked, cache-aware computation layer. | docs/whitepaper/2signals-engine-v0.4.md |
| 3 | Correctness Model | We separate dataset correctness from strategy correctness. Timing without matching outputs is not useful. | docs/benchmarks/results/2signals-vs-freqtrade-main-v1.md |
| 4 | EMA Side-By-Side | 10 EMA variants: 0 mismatches, 2Signals 20.25 ms, Freqtrade strategy-list 5.51 s. | Main benchmark report. |
| 5 | Complex Futures | 181,447 candles, 7 futures pairs, 123 trades, 0 mismatched fields. | Complex current-engine export report. |
| 6 | UI Evidence | Production-like Builder render path is measured separately from engine timing. | benchmarks/results/builder-production-like-production/2026-07-26T22-25-07-155Z/benchmark-matrix.md |
| 7 | R&D Roadmap | Canonical AST/IR, dependency graph, invalidation, broader correctness corpus and exporter parity. | docs/whitepaper/evidence-package-v0.2.md |
| 8 | Ask | Funding supports turning controlled proof into a robust deep-tech engine. | Grant evidence summary. |
If You Have Only 5 Minutes
Use this order:
- "The product problem is interactive strategy exploration."
- "The technical problem is correctness-preserving reuse."
- "We now compare 2Signals with Freqtrade for both outputs and timing in controlled boundaries."
- "The simple EMA slice gives clear side-by-side timing and correctness."
- "The complex futures slice proves the approach on a non-trivial dataset."
- "The next funding step is AST/IR plus dependency invalidation, so this works across a broader strategy corpus."
What To Open During Prep
| Priority | File | Why |
|---|---|---|
| 1 | docs/benchmarks/results/2signals-vs-freqtrade-main-v1.md | Main answer to "how do we compare with Freqtrade?" |
| 2 | docs/whitepaper/2signals-engine-v0.4.md | Short current evidence summary with statistic descriptions. |
| 3 | docs/whitepaper/grant-evidence-summary-v0.2.md | Funding-friendly thesis and work packages. |
| 4 | /whitepaper in the app | Clean visual page for internal review and demos. |
| 5 | /whitepaper/evidence in the app | Formatted markdown reader for the supporting reports. |
Supporting Files
Open these only when someone asks for details:
| File | Use when asked about |
|---|---|
docs/benchmarks/results/controlled-ema-variant-scale-side-by-side-v1.md | EMA correctness, timing samples, boundaries and source artifacts. |
docs/benchmarks/results/controlled-ema-freqtrade-boundaries-v1.md | Freqtrade --strategy-list, CLI, phase timings and workflow caveats. |
docs/benchmarks/results/controlled-complex-current-engine-export-v1.md | Current 2Signals complex export correctness. |
docs/benchmarks/results/controlled-complex-freqtrade-frozen-boundary-v1.md | Fresh Freqtrade complex boundary, phase timings and artifact export. |
docs/whitepaper/evidence-freeze-v0.2.md | Hashes, commits, raw artifact paths and external verification. |
Historical Or Low-Priority Files
These are not the first thing to show:
| File or category | Current role |
|---|---|
docs/whitepaper/2signals-engine-v0.1.md | Historical architecture draft. |
docs/whitepaper/2signals-engine-v0.2.md | Historical evidence draft. |
docs/whitepaper/2signals-engine-whitepaper-v0.3.md | Older publication narrative; useful prose, not current source of numbers. |
| Generated whitepaper/deck pipeline ideas | Do not maintain now unless there is a concrete publication deadline. |
| Additional tiny EMA-only reports | Lower priority than broader correctness and one larger side-by-side slice. |
What Not To Claim
Avoid these formulations:
- "2Signals is universally faster than Freqtrade."
- "This is a pure engine-to-engine benchmark."
- "This proves parity for all strategies."
- "This is full authenticated
/builderlatency." - "The ML/LLM layer already exists as a proprietary trading model."
Use these instead:
- "In controlled local boundaries, 2Signals and Freqtrade outputs match for the current EMA and complex futures slices."
- "The timing rows are explicitly labeled workflow boundaries."
- "The evidence supports an R&D thesis: correctness-checked reuse for interactive strategy exploration."
Likely Questions And Answers
| Question | Short answer |
|---|---|
| Is this benchmark fair? | It is fair within named boundaries. We do not hide that 2Signals and Freqtrade execute through different workflows. |
| Why compare with Freqtrade? | Freqtrade is a known open-source reference for strategy execution, so matching it helps validate semantics. |
| Why not just claim speed? | Because timing without correctness is weak. The stronger claim is correctness-checked interactive computation. |
| What is the strongest evidence? | Complex futures correctness: 181,447 candles, 7 pairs, 123 compared trades, 0 mismatched fields. |
| What is still missing? | Broader strategy corpus, canonical AST/IR, dependency invalidation graph and full production user-flow benchmarks. |
| What funding supports? | Turning controlled benchmark proof into a robust engine: schema, IR, invalidation, exporters and validation corpus. |
What I Would Simplify Next
- Treat this file,
2signals-engine-v0.4.mdand2signals-vs-freqtrade-main-v1.mdas the only active entry points. - Keep older whitepaper drafts, but clearly label them historical.
- Stop investing in generated whitepaper/deck automation until the evidence is frozen for a specific external deadline.
- Improve one benchmark instead of adding five documents: the next useful benchmark is a larger non-EMA side-by-side slice with the same correctness discipline.
docs/whitepaper/2signals-engine-v0.4.mdCurrent benchmark evidence summaryShort manually maintained summary of the benchmark evidence that is useful right now.What to look for: The current result table: each statistic has a value, boundary, meaning, reason and source path.Open
2Signals Engine - Current Benchmark Evidence
This is a short, manually maintained summary of the benchmark evidence that is currently useful for product, whitepaper and grant work.
The source of truth is not this document. The source of truth is the benchmark
reports and raw JSON artifacts under docs/benchmarks/results/ and
benchmarks/results/.
Use this document as the readable front door. A statistic is ready for whitepaper or grant material only when it has all of the following:
- a named benchmark boundary,
- a short explanation of what it measures,
- a short explanation of why it is needed,
- a correctness status or caveat,
- a source report or raw artifact path.
What Matters
The current useful evidence is:
- Main controlled 2Signals vs Freqtrade benchmark summary.
- Controlled 2Signals EMA variant scaling.
- Controlled production-like Builder render latency.
- Controlled Freqtrade boundary references.
- Complex futures correctness against a frozen Freqtrade reference.
This is enough to explain the current technical direction without turning the whitepaper into its own generated documentation system.
Start with docs/whitepaper/README.md when preparing for a presentation. It
contains the talk track, slide flow, key numbers, Q&A and what not to claim.
Start with docs/benchmarks/results/2signals-vs-freqtrade-main-v1.md when the
question is: "do we compare 2Signals and Freqtrade for both correctness and
time?" It links the detailed source reports and keeps boundary caveats visible.
Current Results
| Area | Statistic | Current value | What it measures | Why it is needed | Source |
|---|---|---|---|---|---|
| Main comparison | Current 2Signals vs Freqtrade status | EMA side-by-side passed; complex futures passed | The two strongest controlled comparison slices: simple EMA timing/correctness and complex futures correctness/timing. | Gives one readable entry point for whitepaper and funding work without hiding source reports. | docs/benchmarks/results/2signals-vs-freqtrade-main-v1.md |
| 2Signals scaling | 1000-variant cold median | 1559.96 ms | Time to compute a full 1000-strategy EMA variant sweep in the Node/service benchmark boundary. | Shows whether related strategy exploration can scale without invoking UI, auth or external data fetch. | docs/benchmarks/results/controlled-ema-2signals-variant-scale-btcusdt-5m-v2.md |
| 2Signals scaling | 1000-variant per-variant median | 1.35 ms | Median cost per variant inside the 1000-variant cold sweep. | Explains whether adjacent strategy edits remain practical as variant count grows. | docs/benchmarks/results/controlled-ema-2signals-variant-scale-btcusdt-5m-v2.md |
| Correctness | EMA scale strategy variants checked | 1610 variants, 0 mismatches | Strategy correctness checks across the declared EMA scale scope. | Timing results are only useful if dataset, indicators, masks, signals, trades, fees and P/L remain correct. | benchmarks/results/controlled-ema-2signals-variant-scale-btcusdt-5m-v2/2026-07-26T22-21-05-858Z/controlled-ema-2signals-variant-scale-btcusdt-5m-v2.correctness.json |
| Builder UI | Fully rendered median range | 241.4-258.3 ms | Time until the production-like Builder harness has chart, indicator series, markers, trades and metrics rendered. | Gives a user-facing latency signal, unlike engine-only timing. | benchmarks/results/builder-production-like-production/2026-07-26T22-25-07-155Z/benchmark-matrix.md |
| Builder UI | Presentation-ready median | 9.4-33.6 ms across selected scenarios | Time until computed results are available to the UI layer. | Separates engine/service readiness from visual rendering cost. | benchmarks/results/builder-production-like-production/2026-07-26T22-25-07-155Z/benchmark-matrix.md |
| Freqtrade reference | 2Signals in-process workflow | 20.25 ms | Local workflow timing for 10 EMA variants in one running process. | Provides the closest internal workflow reference for the same strategy family. | docs/benchmarks/results/controlled-ema-freqtrade-boundaries-v1.md |
| Freqtrade reference | Freqtrade strategy-list workflow | 5.51 s | One Freqtrade process running 10 strategies through the natural --strategy-list boundary. | Separates the supported batch workflow from repeated single-process CLI invocation. | docs/benchmarks/results/controlled-ema-freqtrade-boundaries-v1.md |
| Freqtrade reference | Freqtrade separate-process CLI workflow | 35.52 s | Repeated CLI workflow where each strategy variant uses a separate process. | Shows the cost of process startup and repeated CLI orchestration. | docs/benchmarks/results/controlled-ema-freqtrade-boundaries-v1.md |
| Complex futures | Dataset size | 181,447 candles across 7 USDT perpetual pairs | Frozen data scope for the complex futures comparison. | Demonstrates that the strongest correctness evidence is not only a tiny EMA fixture. | docs/benchmarks/results/controlled-complex-current-engine-export-v1.md |
| Complex futures | Indicator values compared | 2,903,152 | Per-candle indicator values compared between controlled outputs. | Confirms the computational base of the strategy before trade-level comparison. | docs/benchmarks/results/controlled-complex-current-engine-export-v1.md |
| Complex futures | Mask values compared | 725,788 | Entry and exit boolean mask values compared across the strategy boundary. | Catches semantic differences before trade simulation. | docs/benchmarks/results/controlled-complex-current-engine-export-v1.md |
| Complex futures | Compared trades and mismatches | 123 trades, 0 mismatched fields | Trade-level comparison between the current 2Signals export and frozen Freqtrade reference. | This is the most practical current correctness signal for a non-trivial strategy sample. | docs/benchmarks/results/controlled-complex-current-engine-export-v1.md |
Metric Definitions
| Metric | Meaning | Why it matters |
|---|---|---|
| Median | Central measured value across benchmark samples. | Avoids treating one noisy local run as the result. |
| Cold run | Run where benchmark-level reusable work is cleared or treated as unavailable. | Shows the cost when the system cannot reuse previous computation. |
| Warm run | Repeated run after reusable work is already available. | Shows whether cache reuse helps without changing correctness. |
| Presentation-ready | Computed results are ready for the presentation layer. | Separates engine/service cost from drawing the UI. |
| Fully rendered | Chart, indicator series, markers, trades and metrics are rendered in the harness. | Closer to user-visible latency than engine-only timing. |
| Mismatched fields | Count of compared correctness fields that differ between controlled outputs. | Prevents performance claims when the outputs disagree. |
Reproduction Commands
Use these when the evidence needs to be checked again:
pnpm bench:compare:ema:2signals-scale:correctness
pnpm bench:compare:ema:variant-scale:matrix
pnpm bench:compare:ema:freqtrade-persistent-variant-scale
pnpm bench:equivalence:complex:current-engine-export:controlled
pnpm bench:builder:production
Methodological Rules
- Do not claim a universal 2Signals vs Freqtrade ratio.
- Do not call workflow boundaries pure engine-to-engine comparisons.
- Do not claim strict linear scalability.
- Do not count the same dataset candles once per strategy variant.
- Keep correctness and timing boundaries separate.
- Keep complex futures evidence visible; it is more meaningful than another tiny EMA-only example.
What Not To Maintain
We do not need a daily-generated whitepaper pipeline right now.
Avoid maintaining:
- a generated whitepaper evidence manifest,
- a generated deck markdown file,
- a generated public evidence JSON file,
- a dedicated whitepaper validator,
- repeated markdown files that say the same thing.
The next useful work should improve benchmark quality, correctness scope and result visibility, not document generation.
docs/whitepaper/evidence-package-v0.2.mdEvidence package indexMap of whitepaper documents, benchmark reports, safe claims and R&D work packages.What to look for: Use the current-document map and claim ladder to decide which files are current, historical or only supporting evidence.Open
2Signals Evidence Package v0.2
Status: working package for whitepaper publication and deep-tech funding preparation.
This document connects the whitepaper summaries, benchmark artifacts and the research roadmap. It is an index and claim guardrail, not another source of benchmark truth.
For presentation prep, start with docs/whitepaper/README.md. For day-to-day
benchmark numbers, use docs/whitepaper/2signals-engine-v0.4.md. Use this file
when you need to know which supporting documents exist and how to interpret
them.
How To Read This Package
| Need | Start with | Why |
|---|---|---|
| Presentation prep | docs/whitepaper/README.md | Talk track, slide flow, key numbers, file map, Q&A and what not to claim. |
| Current whitepaper numbers | docs/whitepaper/2signals-engine-v0.4.md | Short manually maintained summary with statistic descriptions, measurement boundaries and sources. |
| 2Signals vs Freqtrade result | docs/benchmarks/results/2signals-vs-freqtrade-main-v1.md | One readable entry point for correctness and timing evidence across the EMA and complex futures slices. |
| Funding or grant introduction | docs/whitepaper/grant-evidence-summary-v0.2.md | Short thesis and work-package narrative for non-code reviewers. |
| Raw artifact verification | docs/whitepaper/evidence-freeze-v0.2.md | Commits, artifact paths, hashes and reproduction commands. |
| Technical due diligence | Benchmark reports under docs/benchmarks/results/ | Detailed methodology, correctness and boundary limitations. |
| Historical context | docs/whitepaper/2signals-engine-v0.1.md, docs/whitepaper/2signals-engine-v0.2.md, docs/whitepaper/2signals-engine-whitepaper-v0.3.md | Older drafts. Do not use them as the current source for benchmark numbers without checking v0.4 and the reports. |
Current State
| Item | Path | Role | How to use it |
|---|---|---|---|
| Presentation brief | docs/whitepaper/README.md | Practical start-here file for presentations. | Use before any pitch, funding or reviewer conversation. |
| Current evidence summary | docs/whitepaper/2signals-engine-v0.4.md | Current short source for whitepaper numbers. | Use first. Each statistic states what it measures, why it matters and where the source report lives. |
| Main 2Signals/Freqtrade benchmark | docs/benchmarks/results/2signals-vs-freqtrade-main-v1.md | Current front-door report for correctness and timing. | Use when the reviewer asks how 2Signals compares with Freqtrade. |
| Public results page | src/app/whitepaper/page.tsx | Website version of the current summary. | Use for internal review and demos. It should stay manually maintained and simple. |
| Report reader page | src/app/whitepaper/evidence/page.tsx | In-app table of contents for key markdown files. | Use when you want to open supporting reports without digging through the repo. |
| Grant evidence summary v0.2 | docs/whitepaper/grant-evidence-summary-v0.2.md | Short review brief for funding and pitch conversations. | Use after checking the current summary and raw report sources. |
| Evidence freeze v0.2 | docs/whitepaper/evidence-freeze-v0.2.md | Artifact ledger, hashes and reproduction commands. | Use for external verification and artifact packaging. |
| Review bundle script | scripts/whitepaper/create_review_bundle.mjs | Optional archive generator. | Use before sharing evidence externally, not as a daily whitepaper generator. |
| Technical whitepaper v0.1 | docs/whitepaper/2signals-engine-v0.1.md | Historical architecture draft. | Superseded for benchmark claims. |
| Technical whitepaper v0.2 | docs/whitepaper/2signals-engine-v0.2.md | Historical evidence draft. | Keep for context; verify numbers against v0.4 and benchmark reports. |
| Publication whitepaper v0.3 | docs/whitepaper/2signals-engine-whitepaper-v0.3.md | Older publication-oriented narrative. | Useful prose, but not the current source of benchmark statistics. |
| Whitepaper deck PDF v0.3 | public/whitepaper/2signals-engine-whitepaper-v0.3-deck.pdf | Historical deck output. | Do not regenerate daily. Refresh only after the benchmark evidence is frozen again. |
| Benchmark findings | docs/benchmarks/results/benchmark-findings-v1.md | Methodological audit. | Use as a sanity check before making claims. |
| 2Signals scale v2 report | docs/benchmarks/results/controlled-ema-2signals-variant-scale-btcusdt-5m-v2.md | Main measured scale report. | Use for variant scaling and correctness counts with boundary qualifiers. |
| Production-like Builder matrix | benchmarks/results/builder-production-like-production/2026-07-26T22-25-07-155Z/benchmark-matrix.md | Measured UI render report. | Use for production-like harness latency, not full authenticated /builder latency. |
| Freqtrade boundary report | docs/benchmarks/results/controlled-ema-freqtrade-boundaries-v1.md | Measured boundary reference. | Use only as a workflow-boundary reference. |
| Side-by-side matrix | docs/benchmarks/results/controlled-ema-variant-scale-side-by-side-v1.md | Neutral boundary comparison. | Use with explicit boundary disclaimers. |
| Complex current-engine export | docs/benchmarks/results/controlled-complex-current-engine-export-v1.md | Strongest current complex correctness report. | Use for the non-trivial futures correctness evidence. |
| Complex Freqtrade frozen boundary | docs/benchmarks/results/controlled-complex-freqtrade-frozen-boundary-v1.md | Supporting Freqtrade complex boundary report. | Use for phase timings and artifact scope. |
| Architecture audit | docs/engine/current-architecture.md | Implemented architecture evidence. | Use for current-state sections. |
| Cache audit | docs/engine/cache-audit.md | Implemented cache evidence and risk analysis. | Use for R&D problem statement. |
Statistic Glossary
| Statistic | What it means | What it measures | Why it is needed |
|---|---|---|---|
| Median | The central measured sample after sorting all samples. | Typical duration for a named benchmark boundary. | Prevents one noisy local run from becoming the headline result. |
| Cold run | A run where benchmark-level reusable work is cleared or unavailable. | Cost without reuse for the measured boundary. | Shows the worst normal case for a fresh computation path. |
| Warm run | A repeated run after reusable work exists. | Cost when caches or prepared computations can be reused. | Confirms reuse helps without changing correctness. |
| Per-variant median | Median cost assigned to one strategy variant inside a scale run. | Approximate local cost of adjacent strategy exploration. | Helps explain why variant sweeps can remain interactive. |
| Presentation-ready | Computed results are available to the presentation layer. | Service/result readiness before full visual rendering. | Separates engine and data work from UI drawing. |
| Fully rendered | Chart, indicators, markers, trades and metrics are rendered in the harness. | User-visible latency in the controlled Builder-like view. | Gives a more practical UI signal than engine-only timing. |
| Mismatched fields | Compared correctness fields that differ between controlled outputs. | Semantic disagreement across indicators, masks, signals, trades or metrics. | Timing should not be used as evidence when outputs disagree. |
| Workflow boundary | A measured path that may include startup, config loading, imports or parsing. | End-to-end work for a named system path. | Keeps Freqtrade and 2Signals comparisons honest when boundaries differ. |
Evidence baseline status: local evidence rows now span two measured baselines.
The EMA scale and production-like Builder rerun were recorded on
f771cf2ea946f9cac03392f2b1ea06b4d8185259; the complex frozen Freqtrade
boundary and current-engine export were recorded on
b261ffb7469f6a95c3c6611b9340800ea988caab. The freeze ledger records the raw
artifact paths and hashes. External publication should still use a tagged
evidence commit or exported artifact bundle.
Publication-Safe Claim Ladder
Strong claims
These can be used in the whitepaper with the stated boundary and rerun caveats:
| Claim | Evidence | Required wording |
|---|---|---|
| 2Signals has a repeatable benchmark evidence framework. | Raw JSON artifacts, matrix reports, correctness reports. | Use "repeatable framework", not "certified benchmark". |
| Correctness passed for 1 unique dataset and 1610 checked strategy variants. | benchmark-findings-v1.md, scale v2 correctness report. | Include the declared scope and 0 mismatches. |
2Signals processed 1000 EMA variants in 1.56 s median cold full-sweep time. | Scale v2 report. | Always include "tested Node/service boundary". |
Production-like Builder rendering completed around 241-258 ms. | Production-like Builder matrix. | Always include "production-like harness", not full production flow. |
| Freqtrade 10-variant references were measured for separate process and strategy-list boundaries. | Freqtrade boundary report. | Use "boundary references", not algorithm-only comparison. |
Qualified claims
These are usable only with careful wording:
| Claim area | Safe framing | Unsafe framing |
|---|---|---|
| Scale behavior | Approximately proportional growth in the tested Node/service range. | Linear scalability. |
| Per-variant cost | Stable in the measured EMA v2 grid and local boundary. | Stable for all strategies. |
| Freqtrade comparison | Observed workflow durations differ substantially, but boundaries differ. | Unqualified ratios between non-equivalent boundaries. |
| Cache reuse | Indicator reuse is visible for related EMA variants. | Cache solves all incremental recomputation. |
| UI readiness | Production-like fully-rendered harness latency was measured. | Full production /builder latency was measured. |
Not yet publication-ready
- Unqualified complex strategy parity across all product/export paths. The fresh
controlled Freqtrade boundary and current-engine export pass locally, but the
historical exported-fixture report remains a useful mismatch fixture and the
result is still not full authenticated
/builderflow evidence. - Full production
/builderauthenticated user-flow latency. - Cross-engine Freqtrade equivalence for 100/500/1000 variants.
- Production browser memory and IndexedDB footprint.
- Cache eviction behavior.
- Multi-timeframe and multi-asset correctness.
- Real-market large dataset scaling beyond the current frozen EMA fixture.
Deep-Tech Funding Thesis
The strongest funding thesis is not that 2Signals is merely a faster backtester. The stronger technical thesis is:
2Signals is developing a correctness-checked, cache-aware strategy computation system for interactive exploration of large strategy variant spaces.
This thesis is supported by current evidence and leaves credible R&D work:
- deterministic strategy representation;
- reusable computation over related strategy variants;
- correctness artifacts that separate dataset correctness from strategy correctness;
- boundary-aware comparison with Freqtrade workflows;
- production-like rendering evidence;
- planned canonical AST/IR and dependency invalidation graph.
Proposed R&D Work Packages
| Work package | Research objective | Current evidence | Output |
|---|---|---|---|
| WP1: Canonical strategy AST and IR | Separate strategy semantics from UI and Freqtrade config. | Current model works but is not canonical. | Versioned AST, migrations, validation and deterministic hashes. |
| WP2: Correctness-first benchmark corpus | Expand beyond the current EMA fixture. | Current EMA correctness model is strong but narrow. | Frozen real and synthetic datasets, per-candle artifacts and mismatch reports. |
| WP3: Dependency and invalidation graph | Recompute only affected indicators, rules, signals and metrics. | Current cache reuse is key-based and benchmarked for EMA variants. | Explicit graph planner, invalidation rules and cache diagnostics. |
| WP4: Freqtrade-equivalent exporter boundary | Preserve semantics when exporting controlled strategy slices. | EMA/Freqtrade slices and boundary reports exist. | Capability matrix, deterministic exporter and equivalence reports. |
| WP5: Production execution and memory validation | Validate UI, IndexedDB and memory behavior under production-like load. | Production-like Builder harness exists; memory data is diagnostic. | Memory-only runs, browser cache measurements and production-like latency reports. |
| WP6: Semantic LLM and future ML layer | Assist strategy authoring and experiment selection without replacing deterministic execution. | Whitepaper defines this as planned/research. | Validated NL-to-strategy workflow, experiment proposal layer and ML-ready experiment dataset. |
Evidence Rerun Status
The current evidence was rerun locally across the measured baselines listed in
docs/whitepaper/evidence-freeze-v0.2.md. The raw benchmark directories are
local artifacts under benchmarks/results and .benchmark-artifacts; if they
are needed outside this workspace, export or archive them explicitly.
Completed in the rerun:
- Static validation and benchmark contract tests passed.
- 2Signals scale v2 correctness, timing and report regenerated.
- 2Signals 10-variant boundary, Freqtrade separate-process CLI boundary and Freqtrade strategy-list boundary regenerated where applicable.
- Side-by-side matrix regenerated with 10 shared EMA variants and 0 correctness mismatches.
- Production-like Builder benchmark passed in production build with 70 measured samples and 0 failures.
Still pending before external publication:
- Commit these refreshed reports and docs.
- Decide whether raw ignored benchmark artifacts should be exported as a release bundle.
- Tag the evidence baseline or create a signed publication package.
- Regenerate
benchmark-findings-v1.mdif it should become the primary narrative report instead of the boundary-specific reports.
Command set used or completed during the local rerun:
pnpm exec tsc --noEmit
pnpm exec vitest run src/lib/benchmarks/report-script.test.ts src/lib/benchmarks/production-builder-benchmark-script.test.ts src/lib/benchmarks/controlled-variant-scale-comparison-script.test.ts --reporter=dot
pnpm bench:compare:ema:2signals-scale:correctness
pnpm bench:compare:ema:2signals-scale
pnpm bench:compare:ema:2signals-scale:report
pnpm bench:compare:ema:variant-scale
pnpm bench:compare:ema:variant-scale:report
pnpm bench:compare:ema:freqtrade-variant-scale
pnpm bench:compare:ema:freqtrade-variant-scale:report
pnpm bench:compare:ema:freqtrade-persistent-variant-scale
pnpm bench:compare:ema:freqtrade-persistent-variant-scale:report
pnpm bench:compare:ema:variant-scale:matrix
pnpm bench:builder:production
git diff --check
pnpm bench:builder:production required local server permissions in this
sandboxed Codex environment because it starts next start on 127.0.0.1.
Next Publication Priority
Recommended next publication slice: produce an external review bundle from the evidence freeze.
Goal:
- tag or commit the benchmark evidence state;
- run
pnpm whitepaper:review-bundleto export docs, reports, selected raw results and ignored.benchmark-artifactsinto a review archive; - verify exported artifact hashes with the generated
SHA256SUMS; - package the whitepaper, evidence package, freeze ledger, benchmark reports and raw artifacts through the review bundle;
- separate controlled evidence from product and marketing claims.
Minimum acceptance:
| Requirement | Status needed |
|---|---|
| Frozen dataset manifest | already available; keep exact hash and pair metadata |
| Strategy artifact | deterministic hash and capability matrix |
| 2Signals run | raw JSON and correctness artifact already available |
| Freqtrade run | raw JSON and correctness artifact |
| Dataset correctness | passed or explicit failure report |
| Strategy correctness | passed or explicit mismatch report |
| Timing boundary | explicitly named and separated from artifact export |
| Publication wording | no marketing ratio unless boundaries are equivalent |
Funding Narrative Guardrails
Use:
- correctness-checked computation;
- reproducible benchmark artifacts;
- deterministic strategy representation;
- interactive strategy exploration;
- cache-aware reuse;
- boundary-aware external validation;
- research roadmap for AST, IR, invalidation and ML-assisted exploration.
Avoid:
- unqualified speed claims;
- algorithm-only claims from workflow benchmarks;
- claims of full Freqtrade equivalence at scale;
- claims that the LLM or ML layer trades autonomously;
- claims that a proprietary ML model already exists;
- claims that production
/builderlatency has been fully measured.
Immediate Open Items
| Item | Why it matters | Recommended owner action |
|---|---|---|
| Clean evidence commit | Current docs cite measured rows from more than one commit. | Commit the freeze docs and tag the publication evidence state. |
| External artifact bundle | Raw benchmark JSON and per-candle artifacts are ignored by git. | Export benchmarks/results and .benchmark-artifacts paths listed in the freeze ledger. |
| Memory-only benchmark | Current memory evidence is diagnostic. | Run fresh process with --expose-gc and isolated phases. |
| Dataset expansion | One BTC/USDT 5m fixture is narrow. | Add larger real-market fixtures with clear licensing/source metadata. |
| Grant-specific narrative | Funding applications need work packages, milestones and risk controls. | Convert this package into application-specific sections. |
docs/whitepaper/grant-evidence-summary-v0.2.mdGrant evidence summaryShort reviewer-facing brief for funding and pitch conversations.What to look for: Use the thesis, evidence snapshot and work packages; do not treat it as the raw benchmark source.Open
2Signals Grant Evidence Summary v0.2
Status: short review brief for grant, funding and pitch conversations.
Evidence anchor: evidence/2signals-engine-v0.2-2026-07-27 at commit
f4bf1db60d6dfc400fff818ef62ec22d5bf283a4.
External artifact bundle:
/private/tmp/2signals-evidence-v0.2-2026-07-27.tgz, SHA-256
4b4842b1dc80963d7edba255ad8c4b5a35f4d590ad8ba4bb0189492e9c070ecd.
This summary is intentionally conservative. It is a grant/pitch bridge over the technical whitepaper and benchmark evidence, not a replacement for the raw artifacts.
One-Sentence Thesis
2Signals is developing a correctness-checked, cache-aware strategy computation system for interactive exploration of large trading-strategy variant spaces.
Why This Is Deep-Tech Work
Backtesting tools are often evaluated only by final trade output or total run time. 2Signals is pursuing a more structured engine model:
- deterministic strategy execution with explicit correctness artifacts;
- dataset correctness separated from strategy correctness;
- reusable computation across related strategy variants;
- boundary-aware comparison with Freqtrade workflows;
- production-like UI latency measurement for interactive strategy review;
- a roadmap toward a canonical strategy AST, normalized IR and dependency invalidation graph.
The technical risk is real and appropriate for R&D funding: the current product model works, but it is not yet the final canonical strategy representation; the current cache model is key-based, not a complete computation graph; and broader multi-timeframe, multi-asset and production-flow validation is still planned.
Current Evidence Snapshot
| Evidence area | Current result | Boundary |
|---|---|---|
| 2Signals vs Freqtrade main report | Current front-door report combines the EMA side-by-side correctness/timing slice with the complex futures correctness/timing slice. | Controlled local boundaries; source reports remain authoritative. |
| Repeatable benchmark framework | Implemented with raw JSON artifacts, matrix reports, correctness reports and reproduction commands. | Repository benchmark tooling and evidence freeze. |
| EMA variant correctness | 1 unique frozen dataset and 1610 checked strategy variants with 0 mismatches in the declared scope. | Controlled EMA scale v2. |
| EMA variant throughput | 1000 related EMA variants completed with 1.56 s median cold full-sweep time. | Tested Node/service boundary, not UI or full production flow. |
| Production-like Builder rendering | Fully-rendered latency around 241-258 ms across reported production-like scenarios. | Controlled harness with production chart, metrics and trades components; not full authenticated /builder. |
| Complex futures correctness | Fresh current-engine 2Signals export and fresh Freqtrade frozen boundary are semantically_equivalent: 123 compared trades, 0 missing trades, 0 mismatched fields. | Local frozen futures data, controlled Builder-equivalent export, local Freqtrade boundary. |
| Per-candle complex correctness | Dataset correctness passed for 7 pairs, 181447 candles and 907235 OHLCV values; strategy correctness passed for 2903152 indicator values, 725788 mask values, 19937 signal timestamps and 123 trades. | Diagnostic per-candle artifacts outside measured timing. |
How To Interpret The Statistics
| Statistic | What it measures | Why it is needed in the funding narrative |
|---|---|---|
| 1000 related EMA variants | A controlled sweep of related strategy variants over the same frozen BTC/USDT 5m dataset. | Shows the research direction: reusable computation across adjacent strategy experiments, not just one isolated backtest. |
| Median cold full-sweep time | The central measured duration when benchmark-level reusable work is unavailable. | Gives a conservative local baseline for the tested computation boundary. |
| Per-variant median | Approximate cost attributed to one strategy variant inside a larger sweep. | Explains why interactive parameter exploration is technically plausible. |
| Fully-rendered latency | Time until the controlled Builder-like harness has chart, indicators, markers, trades and metrics rendered. | Connects engine work to user-facing review latency, while still excluding auth and live network fetch. |
| Dataset correctness | Hashes, candle counts, timestamps and OHLCV checks for each unique frozen dataset. | Prevents strategy results from being compared on different data. |
| Strategy correctness | Indicators, masks, signals, trades, prices, fees, P/L and comparable metrics. | Ensures performance evidence is not separated from semantic correctness. |
| Mismatched fields | Count of compared fields that differ between controlled outputs. | Keeps the narrative honest: timing claims should not be made when outputs disagree. |
Publication-Safe Claims
Safe wording:
- 2Signals has a repeatable, correctness-gated benchmark evidence framework.
- 2Signals demonstrates reusable computation over related EMA strategy variants in the tested Node/service boundary.
- The current evidence includes controlled Freqtrade boundary references, but they are workflow references rather than pure engine-to-engine measurements.
- The complex futures slice now has a current controlled correctness reference against fresh Freqtrade output.
- Production-like Builder rendering has been measured in a controlled harness that uses production chart, metrics and trades components.
Avoid:
- unqualified claims that 2Signals is faster than Freqtrade;
- claims of full Freqtrade equivalence for all strategies;
- claims that the benchmark is full authenticated production
/builderlatency; - claims that a proprietary ML model already exists;
- claims that cache reuse solves all incremental recomputation.
Proposed R&D Work Packages
| Work package | Objective | Expected output |
|---|---|---|
| WP1: Canonical strategy AST and IR | Separate strategy semantics from UI state and exporter-specific configuration. | Versioned schema, migrations, deterministic serialization and validation. |
| WP2: Correctness-first benchmark corpus | Move beyond the current EMA and complex futures slices. | Frozen datasets, per-candle artifacts, mismatch reports and tolerance profiles. |
| WP3: Dependency and invalidation graph | Recompute only affected indicators, rules, signals and metrics after edits. | Planner, computation IDs, cache invalidation rules and diagnostics. |
| WP4: Freqtrade-equivalent exporter boundary | Preserve semantics for supported exported strategy slices. | Capability matrix, deterministic Python generation and equivalence artifacts. |
| WP5: Production execution and memory validation | Validate interactive latency, IndexedDB behavior and memory under production-like load. | Browser memory studies, cache eviction reports and full-flow latency boundaries. |
| WP6: Semantic assistant and experiment layer | Help users author, compare and explain strategies without replacing deterministic execution. | Validated natural-language-to-strategy workflow and experiment proposal layer. |
Evidence References
| Reference | Path |
|---|---|
| Current evidence summary | docs/whitepaper/2signals-engine-v0.4.md |
| Main 2Signals/Freqtrade benchmark | docs/benchmarks/results/2signals-vs-freqtrade-main-v1.md |
| Technical whitepaper | docs/whitepaper/2signals-engine-v0.2.md |
| Evidence package | docs/whitepaper/evidence-package-v0.2.md |
| Evidence freeze ledger | docs/whitepaper/evidence-freeze-v0.2.md |
| Complex Freqtrade boundary report | docs/benchmarks/results/controlled-complex-freqtrade-frozen-boundary-v1.md |
| Complex current-engine export report | docs/benchmarks/results/controlled-complex-current-engine-export-v1.md |
| Benchmark matrix | benchmarks/matrix.json |
Recommended Use
Use this document as a two-minute entry point for reviewers. For diligence, attach the evidence bundle and direct technical reviewers to the freeze ledger first, then to the whitepaper and benchmark reports.
docs/whitepaper/evidence-freeze-v0.2.mdEvidence freeze ledgerArtifact ledger with commits, paths, hashes and reproduction commands.What to look for: Use this when someone needs to verify which raw artifacts and commits support a claim.Open
2Signals Evidence Freeze v0.2
Status: prepared for publication/funding review.
Freeze label: evidence/2signals-engine-v0.2-2026-07-27.
This document is an evidence ledger for the technical whitepaper and funding materials. It freezes the paths, measured commits, raw artifacts, SHA-256 hashes and reproduction commands for the current controlled benchmark evidence. It is not a marketing summary and does not introduce new benchmark claims.
Scope
| Field | Value |
|---|---|
| Repository branch | dev |
| Current HEAD during freeze | b261ffb7469f6a95c3c6611b9340800ea988caab |
| Freeze date | 2026-07-27 |
| Primary evidence package | docs/whitepaper/evidence-package-v0.2.md |
| Technical whitepaper | docs/whitepaper/2signals-engine-v0.2.md |
| Implementation report | docs/benchmarks/implementation-report.md |
| Benchmark matrix | benchmarks/matrix.json |
The measured evidence rows currently span two local baselines:
f771cf2ea946f9cac03392f2b1ea06b4d8185259for the controlled EMA scale and production-like Builder render rerun recorded earlier in the evidence package.b261ffb7469f6a95c3c6611b9340800ea988caabfor the complex frozen Freqtrade boundary and current-engine Builder-equivalent export.
The freeze commit or tag should identify the final documentation state. Because raw benchmark directories are intentionally ignored by git, external review also needs an exported artifact bundle or access to the local artifact paths listed below.
Primary Complex Evidence
| Evidence item | Status | Measured commit | Report | Raw artifact | SHA-256 |
|---|---|---|---|---|---|
| Complex fresh Freqtrade boundary | passed | b261ffb7469f6a95c3c6611b9340800ea988caab | docs/benchmarks/results/controlled-complex-freqtrade-frozen-boundary-v1.md | benchmarks/results/equivalence/2026-07-27T03-50-24-007Z.builder-complex-freqtrade-frozen-boundary.equivalence.json | 76645b6134d374dcd2ec82993e7cb605c50bc4f3af6ce3bf3e8b555fa1e83c7d |
| Complex current-engine export | passed | b261ffb7469f6a95c3c6611b9340800ea988caab | docs/benchmarks/results/controlled-complex-current-engine-export-v1.md | benchmarks/results/equivalence/2026-07-27T04-08-26-879Z.builder-complex-current-engine-export.equivalence.json | e287d7fd2c8ea5f7d861ba7fdcd035c45980cfb834b41b250018638fd1418cd1 |
| Current-engine export JSON | passed | b261ffb7469f6a95c3c6611b9340800ea988caab | docs/benchmarks/results/controlled-complex-current-engine-export-v1.md | .benchmark-artifacts/controlled-complex-current-engine-export-v1/2026-07-27T04-08-26-879Z/2026-07-27T04-08-26-879Z.builder-complex-current-engine-export.json | 24ff88866ba2c3767103f944a6612caaa315ca5e99ef97019553d6559b440605 |
| Freqtrade phase timings | passed | b261ffb7469f6a95c3c6611b9340800ea988caab | docs/benchmarks/results/controlled-complex-freqtrade-frozen-boundary-v1.md | .benchmark-artifacts/controlled-complex-freqtrade-frozen-boundary-v1/2026-07-27T03-50-24-007Z/freqtrade-phase-timings.json | c99e99fc04f72a86da19d809dd479cae8901d0ea04ff42e29fdaeca5a4b4db23 |
Report file hashes captured before this freeze document was added:
| Report | SHA-256 |
|---|---|
docs/benchmarks/results/controlled-complex-freqtrade-frozen-boundary-v1.md | 871919b8d69edab751e44785a39e4de004972377a3e96ac8b89dfb7e0f76230f |
docs/benchmarks/results/controlled-complex-current-engine-export-v1.md | 1884f9f8a466a89a9087f38f063c25a897deec20ebc402f6d0c98ea929a6e427 |
Per-candle artifact directories:
| Boundary | Path | File count | Git status |
|---|---|---|---|
| Complex fresh Freqtrade boundary | .benchmark-artifacts/controlled-complex-freqtrade-frozen-boundary-v1/2026-07-27T03-50-24-007Z/per-candle-artifacts | 22 | ignored |
| Complex current-engine export | .benchmark-artifacts/controlled-complex-current-engine-export-v1/2026-07-27T04-08-26-879Z/per-candle-artifacts | 7 | ignored |
Correctness Summary
| Boundary | Result |
|---|---|
| Complex fresh 2Signals vs fresh Freqtrade | semantically_equivalent; 123 compared trades; 0 missing trades; 0 mismatched fields |
| Complex current-engine export vs fresh Freqtrade boundary | semantically_equivalent; 123 compared trades; 0 missing trades; 0 mismatched fields |
| Dataset correctness | passed; 1 unique dataset; 7 pairs; 181447 candles; 907235 OHLCV values; 0 mismatches |
| Strategy correctness | passed; 2903152 indicator values; 725788 mask values; 19937 signal timestamps; 123 trades; 1722 trade metric fields; 0 mismatches |
Dataset hashes:
| Dataset | Hash |
|---|---|
| Complex frozen market data | 8187f41a5104f2dbae03adcd34e13611bfbff17ec17bf9948f8fa2ef36cf79c1 |
| Complex funding data | 54d5e30b8af6ce48f5c6e019b8a726b988828d0333c429a839e406b6afbc2130 |
Timing Boundaries
The timing rows below are boundary labels, not pure engine-to-engine claims.
| Boundary | Measured timing | Included |
|---|---|---|
| Complex 2Signals BacktestService | 2.45 s to 2.47 s | Frozen local OHLCV/funding data, indicator computation, rule evaluation, signal generation, trade simulation and result preparation inside the service boundary. |
| Complex Freqtrade Backtesting.start() | 20.32 s | Local Freqtrade backtesting phase for the generated strategy and frozen local data. |
| Complex Freqtrade child process | 23.82 s | Python/Freqtrade process, imports, config/strategy loading, data loading, backtest execution and Freqtrade-side export. |
| Complex Freqtrade per-candle artifact export | 39.97 s | Diagnostic artifact export only; outside the measured backtest boundary. |
| Complex current-engine export workflow | 14.07 s | Dataset audit read, current 2Signals run, Builder-equivalent export, artifact writes, comparison and report-facing summary. |
Reproduction Commands
Use these commands from the repository root:
pnpm exec vitest run src/lib/benchmarks/complex-current-engine-export-report-script.test.ts src/lib/benchmarks/complexPerCandleArtifacts.test.ts src/lib/benchmarks/complex-freqtrade-boundary-report-script.test.ts src/lib/benchmarks/report-script.test.ts
pnpm exec tsc --noEmit --pretty false
pnpm exec eslint benchmarks/equivalence/builder-complex-current-engine-export.bench.ts benchmarks/equivalence/builder-complex-freqtrade-frozen-boundary.bench.ts scripts/benchmarks/report-complex-current-engine-export.mjs scripts/benchmarks/report-complex-freqtrade-frozen-boundary.mjs src/lib/benchmarks/complexPerCandleArtifacts.ts src/lib/benchmarks/complexPerCandleArtifacts.test.ts src/lib/benchmarks/complex-current-engine-export-report-script.test.ts src/lib/benchmarks/complex-freqtrade-boundary-report-script.test.ts
pnpm exec prettier --check benchmarks/equivalence/builder-complex-current-engine-export.bench.ts benchmarks/equivalence/builder-complex-freqtrade-frozen-boundary.bench.ts scripts/benchmarks/report-complex-current-engine-export.mjs scripts/benchmarks/report-complex-freqtrade-frozen-boundary.mjs src/lib/benchmarks/complexPerCandleArtifacts.ts src/lib/benchmarks/complexPerCandleArtifacts.test.ts src/lib/benchmarks/complex-current-engine-export-report-script.test.ts src/lib/benchmarks/complex-freqtrade-boundary-report-script.test.ts docs/benchmarks/results/controlled-complex-current-engine-export-v1.md docs/benchmarks/results/controlled-complex-freqtrade-frozen-boundary-v1.md docs/whitepaper/2signals-engine-v0.2.md docs/whitepaper/evidence-package-v0.2.md docs/whitepaper/evidence-freeze-v0.2.md
pnpm bench:equivalence:complex:freqtrade-frozen-boundary:controlled
pnpm bench:equivalence:complex:current-engine-export:controlled
pnpm bench:report
git diff --check
The Freqtrade boundary requires the local Freqtrade repository and local frozen Freqtrade data used by the runner. It does not fetch exchange data during the measured phase.
Archive Checklist
Before sharing outside the workspace:
- Commit the code, reports and whitepaper docs.
- Tag the commit with
evidence/2signals-engine-v0.2-2026-07-27. - Export ignored raw artifacts from
benchmarks/resultsand.benchmark-artifacts. - Verify the exported files with the SHA-256 hashes in this document.
- Include this document,
docs/whitepaper/evidence-package-v0.2.md,docs/whitepaper/2signals-engine-v0.2.mdand the benchmark result reports. - Keep wording boundary-aware: controlled evidence, not broad performance or full production-flow claims.
Suggested local archive command:
pnpm whitepaper:review-bundle
The generated archive is written outside the repository by default under
/private/tmp/2signals-review-bundles. It contains README.md,
MANIFEST.json and SHA256SUMS files. To generate a smaller documentation-only
review bundle without ignored raw artifact directories:
REVIEW_BUNDLE_INCLUDE_RAW=0 pnpm whitepaper:review-bundle
Methodology Guardrails
- Do not describe the complex current-engine export as a full authenticated
/builderbrowser export. - Do not compare the 2Signals service timing directly to the Freqtrade child process timing as a pure engine ratio.
- Do not include per-candle artifact export time in the backtest boundary.
- Do not use unqualified terms such as "10x faster" or "engine advantage".
- Do state that raw artifacts are ignored locally and must be archived explicitly for external review.
- Do state the exact dataset hashes, measured commits and boundary names next to each claim.
Benchmark reports
Use these files for technical due diligence. They contain the measured benchmark boundaries, correctness results and limitations.
docs/benchmarks/results/2signals-vs-freqtrade-main-v1.md2Signals vs Freqtrade main benchmarkCurrent front-door report for controlled 2Signals/Freqtrade benchmark evidence.What to look for: Start with the main snapshot: it combines correctness and timing for the EMA side-by-side slice and the complex futures slice.Open
2Signals vs Freqtrade Main Benchmark v1
Status: current front-door report for controlled 2Signals/Freqtrade benchmark evidence.
This document exists to answer one practical question:
Do we have benchmark evidence that compares 2Signals and Freqtrade for both correctness and timing?
Answer: yes, in controlled local boundaries. The current evidence is strongest when read as two complementary slices:
- a simple EMA variant side-by-side benchmark with detailed timing and correctness;
- a more complex futures correctness benchmark with direct 2Signals and Freqtrade timing boundaries.
This is a manually maintained summary. The source of truth remains the source reports and raw artifacts listed below.
Source Reports
| Report | Role |
|---|---|
docs/benchmarks/results/controlled-ema-variant-scale-side-by-side-v1.md | Main simple side-by-side benchmark: 10 EMA variants, 2Signals timing, Freqtrade timing and correctness. |
docs/benchmarks/results/controlled-ema-freqtrade-boundaries-v1.md | Freqtrade boundary audit and phase timing report, including the natural --strategy-list workflow. |
docs/benchmarks/results/controlled-complex-freqtrade-frozen-boundary-v1.md | Complex futures fresh 2Signals vs fresh Freqtrade comparison, including timing and per-candle correctness. |
docs/benchmarks/results/controlled-complex-current-engine-export-v1.md | Current 2Signals Builder-equivalent export checked against the fresh Freqtrade frozen boundary reference. |
Main Snapshot
| Slice | Correctness status | What is compared | 2Signals timing | Freqtrade timing | What the timing means |
|---|---|---|---|---|---|
| EMA side-by-side, 10 variants | passed, 0 mismatches | Same BTC/USDT 5m frozen dataset, EMA fast 50-59, EMA slow 200, entry/exit masks, signals, trades and P/L. | 20.25 ms total workflow median for 10 sequential in-process variants. | 5.51 s --strategy-list workflow median; 35.52 s separate-process CLI workflow median. | Workflow timing, not pure engine-to-engine timing. 2Signals runs in process; Freqtrade runs through local Python/Freqtrade workflows. |
| Complex futures, 7 pairs | passed, 0 mismatched fields | Same frozen futures OHLCV/funding data, indicators, masks, signals, 123 trades, fees and P/L. | 2.45-2.47 s BacktestService boundary. | 20.32 s Backtesting.start(); 23.82 s child process; 25.26 s workflow without artifact export. | Controlled local backtest boundaries. Freqtrade artifact export is measured separately and excluded from the backtest boundary. |
What The Statistics Mean
| Statistic | What it measures | Why it matters |
|---|---|---|
| Correctness status | Whether dataset and strategy outputs matched under the declared tolerance policy. | Timing is only useful when outputs agree. |
| Mismatch count | Count of compared fields that differed between controlled outputs. | Identifies whether a comparison is semantically safe to interpret. |
| 2Signals in-process workflow | Local Node/service execution over frozen data, including indicator computation, rule/signal evaluation, simulation and result preparation. | Measures the computation path used for interactive strategy exploration, without UI or network fetch. |
Freqtrade --strategy-list workflow | One local Python/Freqtrade process running multiple generated strategies through public strategy-list CLI semantics. | Closest natural Freqtrade batch boundary found so far without building a custom persistent worker. |
| Freqtrade separate-process CLI workflow | One local Python/Freqtrade process per variant. | User-facing repeated CLI reference; includes repeated startup and initialization. |
Freqtrade Backtesting.start() | Marker around Freqtrade's internal backtesting phase. | Closer to the backtesting work than total process duration, but still not a pure isolated algorithm timer. |
| Child process duration | Python/Freqtrade process, imports, config/strategy loading, data loading, backtesting and export. | Explains the process/workflow cost surrounding the backtesting phase. |
| Artifact export | Diagnostic per-candle artifact generation. | Needed for correctness analysis, but intentionally outside measured backtest timing. |
EMA Side-By-Side Evidence
Boundary: controlled local BTC/USDT 5m EMA crossover family.
| Area | Current result |
|---|---|
| Final status | passed |
| Shared variants | 10, EMA fast 50-59 with EMA slow 200 |
| Dataset | 620 candles, dataset hash 499155587500a60de08fe8edd922bcd432d5ce36e80b106814898955264ae5fe |
| Strategy correctness | 10 variants checked |
| Indicator values compared | 12,400 |
| Mask values compared | 12,400 |
| Signals compared | 20 |
| Trades compared | 10 |
| Result metrics compared | 20 |
| Correctness mismatch count | 0 |
| 2Signals total measured workflow median | 20.25 ms |
| 2Signals per-variant median | 1.4 ms |
Freqtrade --strategy-list workflow median | 5.51 s |
| Freqtrade separate-process CLI workflow median | 35.52 s |
| Freqtrade separate-process reported backtesting phase median | 2.91 s |
Interpretation:
- This is the cleanest correctness-plus-timing side-by-side benchmark.
- It is deliberately small and simple, so it should not be presented as a universal strategy benchmark.
- It proves that the benchmark infrastructure can compare 2Signals and Freqtrade outputs while recording timing boundaries.
Complex Futures Evidence
Boundary: controlled local futures strategy over frozen OHLCV/funding artifacts.
| Area | Current result |
|---|---|
| Final status | passed |
| Pair count | 7 USDT perpetual pairs |
| Dataset size | 181,447 5m candles |
| Funding rows | 2,952 |
| Dataset hash | 8187f41a5104f2dbae03adcd34e13611bfbff17ec17bf9948f8fa2ef36cf79c1 |
| Funding dataset hash | 54d5e30b8af6ce48f5c6e019b8a726b988828d0333c429a839e406b6afbc2130 |
| Trade comparison | 123 compared trades, 0 missing in source, 0 missing in target, 0 mismatched fields |
| Indicator values compared | 2,903,152 |
| Mask values compared | 725,788 |
| Signal timestamps compared | 19,937 |
| Trade metric fields compared | 1,722 |
| 2Signals BacktestService | 2.45-2.47 s |
Freqtrade Backtesting.start() | 20.32 s |
| Freqtrade child process duration | 23.82 s |
| Freqtrade workflow without artifacts | 25.26 s |
| Freqtrade per-candle artifact export | 39.97 s, outside measured backtest boundary |
Interpretation:
- This is the strongest current non-trivial correctness evidence.
- It compares fresh 2Signals output with fresh Freqtrade output on the same frozen data.
- The timing rows are boundary references, not a universal engine ratio.
- The current report does not include full authenticated
/builderUI flow.
Neutral Boundary Ratios
These ratios are included only as boundary descriptors. They must not be used without the boundary labels.
| Ratio name | Numerator boundary | Denominator boundary | Value | Note |
|---|---|---|---|---|
| freqtradeStrategyListWorkflowTo2SignalsInProcessWorkflowRatio | Freqtrade --strategy-list total workflow median, 10 EMA variants | 2Signals in-process total workflow median, 10 EMA variants | 271.85 | Different execution boundaries; workflow ratio only. |
| freqtradeCliWorkflowTo2SignalsInProcessWorkflowRatio | Freqtrade separate-process CLI total workflow median, 10 EMA variants | 2Signals in-process total workflow median, 10 EMA variants | 1753.88 | Different execution boundaries; workflow ratio only. |
| complexFreqtradeBacktestingStartTo2SignalsBacktestServiceRatio | Freqtrade Backtesting.start() marker, complex futures | 2Signals BacktestService boundary, complex futures | approximately 8.3 | Different implementation and measurement boundaries; use as diagnostic context only. |
| complexFreqtradeChildProcessTo2SignalsBacktestServiceRatio | Freqtrade child process duration, complex futures | 2Signals BacktestService boundary, complex futures | approximately 9.7 | Includes process, imports, config, strategy loading, data loading, backtesting and export. |
What This Report Supports
Publication-safe wording:
- 2Signals has controlled benchmark evidence that compares correctness and timing against Freqtrade in named local boundaries.
- The EMA side-by-side slice passes correctness for 10 shared variants and records both 2Signals and Freqtrade workflow timing.
- The complex futures slice passes fresh 2Signals vs fresh Freqtrade correctness on 181,447 candles and 123 compared trades.
- Freqtrade boundary references are workflow measurements, not pure algorithm-only measurements.
Avoid:
- "2Signals is X times faster than Freqtrade" without boundary labels.
- "Pure engine-to-engine comparison" for the current Freqtrade workflow rows.
- "Full production
/builderlatency" for the controlled Builder-equivalent or BacktestService timings. - Generalizing the EMA result to all strategies, all exchanges or all datasets.
What Seems Unnecessary Right Now
The useful evidence should stay focused on benchmark results, correctness and reproduction. The following are low-value unless there is a specific publication need:
| Item | Recommendation | Reason |
|---|---|---|
| Daily-generated whitepaper/deck pipeline | Do not maintain for now. | The evidence changes when benchmark scope changes, not daily. Manual summaries are clearer. |
| Multiple active whitepaper drafts with overlapping numbers | Treat v0.1, v0.2 and v0.3 as historical/supporting. | They create confusion unless v0.4 and this report are the current entry points. |
| Public generated evidence JSON just for the whitepaper page | Avoid unless the page becomes data-driven from raw artifacts. | A hand-maintained front-door report is simpler and easier to audit now. |
| More tiny EMA-only reports | Deprioritize. | The complex futures correctness slice is more useful for credibility. |
| Marketing ratios without boundary labels | Do not use. | The current comparison boundaries are intentionally different. |
Keep:
- raw benchmark JSON artifacts;
- correctness artifacts;
- matrix reports;
- the Freqtrade boundary audit;
- the complex futures reports;
- the production-like Builder UI latency report.
Recommended Next Step
Use this document as the main benchmark reference in the whitepaper and funding materials, then improve the benchmark itself rather than adding more document generation:
- rerun the main EMA and complex slices on a clean tagged evidence commit;
- export the raw artifacts listed by the source reports;
- add one larger non-EMA side-by-side timing slice only when correctness can be enforced with the same discipline.
docs/benchmarks/results/controlled-ema-2signals-variant-scale-btcusdt-5m-v2.md2Signals EMA variant scale v2Main 2Signals scaling result. This is the best current evidence for related strategy variant exploration.What to look for: Cold and warm medians, per-variant medians, dataset correctness and strategy correctness counts.Open
controlled-ema-2signals-variant-scale-btcusdt-5m-v2
Status: generated controlled 2Signals-only variant scale benchmark. This report is neutral and limited to the Node/service boundary described below.
Goal
Measure how the 2Signals Node/service engine path scales across related EMA strategy variants, including cache, memory and cleanup diagnostics.
Variant Space
- Version:
ema-grid-v2. - Fast EMA periods:
20through69. - Slow EMA periods:
200, 180, 220, 160, 240, anchored around EMA(200). - Operator combinations: crossed_above/crossed_below, crossed_above/crossed_above, crossed_below/crossed_above, crossed_below/crossed_below.
- Deterministic order: slow period, operator pair, fast period.
- The v2 space uses slow-period combinations because 1000 sensible unique variants cannot be produced from fast EMA periods alone on a 620-candle fixture.
Dataset
- Pair:
BTC/USDT - Timeframe:
5m - Candle count:
620 - Start:
2023-12-31T07:20:00.000Z - Backtest start:
2024-01-01T00:00:00.000Z - End:
2024-01-02T10:55:00.000Z - Dataset hash:
499155587500a60de08fe8edd922bcd432d5ce36e80b106814898955264ae5fe
Correctness Policy
- Correctness runs before timing and outside the measured benchmark phase.
- Dataset correctness is checked once per unique dataset hash and is not repeated for every strategy variant.
- Dataset correctness confirms dataset hash, pair, timeframe, timerange, candle count, first/last timestamp, OHLCV checksum and a dedicated fixture-to-adapter OHLCV comparison.
- Strategy correctness compares indicator series, entry/exit masks, signal timestamps, trades, fees, P/L and result hashes.
- 10 variants use full strategy correctness for every variant plus full result-hash validation.
- 100/500/1000 variants use full result-hash validation for every variant plus deterministic sampled strategy correctness.
Dataset Correctness
| Dataset hash | Pair | Timeframe | Timerange | Candle count | First timestamp | Last timestamp | OHLCV checksum | Adapter candle comparisons | Status |
|---|---|---|---|---|---|---|---|---|---|
| 499155587500a60de08fe8edd922bcd432d5ce36e80b106814898955264ae5fe | BTC/USDT | 5m | 2023-12-31T07:20:00.000Z -> 2024-01-02T10:55:00.000Z | 620 | 2023-12-31T07:20:00.000Z | 2024-01-02T10:55:00.000Z | 5f0a3cdc7c19d03ece613d36f94877c4e39f26e532d94c97cc9f989c28b86867 | 620 | passed |
Strategy Correctness
| Variants | Scope | Strategy variants checked | Passed | Sampled strategy variants | Indicator values compared | Mask values compared | Signals compared | Trades compared | Result metrics compared | Mismatches | Status |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 10 | full strategy correctness + full result-hash validation | 10 | 10 | 10 | 12400 | 12400 | 20 | 10 | 10 | 0 | passed |
| 100 | sampled strategy correctness + full result-hash validation | 100 | 100 | 10 | 12400 | 12400 | 20 | 6 | 100 | 0 | passed |
| 500 | sampled strategy correctness + full result-hash validation | 500 | 500 | 20 | 24800 | 24800 | 40 | 10 | 500 | 0 | passed |
| 1000 | sampled strategy correctness + full result-hash validation | 1000 | 1000 | 30 | 37200 | 37200 | 60 | 16 | 1000 | 0 | passed |
Timing Boundary
- Boundary:
2signals-node-service-sequential-variant-scale-v2. - Includes local frozen candles, indicator computation, cache lookup, rule/signal evaluation, trade simulation and result preparation.
- Excludes UI, chart rendering, IndexedDB, network, Freqtrade, visualization and artifact export.
Reuse Scenarios
- A. Cold variant sweep: cache cleared before the sweep.
- B. Warm identical sweep: identical variant space run again against the existing cache.
- C. Partial reuse sweep: deterministic parameter changes preserve some indicator series and change others.
- D. Return to previous variants: deterministic sampled subset of previous variants is run again.
- E. Single-parameter invalidation: baseline, one dependent parameter change, and return to the baseline configuration.
Scale Curve
| Variants | Cold median | Warm median | Per-variant median | p95 | Cache hit rate | Observed sweep heap high-water mark | Cleanup heap delta | Cache size |
|---|---|---|---|---|---|---|---|---|
| 10 | n=10, median=16.26 ms, mean=16.41 ms, min=15.46 ms, max=17.24 ms, p95=17.24 ms, stddev=0.51 ms | n=10, median=15.38 ms, mean=15.38 ms, min=14.96 ms, max=15.79 ms, p95=15.79 ms, stddev=0.24 ms | n=100, median=1.48 ms, mean=1.59 ms, min=1.32 ms, max=2.52 ms, p95=2.27 ms, stddev=0.32 ms | 17.24 ms | n=10, median=100%, mean=100%, min=100%, max=100%, p95=100%, stddev=0% | 248.37 MiB | 848 B | 835.9 KiB |
| 100 | n=10, median=151.18 ms, mean=150.82 ms, min=148.73 ms, max=152.6 ms, p95=152.6 ms, stddev=1.32 ms | n=10, median=145.42 ms, mean=145.36 ms, min=143.4 ms, max=147.35 ms, p95=147.35 ms, stddev=1.21 ms | n=1000, median=1.35 ms, mean=1.46 ms, min=1.16 ms, max=2.55 ms, p95=2.14 ms, stddev=0.29 ms | 152.6 ms | n=10, median=100%, mean=100%, min=100%, max=100%, p95=100%, stddev=0% | 269.59 MiB | 848 B | 5.29 MiB |
| 500 | n=5, median=752.54 ms, mean=756.22 ms, min=745.08 ms, max=768.96 ms, p95=768.96 ms, stddev=10.13 ms | n=5, median=757.29 ms, mean=771.58 ms, min=752.48 ms, max=824.05 ms, p95=824.05 ms, stddev=26.87 ms | n=2500, median=1.34 ms, mean=1.44 ms, min=1.15 ms, max=4.76 ms, p95=2.06 ms, stddev=0.29 ms | 768.96 ms | n=5, median=100%, mean=100%, min=100%, max=100%, p95=100%, stddev=0% | 296.85 MiB | 848 B | 14.12 MiB |
| 1000 | n=3, median=1.56 s, mean=1.58 s, min=1.54 s, max=1.64 s, p95=1.64 s, stddev=41.73 ms | n=3, median=1.68 s, mean=1.69 s, min=1.6 s, max=1.79 s, p95=1.79 s, stddev=74.95 ms | n=3000, median=1.35 ms, mean=1.47 ms, min=1.15 ms, max=7.21 ms, p95=2.17 ms, stddev=0.36 ms | 1.64 s | n=3, median=100%, mean=100%, min=100%, max=100%, p95=100%, stddev=0% | 379.05 MiB | 848 B | 21.33 MiB |
Scenario Timings
| Variants | Scenario | Samples | Total duration | Per variant | Cache lookup | Indicators | Rules/signals | Simulation | Metrics | Cache hit rate |
|---|---|---|---|---|---|---|---|---|---|---|
| 10 | cold-variant-sweep | 10 | n=10, median=16.26 ms, mean=16.41 ms, min=15.46 ms, max=17.24 ms, p95=17.24 ms, stddev=0.51 ms | n=100, median=1.48 ms, mean=1.59 ms, min=1.32 ms, max=2.52 ms, p95=2.27 ms, stddev=0.32 ms | n=10, median=0.05 ms, mean=0.05 ms, min=0.04 ms, max=0.05 ms, p95=0.05 ms, stddev=0 ms | n=10, median=1.16 ms, mean=1.21 ms, min=1.02 ms, max=1.74 ms, p95=1.74 ms, stddev=0.19 ms | n=10, median=1.66 ms, mean=1.69 ms, min=1.56 ms, max=1.81 ms, p95=1.81 ms, stddev=0.07 ms | n=10, median=3.66 ms, mean=3.69 ms, min=2.83 ms, max=4.85 ms, p95=4.85 ms, stddev=0.7 ms | n=10, median=0.29 ms, mean=0.32 ms, min=0.19 ms, max=0.44 ms, p95=0.44 ms, stddev=0.07 ms | n=10, median=24%, mean=24%, min=24%, max=24%, p95=24%, stddev=0% |
| 10 | warm-identical-sweep | 10 | n=10, median=15.38 ms, mean=15.38 ms, min=14.96 ms, max=15.79 ms, p95=15.79 ms, stddev=0.24 ms | n=100, median=1.37 ms, mean=1.49 ms, min=1.24 ms, max=2.46 ms, p95=2.13 ms, stddev=0.3 ms | n=10, median=0.05 ms, mean=0.05 ms, min=0.04 ms, max=0.09 ms, p95=0.09 ms, stddev=0.01 ms | n=10, median=0.82 ms, mean=0.95 ms, min=0.77 ms, max=1.51 ms, p95=1.51 ms, stddev=0.28 ms | n=10, median=1.19 ms, mean=1.24 ms, min=1.14 ms, max=1.42 ms, p95=1.42 ms, stddev=0.09 ms | n=10, median=3.58 ms, mean=3.57 ms, min=2.94 ms, max=4.69 ms, p95=4.69 ms, stddev=0.55 ms | n=10, median=0.09 ms, mean=0.09 ms, min=0.06 ms, max=0.12 ms, p95=0.12 ms, stddev=0.02 ms | n=10, median=100%, mean=100%, min=100%, max=100%, p95=100%, stddev=0% |
| 10 | partial-reuse-sweep | 10 | n=10, median=15.48 ms, mean=15.71 ms, min=15.34 ms, max=16.23 ms, p95=16.23 ms, stddev=0.3 ms | n=100, median=1.4 ms, mean=1.52 ms, min=1.25 ms, max=2.32 ms, p95=2.15 ms, stddev=0.29 ms | n=10, median=0.05 ms, mean=0.05 ms, min=0.04 ms, max=0.06 ms, p95=0.06 ms, stddev=0.01 ms | n=10, median=0.82 ms, mean=0.94 ms, min=0.78 ms, max=1.45 ms, p95=1.45 ms, stddev=0.23 ms | n=10, median=1.46 ms, mean=1.48 ms, min=1.42 ms, max=1.56 ms, p95=1.56 ms, stddev=0.05 ms | n=10, median=3.61 ms, mean=3.68 ms, min=2.98 ms, max=4.35 ms, p95=4.35 ms, stddev=0.47 ms | n=10, median=0.22 ms, mean=0.23 ms, min=0.18 ms, max=0.27 ms, p95=0.27 ms, stddev=0.03 ms | n=10, median=72%, mean=72%, min=72%, max=72%, p95=72%, stddev=0% |
| 10 | return-to-previous-variants | 10 | n=10, median=15.19 ms, mean=15.2 ms, min=14.2 ms, max=15.78 ms, p95=15.78 ms, stddev=0.43 ms | n=100, median=1.35 ms, mean=1.47 ms, min=1.24 ms, max=2.34 ms, p95=2.15 ms, stddev=0.3 ms | n=10, median=0.05 ms, mean=0.05 ms, min=0.04 ms, max=0.06 ms, p95=0.06 ms, stddev=0.01 ms | n=10, median=0.75 ms, mean=0.89 ms, min=0.71 ms, max=1.48 ms, p95=1.48 ms, stddev=0.29 ms | n=10, median=1.21 ms, mean=1.21 ms, min=1.11 ms, max=1.29 ms, p95=1.29 ms, stddev=0.05 ms | n=10, median=3.68 ms, mean=3.68 ms, min=2.94 ms, max=4.32 ms, p95=4.32 ms, stddev=0.49 ms | n=10, median=0.08 ms, mean=0.09 ms, min=0.05 ms, max=0.14 ms, p95=0.14 ms, stddev=0.03 ms | n=10, median=100%, mean=100%, min=100%, max=100%, p95=100%, stddev=0% |
| 10 | single-parameter-invalidation | 10 | n=10, median=5.11 ms, mean=4.86 ms, min=4.06 ms, max=5.44 ms, p95=5.44 ms, stddev=0.47 ms | n=30, median=1.39 ms, mean=1.56 ms, min=1.24 ms, max=2.39 ms, p95=2.33 ms, stddev=0.35 ms | n=10, median=0.02 ms, mean=0.09 ms, min=0.01 ms, max=0.71 ms, p95=0.71 ms, stddev=0.21 ms | n=10, median=0.29 ms, mean=0.38 ms, min=0.24 ms, max=1.05 ms, p95=1.05 ms, stddev=0.23 ms | n=10, median=0.41 ms, mean=0.42 ms, min=0.37 ms, max=0.47 ms, p95=0.47 ms, stddev=0.03 ms | n=10, median=0.93 ms, mean=1.11 ms, min=0.83 ms, max=1.65 ms, p95=1.65 ms, stddev=0.33 ms | n=10, median=0.07 ms, mean=0.08 ms, min=0.05 ms, max=0.12 ms, p95=0.12 ms, stddev=0.02 ms | n=10, median=73%, mean=73%, min=73%, max=73%, p95=73%, stddev=0% |
| 100 | cold-variant-sweep | 10 | n=10, median=151.18 ms, mean=150.82 ms, min=148.73 ms, max=152.6 ms, p95=152.6 ms, stddev=1.32 ms | n=1000, median=1.35 ms, mean=1.46 ms, min=1.16 ms, max=2.55 ms, p95=2.14 ms, stddev=0.29 ms | n=10, median=0.46 ms, mean=0.47 ms, min=0.45 ms, max=0.49 ms, p95=0.49 ms, stddev=0.02 ms | n=10, median=10.8 ms, mean=10.78 ms, min=9.9 ms, max=11.35 ms, p95=11.35 ms, stddev=0.53 ms | n=10, median=14.41 ms, mean=14.9 ms, min=13.55 ms, max=16.68 ms, p95=16.68 ms, stddev=0.98 ms | n=10, median=27.68 ms, mean=28.32 ms, min=26.32 ms, max=32.17 ms, p95=32.17 ms, stddev=1.96 ms | n=10, median=1.83 ms, mean=1.83 ms, min=1.51 ms, max=2.17 ms, p95=2.17 ms, stddev=0.19 ms | n=10, median=53%, mean=53%, min=53%, max=53%, p95=53%, stddev=0% |
| 100 | warm-identical-sweep | 10 | n=10, median=145.42 ms, mean=145.36 ms, min=143.4 ms, max=147.35 ms, p95=147.35 ms, stddev=1.21 ms | n=1000, median=1.31 ms, mean=1.4 ms, min=1.14 ms, max=3.74 ms, p95=1.96 ms, stddev=0.26 ms | n=10, median=0.48 ms, mean=0.48 ms, min=0.47 ms, max=0.5 ms, p95=0.5 ms, stddev=0.01 ms | n=10, median=8.53 ms, mean=8.45 ms, min=7.6 ms, max=9.42 ms, p95=9.42 ms, stddev=0.49 ms | n=10, median=10.92 ms, mean=11.73 ms, min=10.72 ms, max=13.6 ms, p95=13.6 ms, stddev=1.03 ms | n=10, median=28.56 ms, mean=28.58 ms, min=27.75 ms, max=29.47 ms, p95=29.47 ms, stddev=0.57 ms | n=10, median=0.71 ms, mean=0.73 ms, min=0.67 ms, max=0.79 ms, p95=0.79 ms, stddev=0.04 ms | n=10, median=100%, mean=100%, min=100%, max=100%, p95=100%, stddev=0% |
| 100 | partial-reuse-sweep | 10 | n=10, median=147.92 ms, mean=152.16 ms, min=145.58 ms, max=183.61 ms, p95=183.61 ms, stddev=11.09 ms | n=1000, median=1.33 ms, mean=1.45 ms, min=1.15 ms, max=5.82 ms, p95=2.03 ms, stddev=0.38 ms | n=10, median=0.48 ms, mean=0.49 ms, min=0.46 ms, max=0.61 ms, p95=0.61 ms, stddev=0.04 ms | n=10, median=8.84 ms, mean=8.92 ms, min=7.59 ms, max=10.76 ms, p95=10.76 ms, stddev=0.77 ms | n=10, median=13.18 ms, mean=14.1 ms, min=12.27 ms, max=19.68 ms, p95=19.68 ms, stddev=2.23 ms | n=10, median=28.23 ms, mean=29.31 ms, min=26.48 ms, max=33.15 ms, p95=33.15 ms, stddev=2.12 ms | n=10, median=1.23 ms, mean=1.3 ms, min=1.1 ms, max=1.92 ms, p95=1.92 ms, stddev=0.22 ms | n=10, median=83%, mean=83%, min=83%, max=83%, p95=83%, stddev=0% |
| 100 | return-to-previous-variants | 10 | n=10, median=15.35 ms, mean=15.45 ms, min=14.64 ms, max=16.13 ms, p95=16.13 ms, stddev=0.43 ms | n=100, median=1.33 ms, mean=1.48 ms, min=1.15 ms, max=2.75 ms, p95=2.41 ms, stddev=0.39 ms | n=10, median=0.05 ms, mean=0.05 ms, min=0.04 ms, max=0.06 ms, p95=0.06 ms, stddev=0.01 ms | n=10, median=0.81 ms, mean=0.93 ms, min=0.7 ms, max=1.69 ms, p95=1.69 ms, stddev=0.3 ms | n=10, median=1.13 ms, mean=1.16 ms, min=1.05 ms, max=1.36 ms, p95=1.36 ms, stddev=0.09 ms | n=10, median=2.93 ms, mean=3.04 ms, min=2.5 ms, max=3.59 ms, p95=3.59 ms, stddev=0.43 ms | n=10, median=0.09 ms, mean=0.08 ms, min=0.04 ms, max=0.1 ms, p95=0.1 ms, stddev=0.03 ms | n=10, median=100%, mean=100%, min=100%, max=100%, p95=100%, stddev=0% |
| 100 | single-parameter-invalidation | 10 | n=10, median=4.89 ms, mean=5.24 ms, min=4.59 ms, max=5.85 ms, p95=5.85 ms, stddev=0.52 ms | n=30, median=1.53 ms, mean=1.61 ms, min=1.34 ms, max=2.57 ms, p95=2.45 ms, stddev=0.34 ms | n=10, median=0.02 ms, mean=0.02 ms, min=0.02 ms, max=0.03 ms, p95=0.03 ms, stddev=0 ms | n=10, median=0.32 ms, mean=0.33 ms, min=0.3 ms, max=0.35 ms, p95=0.35 ms, stddev=0.02 ms | n=10, median=0.41 ms, mean=0.41 ms, min=0.37 ms, max=0.45 ms, p95=0.45 ms, stddev=0.02 ms | n=10, median=0.94 ms, mean=1.32 ms, min=0.9 ms, max=1.98 ms, p95=1.98 ms, stddev=0.48 ms | n=10, median=0.09 ms, mean=0.09 ms, min=0.07 ms, max=0.1 ms, p95=0.1 ms, stddev=0.01 ms | n=10, median=73%, mean=73%, min=73%, max=73%, p95=73%, stddev=0% |
| 500 | cold-variant-sweep | 5 | n=5, median=752.54 ms, mean=756.22 ms, min=745.08 ms, max=768.96 ms, p95=768.96 ms, stddev=10.13 ms | n=2500, median=1.34 ms, mean=1.44 ms, min=1.15 ms, max=4.76 ms, p95=2.06 ms, stddev=0.29 ms | n=5, median=2.32 ms, mean=2.36 ms, min=2.26 ms, max=2.58 ms, p95=2.58 ms, stddev=0.11 ms | n=5, median=44.14 ms, mean=44.31 ms, min=43.01 ms, max=46.07 ms, p95=46.07 ms, stddev=1.08 ms | n=5, median=68.48 ms, mean=69.08 ms, min=67.11 ms, max=72.3 ms, p95=72.3 ms, stddev=1.87 ms | n=5, median=135.41 ms, mean=137.52 ms, min=135.21 ms, max=142.91 ms, p95=142.91 ms, stddev=3.03 ms | n=5, median=6.43 ms, mean=6.49 ms, min=6.22 ms, max=6.76 ms, p95=6.76 ms, stddev=0.21 ms | n=5, median=73%, mean=73%, min=73%, max=73%, p95=73%, stddev=0% |
| 500 | warm-identical-sweep | 5 | n=5, median=757.29 ms, mean=771.58 ms, min=752.48 ms, max=824.05 ms, p95=824.05 ms, stddev=26.87 ms | n=2500, median=1.32 ms, mean=1.44 ms, min=1.17 ms, max=20.37 ms, p95=2.03 ms, stddev=0.51 ms | n=5, median=2.41 ms, mean=2.59 ms, min=2.33 ms, max=3.34 ms, p95=3.34 ms, stddev=0.38 ms | n=5, median=41.39 ms, mean=41.69 ms, min=38.98 ms, max=45.5 ms, p95=45.5 ms, stddev=2.18 ms | n=5, median=55.07 ms, mean=56.47 ms, min=54.12 ms, max=62.13 ms, p95=62.13 ms, stddev=2.92 ms | n=5, median=142.22 ms, mean=143.22 ms, min=137.68 ms, max=152.12 ms, p95=152.12 ms, stddev=4.8 ms | n=5, median=3.59 ms, mean=3.85 ms, min=3.54 ms, max=4.42 ms, p95=4.42 ms, stddev=0.36 ms | n=5, median=100%, mean=100%, min=100%, max=100%, p95=100%, stddev=0% |
| 500 | partial-reuse-sweep | 5 | n=5, median=765.98 ms, mean=772.06 ms, min=760.32 ms, max=795.68 ms, p95=795.68 ms, stddev=12.55 ms | n=2500, median=1.33 ms, mean=1.44 ms, min=1.17 ms, max=6.78 ms, p95=2.06 ms, stddev=0.34 ms | n=5, median=2.41 ms, mean=2.45 ms, min=2.41 ms, max=2.53 ms, p95=2.53 ms, stddev=0.05 ms | n=5, median=41.94 ms, mean=42.1 ms, min=41.2 ms, max=43.54 ms, p95=43.54 ms, stddev=0.8 ms | n=5, median=58.66 ms, mean=57.98 ms, min=55.88 ms, max=59.2 ms, p95=59.2 ms, stddev=1.23 ms | n=5, median=137.4 ms, mean=138.53 ms, min=135.2 ms, max=141.77 ms, p95=141.77 ms, stddev=2.46 ms | n=5, median=4.4 ms, mean=4.63 ms, min=4.34 ms, max=5.12 ms, p95=5.12 ms, stddev=0.33 ms | n=5, median=96%, mean=96%, min=96%, max=96%, p95=96%, stddev=0% |
| 500 | return-to-previous-variants | 5 | n=5, median=30.8 ms, mean=31.43 ms, min=29.5 ms, max=35.93 ms, p95=35.93 ms, stddev=2.3 ms | n=100, median=1.3 ms, mean=1.43 ms, min=1.19 ms, max=2.41 ms, p95=2.22 ms, stddev=0.31 ms | n=5, median=0.1 ms, mean=0.09 ms, min=0.08 ms, max=0.1 ms, p95=0.1 ms, stddev=0.01 ms | n=5, median=1.49 ms, mean=1.47 ms, min=1.32 ms, max=1.6 ms, p95=1.6 ms, stddev=0.09 ms | n=5, median=2.14 ms, mean=2.35 ms, min=2.07 ms, max=3.24 ms, p95=3.24 ms, stddev=0.45 ms | n=5, median=4.75 ms, mean=4.89 ms, min=4.46 ms, max=5.3 ms, p95=5.3 ms, stddev=0.32 ms | n=5, median=0.13 ms, mean=0.12 ms, min=0.06 ms, max=0.15 ms, p95=0.15 ms, stddev=0.03 ms | n=5, median=100%, mean=100%, min=100%, max=100%, p95=100%, stddev=0% |
| 500 | single-parameter-invalidation | 5 | n=5, median=4.47 ms, mean=4.6 ms, min=4.43 ms, max=4.81 ms, p95=4.81 ms, stddev=0.17 ms | n=15, median=1.39 ms, mean=1.41 ms, min=1.3 ms, max=1.59 ms, p95=1.59 ms, stddev=0.08 ms | n=5, median=0.02 ms, mean=0.02 ms, min=0.02 ms, max=0.03 ms, p95=0.03 ms, stddev=0 ms | n=5, median=0.31 ms, mean=0.31 ms, min=0.29 ms, max=0.35 ms, p95=0.35 ms, stddev=0.02 ms | n=5, median=0.38 ms, mean=0.38 ms, min=0.35 ms, max=0.41 ms, p95=0.41 ms, stddev=0.02 ms | n=5, median=0.85 ms, mean=0.87 ms, min=0.84 ms, max=0.91 ms, p95=0.91 ms, stddev=0.03 ms | n=5, median=0.02 ms, mean=0.02 ms, min=0.01 ms, max=0.04 ms, p95=0.04 ms, stddev=0.01 ms | n=5, median=80%, mean=80%, min=80%, max=80%, p95=80%, stddev=0% |
| 1000 | cold-variant-sweep | 3 | n=3, median=1.56 s, mean=1.58 s, min=1.54 s, max=1.64 s, p95=1.64 s, stddev=41.73 ms | n=3000, median=1.35 ms, mean=1.47 ms, min=1.15 ms, max=7.21 ms, p95=2.17 ms, stddev=0.36 ms | n=3, median=4.8 ms, mean=4.99 ms, min=4.8 ms, max=5.38 ms, p95=5.38 ms, stddev=0.27 ms | n=3, median=85.31 ms, mean=85.24 ms, min=83.2 ms, max=87.2 ms, p95=87.2 ms, stddev=1.63 ms | n=3, median=134.94 ms, mean=135.63 ms, min=132.96 ms, max=139 ms, p95=139 ms, stddev=2.51 ms | n=3, median=282.98 ms, mean=280.05 ms, min=272.36 ms, max=284.8 ms, p95=284.8 ms, stddev=5.49 ms | n=3, median=12.14 ms, mean=12.71 ms, min=12.12 ms, max=13.87 ms, p95=13.87 ms, stddev=0.82 ms | n=3, median=76%, mean=76%, min=76%, max=76%, p95=76%, stddev=0% |
| 1000 | warm-identical-sweep | 3 | n=3, median=1.68 s, mean=1.69 s, min=1.6 s, max=1.79 s, p95=1.79 s, stddev=74.95 ms | n=3000, median=1.37 ms, mean=1.53 ms, min=1.21 ms, max=17.68 ms, p95=2.23 ms, stddev=0.49 ms | n=3, median=5.12 ms, mean=5.47 ms, min=4.85 ms, max=6.43 ms, p95=6.43 ms, stddev=0.69 ms | n=3, median=91.07 ms, mean=90.58 ms, min=85.51 ms, max=95.15 ms, p95=95.15 ms, stddev=3.95 ms | n=3, median=124.55 ms, mean=122.53 ms, min=113.12 ms, max=129.92 ms, p95=129.92 ms, stddev=7.01 ms | n=3, median=265.11 ms, mean=285.13 ms, min=264.72 ms, max=325.57 ms, p95=325.57 ms, stddev=28.59 ms | n=3, median=7.55 ms, mean=8.46 ms, min=6.39 ms, max=11.44 ms, p95=11.44 ms, stddev=2.16 ms | n=3, median=100%, mean=100%, min=100%, max=100%, p95=100%, stddev=0% |
| 1000 | partial-reuse-sweep | 3 | n=3, median=1.71 s, mean=1.69 s, min=1.64 s, max=1.71 s, p95=1.71 s, stddev=32.18 ms | n=3000, median=1.37 ms, mean=1.53 ms, min=1.21 ms, max=8.19 ms, p95=2.26 ms, stddev=0.43 ms | n=3, median=5.3 ms, mean=5.36 ms, min=5.12 ms, max=5.67 ms, p95=5.67 ms, stddev=0.23 ms | n=3, median=91.44 ms, mean=93.41 ms, min=91.22 ms, max=97.58 ms, p95=97.58 ms, stddev=2.95 ms | n=3, median=121.82 ms, mean=122.9 ms, min=119.67 ms, max=127.22 ms, p95=127.22 ms, stddev=3.18 ms | n=3, median=282.03 ms, mean=280.63 ms, min=267.56 ms, max=292.29 ms, p95=292.29 ms, stddev=10.14 ms | n=3, median=8.33 ms, mean=8.34 ms, min=7.26 ms, max=9.43 ms, p95=9.43 ms, stddev=0.89 ms | n=3, median=100%, mean=100%, min=100%, max=100%, p95=100%, stddev=0% |
| 1000 | return-to-previous-variants | 3 | n=3, median=50.91 ms, mean=50.06 ms, min=48.17 ms, max=51.1 ms, p95=51.1 ms, stddev=1.34 ms | n=90, median=1.38 ms, mean=1.47 ms, min=1.22 ms, max=2.51 ms, p95=2.15 ms, stddev=0.28 ms | n=3, median=0.19 ms, mean=0.18 ms, min=0.15 ms, max=0.19 ms, p95=0.19 ms, stddev=0.02 ms | n=3, median=2.44 ms, mean=2.44 ms, min=2.33 ms, max=2.54 ms, p95=2.54 ms, stddev=0.09 ms | n=3, median=3.52 ms, mean=3.44 ms, min=3.21 ms, max=3.6 ms, p95=3.6 ms, stddev=0.17 ms | n=3, median=9.28 ms, mean=9.01 ms, min=7.58 ms, max=10.17 ms, p95=10.17 ms, stddev=1.07 ms | n=3, median=0.27 ms, mean=0.26 ms, min=0.17 ms, max=0.35 ms, p95=0.35 ms, stddev=0.07 ms | n=3, median=100%, mean=100%, min=100%, max=100%, p95=100%, stddev=0% |
| 1000 | single-parameter-invalidation | 3 | n=3, median=4.74 ms, mean=4.89 ms, min=4.69 ms, max=5.24 ms, p95=5.24 ms, stddev=0.25 ms | n=9, median=1.46 ms, mean=1.45 ms, min=1.33 ms, max=1.59 ms, p95=1.59 ms, stddev=0.08 ms | n=3, median=0.02 ms, mean=0.02 ms, min=0.02 ms, max=0.03 ms, p95=0.03 ms, stddev=0 ms | n=3, median=0.31 ms, mean=0.32 ms, min=0.3 ms, max=0.36 ms, p95=0.36 ms, stddev=0.03 ms | n=3, median=0.41 ms, mean=0.41 ms, min=0.4 ms, max=0.42 ms, p95=0.42 ms, stddev=0.01 ms | n=3, median=0.87 ms, mean=0.9 ms, min=0.86 ms, max=0.96 ms, p95=0.96 ms, stddev=0.04 ms | n=3, median=0.02 ms, mean=0.03 ms, min=0.02 ms, max=0.04 ms, p95=0.04 ms, stddev=0.01 ms | n=3, median=80%, mean=80%, min=80%, max=80%, p95=80%, stddev=0% |
Cache Diagnostics
- Cache diagnostics in this table are aggregate totals across measured samples for each scale level, not a single-sweep value.
- Cold sweeps start with an empty cache, but related variants can still reuse cache entries created earlier in the same sweep.
- Warm 100% cache hit rate means measured cache reads hit; per-variant orchestration, rule/signal handling, simulation, metrics shaping and diagnostics still run.
| Variants | Reused indicator series | Recomputed indicator series | Unique indicator entries | Result misses | Unique result entries | Eviction policy | Eviction count |
|---|---|---|---|---|---|---|---|
| 10 | 730 | 130 | n=50, median=12, mean=11.8, min=11, max=13, p95=13, stddev=0.75 | 110 | n=50, median=10, mean=9, min=7, max=11, p95=11, stddev=1.67 | not implemented | not applicable |
| 100 | 5730 | 530 | n=50, median=52, mean=51.8, min=51, max=53, p95=53, stddev=0.75 | 460 | n=50, median=45, mean=41.6, min=36, max=46, p95=46, stddev=4.59 | not implemented | not applicable |
| 500 | 14955 | 275 | n=25, median=54, mean=53.8, min=53, max=55, p95=55, stddev=0.75 | 470 | n=25, median=94, mean=89.6, min=83, max=94, p95=94, stddev=5.39 | not implemented | not applicable |
| 1000 | 18030 | 168 | n=15, median=55, mean=55.2, min=55, max=56, p95=56, stddev=0.4 | 405 | n=15, median=135, mean=135, min=135, max=135, p95=135, stddev=0 | not implemented | not applicable |
Memory Methodology
- Memory uses Node
process.memoryUsage()from this benchmark process. - The benchmark invokes
global.gc?.()around sweeps and cleanup when available; this run recordedgcAvailable=0andgcRan=false, so GC was not forced. - These numbers are useful for relative local process diagnostics, not total application memory.
Observed sweep heap high-water markis the max ofheapUsedbefore and after each measured sweep; it is not a continuously sampled peak.Cleanup heap deltaisheapUsed after cleanup - heapUsed before cleanup. The raw JSON field remainsretainedHeapBytesfor backward compatibility, but it should not be interpreted as retained heap from a stable process baseline.Cache sizeis a benchmark cache mock JSON serialization estimate fromBuffer.byteLength(JSON.stringify(entries), "utf8"); it is not IndexedDB size or total process memory.
Scaling Growth
| From | To | Variant growth | Time growth | Time growth / variant growth | Memory growth | Per-variant time change | Cache hit-rate delta |
|---|---|---|---|---|---|---|---|
| 10 | 100 | 10 | 9.3 | 0.93 | 0.81 | 0.91 | 0 |
| 100 | 500 | 5 | 4.98 | 1 | 1.16 | 0.99 | 0 |
| 500 | 1000 | 2 | 2.07 | 1.04 | 1.34 | 1.01 | 0 |
Invalidation And Cleanup
| Variants | Cleanup duration | Entries before | Entries after | Serialized bytes before | Serialized bytes after | Cleanup heap delta | Stale result entries |
|---|---|---|---|---|---|---|---|
| 10 | 0.01 ms | 56 | 0 | 835.9 KiB | 2 B | 848 B | 0 |
| 100 | 0.01 ms | 326 | 0 | 5.29 MiB | 2 B | 848 B | 0 |
| 500 | 0.01 ms | 801 | 0 | 14.12 MiB | 2 B | 848 B | 0 |
| 1000 | 0.01 ms | 1193 | 0 | 21.33 MiB | 2 B | 848 B | 0 |
Frozen Freqtrade Boundary Reference
- Freqtrade
--strategy-list, 10 variants: total workflow median5.38 s. - Freqtrade separate process per variant, 10 variants: total workflow median
35.27 s. - These are frozen boundary references only; this report does not extrapolate Freqtrade to 100/500/1000 variants.
Limitations
- This is one local BTC/USDT 5m fixture with 620 candles.
- The v2 variant grid intentionally expands slow EMA periods around 200 to reach 1000 deterministic variants.
- The benchmark does not include browser rendering, auth, Apollo, IndexedDB, charting or Freqtrade execution.
- Cache eviction is not implemented in this benchmark cache mock.
Neutral Conclusions
All measured v2 samples and correctness gates passed. Timing values should be interpreted only for the explicitly named 2Signals Node/service boundary.
Artifacts
- Result JSON:
benchmarks/results/controlled-ema-2signals-variant-scale-btcusdt-5m-v2/2026-07-26T22-21-05-858Z/2026-07-26T22-21-05-858Z.controlled-ema-2signals-variant-scale-btcusdt-5m-v2.json - Correctness report:
benchmarks/results/controlled-ema-2signals-variant-scale-btcusdt-5m-v2/2026-07-26T22-21-05-858Z/controlled-ema-2signals-variant-scale-btcusdt-5m-v2.correctness.json - Dataset metadata:
benchmarks/results/controlled-ema-2signals-variant-scale-btcusdt-5m-v2/2026-07-26T22-21-05-858Z/dataset.metadata.json - Strategy metadata:
benchmarks/results/controlled-ema-2signals-variant-scale-btcusdt-5m-v2/2026-07-26T22-21-05-858Z/strategy.metadata.json - Docs report:
docs/benchmarks/results/controlled-ema-2signals-variant-scale-btcusdt-5m-v2.md
docs/benchmarks/results/controlled-ema-variant-scale-side-by-side-v1.mdEMA side-by-side matrixNeutral side-by-side correctness and boundary matrix for the controlled EMA variants.What to look for: Boundary-specific timing columns and correctness status. Avoid reading it as a pure engine-to-engine ratio.Open
controlled-ema-variant-scale-side-by-side-v1
Status: generated neutral side-by-side matrix for the controlled EMA variant scale benchmark. Final scale comparison status: passed.
These measurements describe different execution boundaries and must not be interpreted as a pure engine-to-engine speed comparison.
Generated at: 2026-07-26T22:36:04.392Z
Experiment validation
The report is generated only after timing metadata checks pass. Dataset correctness and strategy correctness can pass or fail independently; any failed dataset check or strategy variant sets the final scale comparison status to failed.
| Check | Status | Detail |
|---|---|---|
| comparison family | passed | controlled-ema-variant-scale-btcusdt-5m-v1 and controlled-ema-freqtrade-variant-scale-btcusdt-5m-v1 |
| pair | passed | BTC/USDT / BTC/USDT |
| timeframe | passed | 5m / 5m |
| timerange | passed | {"freqtrade":{"backtestStart":"2024-01-01T00:00:00.000Z","end":"2024-01-02T10:55:00.000Z","start":"2023-12-31T07:20:00.000Z"},"twoSignals":{"backtestStart":"2024-01-01T00:00:00.000Z","end":"2024-01-02T10:55:00.000Z","start":"2023-12-31T07:20:00.000Z"}} |
| dataset hash | passed | 499155587500a60de08fe8edd922bcd432d5ce36e80b106814898955264ae5fe / 499155587500a60de08fe8edd922bcd432d5ce36e80b106814898955264ae5fe |
| candle count | passed | 620 / 620 |
| EMA slow period | passed | 200 / 200 |
| EMA fast variants | passed | 50,51,52,53,54,55,56,57,58,59 / 50,51,52,53,54,55,56,57,58,59 |
| Entry/Exit rule definitions | passed | 10 shared strategy definitions |
| fee and execution assumptions | passed | per-variant strategy hashes include the controlled fee/stake/risk/execution contract generated by the comparison runner |
| measured sample count | passed | 10 / 10 |
| correctness status | passed | passed / passed |
| failures | passed | 0 / 0 |
| trade count artifacts | passed | 10 / 10 |
| correctness artifact compatibility | passed | result hashes are stable inside each system; cross-system hashes are system-specific artifacts and are not required to be identical |
| commit SHA | passed | f771cf2ea946f9cac03392f2b1ea06b4d8185259 / f771cf2ea946f9cac03392f2b1ea06b4d8185259 |
Correctness validation
| Check | Status | Detail |
|---|---|---|
| correctness family | passed | controlled-ema-variant-scale-side-by-side-v1 |
| dataset correctness hash | passed | 499155587500a60de08fe8edd922bcd432d5ce36e80b106814898955264ae5fe / 499155587500a60de08fe8edd922bcd432d5ce36e80b106814898955264ae5fe / 499155587500a60de08fe8edd922bcd432d5ce36e80b106814898955264ae5fe |
| dataset correctness candle count | passed | 620 / 620 / 620 |
| dataset correctness timerange | passed | {"correctness":{"backtestStart":"2024-01-01T00:00:00.000Z","end":"2024-01-02T10:55:00.000Z","start":"2023-12-31T07:20:00.000Z"},"freqtrade":{"backtestStart":"2024-01-01T00:00:00.000Z","end":"2024-01-02T10:55:00.000Z","start":"2023-12-31T07:20:00.000Z"},"twoSignals":{"backtestStart":"2024-01-01T00:00:00.000Z","end":"2024-01-02T10:55:00.000Z","start":"2023-12-31T07:20:00.000Z"}} |
| strategy correctness EMA fast variants | passed | 50,51,52,53,54,55,56,57,58,59 |
| strategy correctness variant count | passed | 10 |
| unique datasets checked | passed | 1 |
| correctness mismatch count available | passed | 0 |
Measurement boundaries
2Signals:
- in-process engine/service workflow;
- local frozen data;
- no UI;
- no network fetch;
- no separate process startup for each variant;
- includes indicator computation, signals, simulation and result preparation;
- uses the existing cache and reuse mechanisms.
Freqtrade:
- separate local Python/Freqtrade process for each variant;
- complete result cache disabled;
- local data;
- includes process startup, initialization, backtesting, export and parsing;
freqtradeBacktestingMsis a marker reported around Freqtradebacktesting.start(), not a full isolated algorithm-only measurement.
Main Matrix
Correctness gate for the shared 10-variant level: passed.
| Metric | 2Signals boundary | 2Signals result | Freqtrade boundary | Freqtrade result |
|---|---|---|---|---|
| number of variants | shared controlled variant set | 10 | shared controlled variant set | 10 |
| total measured workflow median | in-process workflow for 10 sequential variants | 20.25 ms | total process workflow for 10 sequential variants | 35.52 s |
| total workflow p95 | in-process workflow for 10 sequential variants | 21.42 ms | total process workflow for 10 sequential variants | 35.91 s |
| per-variant median | per in-process variant | 1.4 ms | per generated Freqtrade process | 3.39 s |
| per-variant p95 | per in-process variant | 2.08 ms | per generated Freqtrade process | 3.77 s |
| total child process median | not applicable | not applicable | summed child process duration | 34.33 s |
| reported backtesting phase median | not applicable | not applicable | wrapper marker around Freqtrade backtesting.start() | 2.91 s |
| cache hits | indicator cache diagnostics | 90 | complete result cache disabled | not applicable |
| cache misses | indicator cache diagnostics | 110 | complete result cache disabled | not applicable |
| reused indicator series | indicator cache diagnostics | 90 | not instrumented in this process workflow | not measured |
| recomputed indicator series | indicator cache diagnostics | 110 | not instrumented in this process workflow | not measured |
| correctness status | measured sample correctness guard | passed | measured sample correctness guard | passed |
| dataset correctness status | dataset correctness once per unique dataset hash, outside measured timing phase | passed | dataset correctness once per unique dataset hash, outside measured timing phase | passed |
| unique datasets checked | dataset metadata and OHLCV adapter check | 1 | dataset metadata and OHLCV adapter check | 1 |
| dataset candle count | shared frozen dataset | 620 | shared frozen dataset | 620 |
| strategy correctness status | strategy correctness per EMA variant, outside measured timing phase | passed | strategy correctness per EMA variant, outside measured timing phase | passed |
| strategy variants checked | strategy variants | 10 | strategy variants | 10 |
| indicator values compared | EMA fast/slow series values | 12400 | EMA fast/slow series values | 12400 |
| mask values compared | entry and exit boolean masks | 12400 | entry and exit boolean masks | 12400 |
| signals compared | entry and exit signal timestamp lists | 20 | entry and exit signal timestamp lists | 20 |
| trades compared | trade rows and comparable trade fields | 10 | trade rows and comparable trade fields | 10 |
| result metrics compared | comparable aggregate result metrics | 20 | comparable aggregate result metrics | 20 |
| correctness mismatch count | dataset + strategy correctness | 0 | dataset + strategy correctness | 0 |
| failures | measured samples | 0 | measured samples | 0 |
| warnings | measured samples | 30 | measured samples | 50 |
| sample count | all samples for shared 10-variant scenario | 13 | all samples for shared 10-variant scenario | 13 |
| warm-up count | warm-up samples for shared 10-variant scenario | 3 | warm-up samples for shared 10-variant scenario | 3 |
| measured run count | measured samples for shared 10-variant scenario | 10 | measured samples for shared 10-variant scenario | 10 |
2Signals in-process variant workflow
- Total workflow median:
20.25 ms. - Per-variant median:
1.4 ms. - Indicator cache hits/misses:
90 / 110. - Indicator hit rate:
45%. - Reused EMA(200) indicator series:
90. - Recomputed fast EMA indicator series:
110. - Correctness:
passed.
Freqtrade process-based variant workflow
- Total workflow median:
35.52 s. - Total child process median:
34.33 s. - Reported backtesting median:
2.91 s. - Per-variant process median:
3.39 s. - Per-variant reported backtesting median:
287.39 ms. - Correctness:
passed.
Ratio Metrics
The following ratios are neutral descriptions of observed workflow timings. The numerator and denominator boundaries are intentionally different and are shown explicitly.
| Ratio | Numerator boundary | Numerator | Denominator boundary | Denominator | Value | Boundary note |
|---|---|---|---|---|---|---|
| freqtradeTotalWorkflowTo2SignalsInProcessWorkflowRatio | Freqtrade total process workflow median for 10 sequential variants | 35.52 s | 2Signals in-process workflow median for 10 sequential variants | 20.25 ms | 1753.88 | different execution boundaries; observed workflow ratio only |
| freqtradePerVariantProcessTo2SignalsInProcessVariantRatio | Freqtrade per-variant process median | 3.39 s | 2Signals per in-process variant median | 1.4 ms | 2422.95 | different execution boundaries; observed workflow ratio only |
| freqtradeReportedBacktestingTo2SignalsInProcessVariantRatio | Freqtrade per-variant reported backtesting marker median | 287.39 ms | 2Signals per in-process variant median | 1.4 ms | 205.28 | different execution boundaries; observed workflow ratio only |
Correctness
| Correctness check | Status | Detail |
|---|---|---|
| dataset equality | passed | checked 1 unique dataset hash; compared dataset hash, pair, timeframe, timerange, candle count, first/last timestamp, OHLCV checksum, timestamp order and duplicate timestamp count |
| EMA series equivalence | passed | compared EMA fast and EMA slow values for 10 strategy variants |
| entry/exit mask equivalence | passed | compared entry and exit boolean masks for each strategy variant |
| signal timestamp equivalence | passed | compared entry and exit signal timestamp lists exported by each system |
| trade equivalence | passed | compared trade count, pair, direction, entry/exit timestamps, entry/exit prices, stake, amount, fees, tags and duration |
| P/L equivalence | passed | compared profit abs, profit ratio and final balance where available |
| mismatch count | passed | 0 total mismatches across 1 dataset checks and 10 strategy variants; first mismatch: none |
| tolerance policy | passed | {"drawdown":0.000001,"ema":1e-8,"fee":1e-12,"finalBalance":0.000001,"ohlcv":0,"profitAbs":0.000001,"profitRatio":1e-10,"signalTimestamp":0,"stakeAmount":1e-8,"tradeAmount":1e-9,"tradeDuration":0,"tradePrice":1e-8} |
Per-variant correctness
| Variant | Status | Mismatches | First mismatch | Max abs diff | Max relative diff | Indicator values | Mask values | Signals | Trades | Result metrics | Tolerances |
|---|---|---|---|---|---|---|---|---|---|---|---|
| EMA 50/200 | passed | 0 | none | 1.0000803740695119e-8 | 2.887949086562619e-10 | 1240 | 1240 | 2 | 1 | 2 | {"drawdown":0.000001,"ema":1e-8,"fee":1e-12,"finalBalance":0.000001,"ohlcv":0,"profitAbs":0.000001,"profitRatio":1e-10,"signalTimestamp":0,"stakeAmount":1e-8,"tradeAmount":1e-9,"tradeDuration":0,"tradePrice":1e-8} |
| EMA 51/200 | passed | 0 | none | 1.000000082740371e-8 | 2.9504077335851305e-10 | 1240 | 1240 | 2 | 1 | 2 | {"drawdown":0.000001,"ema":1e-8,"fee":1e-12,"finalBalance":0.000001,"ohlcv":0,"profitAbs":0.000001,"profitRatio":1e-10,"signalTimestamp":0,"stakeAmount":1e-8,"tradeAmount":1e-9,"tradeDuration":0,"tradePrice":1e-8} |
| EMA 52/200 | passed | 0 | none | 1.000000082740371e-8 | 2.983618934609203e-10 | 1240 | 1240 | 2 | 1 | 2 | {"drawdown":0.000001,"ema":1e-8,"fee":1e-12,"finalBalance":0.000001,"ohlcv":0,"profitAbs":0.000001,"profitRatio":1e-10,"signalTimestamp":0,"stakeAmount":1e-8,"tradeAmount":1e-9,"tradeDuration":0,"tradePrice":1e-8} |
| EMA 53/200 | passed | 0 | none | 4.503897255148104e-13 | 4.503897255148104e-13 | 1240 | 1240 | 2 | 1 | 2 | {"drawdown":0.000001,"ema":1e-8,"fee":1e-12,"finalBalance":0.000001,"ohlcv":0,"profitAbs":0.000001,"profitRatio":1e-10,"signalTimestamp":0,"stakeAmount":1e-8,"tradeAmount":1e-9,"tradeDuration":0,"tradePrice":1e-8} |
| EMA 54/200 | passed | 0 | none | 4.503897255148104e-13 | 4.503897255148104e-13 | 1240 | 1240 | 2 | 1 | 2 | {"drawdown":0.000001,"ema":1e-8,"fee":1e-12,"finalBalance":0.000001,"ohlcv":0,"profitAbs":0.000001,"profitRatio":1e-10,"signalTimestamp":0,"stakeAmount":1e-8,"tradeAmount":1e-9,"tradeDuration":0,"tradePrice":1e-8} |
| EMA 55/200 | passed | 0 | none | 6.938893903907228e-17 | 6.938893903907228e-17 | 1240 | 1240 | 2 | 1 | 2 | {"drawdown":0.000001,"ema":1e-8,"fee":1e-12,"finalBalance":0.000001,"ohlcv":0,"profitAbs":0.000001,"profitRatio":1e-10,"signalTimestamp":0,"stakeAmount":1e-8,"tradeAmount":1e-9,"tradeDuration":0,"tradePrice":1e-8} |
| EMA 56/200 | passed | 0 | none | 1.5265566588595902e-16 | 1.5265566588595902e-16 | 1240 | 1240 | 2 | 1 | 2 | {"drawdown":0.000001,"ema":1e-8,"fee":1e-12,"finalBalance":0.000001,"ohlcv":0,"profitAbs":0.000001,"profitRatio":1e-10,"signalTimestamp":0,"stakeAmount":1e-8,"tradeAmount":1e-9,"tradeDuration":0,"tradePrice":1e-8} |
| EMA 57/200 | passed | 0 | none | 1.0000803740695119e-8 | 3.193785540339939e-10 | 1240 | 1240 | 2 | 1 | 2 | {"drawdown":0.000001,"ema":1e-8,"fee":1e-12,"finalBalance":0.000001,"ohlcv":0,"profitAbs":0.000001,"profitRatio":1e-10,"signalTimestamp":0,"stakeAmount":1e-8,"tradeAmount":1e-9,"tradeDuration":0,"tradePrice":1e-8} |
| EMA 58/200 | passed | 0 | none | 2.0289464552902814e-11 | 2.0289464552902814e-11 | 1240 | 1240 | 2 | 1 | 2 | {"drawdown":0.000001,"ema":1e-8,"fee":1e-12,"finalBalance":0.000001,"ohlcv":0,"profitAbs":0.000001,"profitRatio":1e-10,"signalTimestamp":0,"stakeAmount":1e-8,"tradeAmount":1e-9,"tradeDuration":0,"tradePrice":1e-8} |
| EMA 59/200 | passed | 0 | none | 2.0236520792416002e-11 | 2.0236520792416002e-11 | 1240 | 1240 | 2 | 1 | 2 | {"drawdown":0.000001,"ema":1e-8,"fee":1e-12,"finalBalance":0.000001,"ohlcv":0,"profitAbs":0.000001,"profitRatio":1e-10,"signalTimestamp":0,"stakeAmount":1e-8,"tradeAmount":1e-9,"tradeDuration":0,"tradePrice":1e-8} |
Future scaling matrix
| Variants | 2Signals status | Freqtrade status | Side-by-side status |
|---|---|---|---|
| 10 | measured | measured | included in this report |
| 100 | measured 2Signals-only | not yet measured side-by-side | not yet measured side-by-side |
| 500 | not yet measured side-by-side | not yet measured side-by-side | not yet measured side-by-side |
| 1000 | not yet measured side-by-side | not yet measured side-by-side | not yet measured side-by-side |
Methodological limitations
- 2Signals is measured as an in-process workflow while Freqtrade is measured through child processes.
- There is no isolated Freqtrade algorithm-only boundary in this report.
- Python and Freqtrade initialization are part of the Freqtrade total process workflow.
- Filesystem and OS page cache can affect repeated local result reads.
- UI rendering is excluded from both scale slices.
- Both slices use local frozen fixtures.
- The strategy is a simple EMA crossover family.
- The side-by-side level covers one pair and one timeframe only.
- Freqtrade memory usage is not measured in this slice.
- There is no long-running Freqtrade worker/API benchmark in this report.
Neutral conclusions
- Final correctness status for the shared 10-variant EMA scale level:
passed. - 2Signals executed the variants inside one process and reused part of the indicator results.
- Freqtrade executed every variant as a separate local process.
- The observed timings reflect these different execution models.
- The next benchmark step should investigate larger variant counts, memory, and a closer Freqtrade execution boundary if it can be obtained without patching Freqtrade internals.
Source artifacts
| Artifact | 2Signals | Freqtrade |
|---|---|---|
| raw JSON | benchmarks/results/controlled-ema-variant-scale-btcusdt-5m-v1/2026-07-26T22-27-15-168Z/2026-07-26T22-27-15-168Z.controlled-ema-variant-scale-btcusdt-5m-v1.json | benchmarks/results/controlled-ema-freqtrade-variant-scale-btcusdt-5m-v1/2026-07-26T22-27-23-697Z/2026-07-26T22-27-23-697Z.controlled-ema-freqtrade-variant-scale-btcusdt-5m-v1.json |
| source report | benchmarks/results/controlled-ema-variant-scale-btcusdt-5m-v1/2026-07-26T22-27-15-168Z/controlled-ema-variant-scale-btcusdt-5m-v1.md | benchmarks/results/controlled-ema-freqtrade-variant-scale-btcusdt-5m-v1/2026-07-26T22-27-23-697Z/controlled-ema-freqtrade-variant-scale-btcusdt-5m-v1.md |
| dataset metadata | benchmarks/results/controlled-ema-variant-scale-btcusdt-5m-v1/2026-07-26T22-27-15-168Z/dataset.metadata.json | benchmarks/results/controlled-ema-freqtrade-variant-scale-btcusdt-5m-v1/2026-07-26T22-27-23-697Z/dataset.metadata.json |
| strategy metadata | benchmarks/results/controlled-ema-variant-scale-btcusdt-5m-v1/2026-07-26T22-27-15-168Z/strategy.metadata.json | benchmarks/results/controlled-ema-freqtrade-variant-scale-btcusdt-5m-v1/2026-07-26T22-27-23-697Z/strategy.metadata.json |
| commit SHA | f771cf2ea946f9cac03392f2b1ea06b4d8185259 | f771cf2ea946f9cac03392f2b1ea06b4d8185259 |
| dataset hash | 499155587500a60de08fe8edd922bcd432d5ce36e80b106814898955264ae5fe | 499155587500a60de08fe8edd922bcd432d5ce36e80b106814898955264ae5fe |
| top-level strategy hash | 82f4e68f7c80fc256b716feb83507079eb3f6dc69553260b4357d4f1d6017c91 | 1f1722372515b1d6388f1e85db434c14c5e43e48eddd8c1839116b32d8fb41ef |
| shared per-variant strategy hashes | 10 matched hashes, first 47e679f2d0c29928f4031e459e045a9fdc105f62256cc0c40df335c7828e6011, last 133bfc4ab7e48549b9550d9dc1e7a234175f6a96b6bdb50a1bb42be50b13c5c1 | 10 matched hashes, first 47e679f2d0c29928f4031e459e045a9fdc105f62256cc0c40df335c7828e6011, last 133bfc4ab7e48549b9550d9dc1e7a234175f6a96b6bdb50a1bb42be50b13c5c1 |
| correctness JSON | benchmarks/results/controlled-ema-variant-scale-side-by-side-v1/2026-07-26T22-35-28-384Z/controlled-ema-variant-scale-side-by-side-v1.correctness.json | benchmarks/results/controlled-ema-variant-scale-side-by-side-v1/2026-07-26T22-35-28-384Z/controlled-ema-variant-scale-side-by-side-v1.correctness.json |
| dataset correctness artifacts | benchmarks/results/controlled-ema-variant-scale-side-by-side-v1/2026-07-26T22-35-28-384Z/correctness-artifacts/scale-ema-50.2signals.artifact.json | benchmarks/results/controlled-ema-variant-scale-side-by-side-v1/2026-07-26T22-35-28-384Z/correctness-artifacts/scale-ema-50.freqtrade.artifact.json |
| first strategy artifact | benchmarks/results/controlled-ema-variant-scale-side-by-side-v1/2026-07-26T22-35-28-384Z/correctness-artifacts/scale-ema-50.2signals.artifact.json | benchmarks/results/controlled-ema-variant-scale-side-by-side-v1/2026-07-26T22-35-28-384Z/correctness-artifacts/scale-ema-50.freqtrade.artifact.json |
| run timestamp | 2026-07-26T22:27:19.288Z | 2026-07-26T22:35:13.475Z |
docs/benchmarks/results/controlled-ema-freqtrade-boundaries-v1.mdFreqtrade boundary referencesAudit and implementation of the closest natural Freqtrade strategy-list boundary plus separate-process CLI reference.What to look for: Phase timings and the reason the Freqtrade rows are workflow references, not direct algorithm-only measurements.Open
controlled-ema-freqtrade-boundaries-v1
Status: neutral audit and boundary report for controlled Freqtrade EMA variant scale execution.
Audit Result
| Area | Source | Interface | API status | Finding |
|---|---|---|---|---|
| CLI backtesting | /Users/aleksanderfroncz/Development/freqtrade/freqtrade-bot/freqtrade/commands/optimize_commands.py | start_backtesting(args) | public CLI entrypoint | Creates one Backtesting(config) object and calls backtesting.start(). |
| Backtesting class | /Users/aleksanderfroncz/Development/freqtrade/freqtrade-bot/freqtrade/optimize/backtesting.py | Backtesting, start(), backtest_one_strategy() | internal implementation | Supports programmatic execution, but it is not a documented stable library API. |
| Strategy-list batch | /Users/aleksanderfroncz/Development/freqtrade/freqtrade-bot/docs/commands/backtesting.md | --strategy-list STRATEGY_LIST ... | public CLI option | Natural single-process batch boundary for multiple strategies. |
| freqUI/API backtest | /Users/aleksanderfroncz/Development/freqtrade/freqtrade-bot/freqtrade/rpc/api_server/api_backtest.py | POST /backtest, __run_backtest_bg() | public authenticated endpoint, private background function | Reuses ApiBG.bt["bt"] and cached loaded data when timeframe/timerange are unchanged. |
| Hyperopt | /Users/aleksanderfroncz/Development/freqtrade/freqtrade-bot/docs/hyperopt.md | freqtrade hyperopt | public CLI workflow | Runs repeated backtests for optimization, often with worker processes and different parameter semantics; not used for this controlled same-strategy comparison. |
Decision: implement the nearest natural supported boundary through freqtrade backtesting --strategy-list, not a custom persistent server. The benchmark still uses a benchmark-only wrapper only to inject local fixture markets and record timings around existing Freqtrade functions.
Measurement Boundaries
- CLI separate-process boundary: one local Python/Freqtrade process per variant; existing reference remains unchanged.
- Persistent/single-process boundary: one local Python/Freqtrade process per sample; all 10 generated strategy classes run through one
backtesting.start()call via--strategy-list. - Both boundaries use the same frozen dataset, EMA fast
50..59, EMA slow200, fee, stake and risk config. - Both boundaries disable Freqtrade result cache with
--cache none; OS page cache is still outside benchmark control.
Side-by-side Boundary Matrix
| Metric | 2Signals in-process workflow | Freqtrade persistent/single-process workflow | Freqtrade separate-process CLI workflow |
|---|---|---|---|
| Run type | full | full | full |
| Measured samples | 10 | 10 | 10 |
| Local child processes | not applicable | 10 | 100 |
| Total workflow | n=10, median=20.25 ms, mean=20.43 ms, min=19.7 ms, max=21.42 ms, p95=21.42 ms, stddev=0.53 ms | n=10, median=5.51 s, mean=5.57 s, min=5.46 s, max=5.84 s, p95=5.84 s, stddev=114.22 ms | n=10, median=35.52 s, mean=35.44 s, min=34.82 s, max=35.91 s, p95=35.91 s, stddev=380.08 ms |
| Per-variant execution marker | n=100, median=1.4 ms, mean=1.53 ms, min=1.33 ms, max=2.21 ms, p95=2.08 ms, stddev=0.25 ms | n=100, median=35.57 ms, mean=43.2 ms, min=33.08 ms, max=126.92 ms, p95=87.69 ms, stddev=18.89 ms | n=100, median=287.39 ms, mean=292.24 ms, min=273.28 ms, max=355.57 ms, p95=330.99 ms, stddev=15.63 ms |
| Child process duration | not applicable | n=10, median=5.38 s, mean=5.44 s, min=5.3 s, max=5.71 s, p95=5.71 s, stddev=116.79 ms | n=10, median=34.33 s, mean=34.24 s, min=33.61 s, max=34.71 s, p95=34.71 s, stddev=372.18 ms |
| Python process startup | not applicable | n=10, median=400.37 ms, mean=406.7 ms, min=396.89 ms, max=444.04 ms, p95=444.04 ms, stddev=13.88 ms | n=10, median=3.99 s, mean=3.99 s, min=3.9 s, max=4.04 s, p95=4.04 s, stddev=40.64 ms |
| Import/module initialization | not applicable | n=10, median=2.66 s, mean=2.67 s, min=2.61 s, max=2.79 s, p95=2.79 s, stddev=48.14 ms | n=10, median=26.24 s, mean=26.17 s, min=25.65 s, max=26.56 s, p95=26.56 s, stddev=325.17 ms |
| Config loading | not applicable | n=10, median=44.65 ms, mean=44.67 ms, min=43.18 ms, max=45.53 ms, p95=45.53 ms, stddev=0.69 ms | n=10, median=436.67 ms, mean=436.88 ms, min=429.98 ms, max=441.47 ms, p95=441.47 ms, stddev=3.74 ms |
| Strategy loading | not applicable | n=10, median=270.36 ms, mean=279.17 ms, min=265.61 ms, max=327.62 ms, p95=327.62 ms, stddev=17.82 ms | n=10, median=414.61 ms, mean=414.92 ms, min=411.48 ms, max=421.37 ms, p95=421.37 ms, stddev=2.7 ms |
| Data loading | not applicable | n=10, median=52.25 ms, mean=52.15 ms, min=49.68 ms, max=55.78 ms, p95=55.78 ms, stddev=1.63 ms | n=10, median=523.57 ms, mean=545.58 ms, min=513.32 ms, max=592.9 ms, p95=592.9 ms, stddev=29.09 ms |
Freqtrade backtesting.start() | not applicable | n=10, median=1.94 s, mean=1.98 s, min=1.92 s, max=2.16 s, p95=2.16 s, stddev=75.46 ms | n=10, median=2.91 s, mean=2.92 s, min=2.86 s, max=3.08 s, p95=3.08 s, stddev=60.03 ms |
| Serialization/export | not applicable | n=10, median=25.38 ms, mean=25.66 ms, min=23.81 ms, max=28.59 ms, p95=28.59 ms, stddev=1.55 ms | n=10, median=204.65 ms, mean=204.79 ms, min=199.03 ms, max=210.25 ms, p95=210.25 ms, stddev=3.16 ms |
| Node result parsing | not applicable | n=10, median=122.23 ms, mean=127.61 ms, min=118.64 ms, max=168.88 ms, p95=168.88 ms, stddev=14.02 ms | n=10, median=1.17 s, mean=1.17 s, min=1.14 s, max=1.22 s, p95=1.22 s, stddev=20.89 ms |
| Correctness | passed | passed | passed |
Phase Timings
| Boundary | Run type | Samples | Processes | Total workflow | Total child process | Process startup | Imports | Config | Strategy loading | Backtesting object init | Data loading | backtesting.start() | Per-variant execution | Serialization/export | Node result parsing | Correctness |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Freqtrade separate-process CLI workflow | full | 10 | 100 | n=10, median=35.52 s, mean=35.44 s, min=34.82 s, max=35.91 s, p95=35.91 s, stddev=380.08 ms | n=10, median=34.33 s, mean=34.24 s, min=33.61 s, max=34.71 s, p95=34.71 s, stddev=372.18 ms | n=10, median=3.99 s, mean=3.99 s, min=3.9 s, max=4.04 s, p95=4.04 s, stddev=40.64 ms | n=10, median=26.24 s, mean=26.17 s, min=25.65 s, max=26.56 s, p95=26.56 s, stddev=325.17 ms | n=10, median=436.67 ms, mean=436.88 ms, min=429.98 ms, max=441.47 ms, p95=441.47 ms, stddev=3.74 ms | n=10, median=414.61 ms, mean=414.92 ms, min=411.48 ms, max=421.37 ms, p95=421.37 ms, stddev=2.7 ms | n=10, median=494.99 ms, mean=495.47 ms, min=491.73 ms, max=503.42 ms, p95=503.42 ms, stddev=3.26 ms | n=10, median=523.57 ms, mean=545.58 ms, min=513.32 ms, max=592.9 ms, p95=592.9 ms, stddev=29.09 ms | n=10, median=2.91 s, mean=2.92 s, min=2.86 s, max=3.08 s, p95=3.08 s, stddev=60.03 ms | n=100, median=287.39 ms, mean=292.24 ms, min=273.28 ms, max=355.57 ms, p95=330.99 ms, stddev=15.63 ms | n=10, median=204.65 ms, mean=204.79 ms, min=199.03 ms, max=210.25 ms, p95=210.25 ms, stddev=3.16 ms | n=10, median=1.17 s, mean=1.17 s, min=1.14 s, max=1.22 s, p95=1.22 s, stddev=20.89 ms | passed |
| Freqtrade single-process strategy-list workflow | full | 10 | 10 | n=10, median=5.51 s, mean=5.57 s, min=5.46 s, max=5.84 s, p95=5.84 s, stddev=114.22 ms | n=10, median=5.38 s, mean=5.44 s, min=5.3 s, max=5.71 s, p95=5.71 s, stddev=116.79 ms | n=10, median=400.37 ms, mean=406.7 ms, min=396.89 ms, max=444.04 ms, p95=444.04 ms, stddev=13.88 ms | n=10, median=2.66 s, mean=2.67 s, min=2.61 s, max=2.79 s, p95=2.79 s, stddev=48.14 ms | n=10, median=44.65 ms, mean=44.67 ms, min=43.18 ms, max=45.53 ms, p95=45.53 ms, stddev=0.69 ms | n=10, median=270.36 ms, mean=279.17 ms, min=265.61 ms, max=327.62 ms, p95=327.62 ms, stddev=17.82 ms | n=10, median=307.97 ms, mean=318.02 ms, min=303.57 ms, max=370.88 ms, p95=370.88 ms, stddev=19.37 ms | n=10, median=52.25 ms, mean=52.15 ms, min=49.68 ms, max=55.78 ms, p95=55.78 ms, stddev=1.63 ms | n=10, median=1.94 s, mean=1.98 s, min=1.92 s, max=2.16 s, p95=2.16 s, stddev=75.46 ms | n=100, median=35.57 ms, mean=43.2 ms, min=33.08 ms, max=126.92 ms, p95=87.69 ms, stddev=18.89 ms | n=10, median=25.38 ms, mean=25.66 ms, min=23.81 ms, max=28.59 ms, p95=28.59 ms, stddev=1.55 ms | n=10, median=122.23 ms, mean=127.61 ms, min=118.64 ms, max=168.88 ms, p95=168.88 ms, stddev=14.02 ms | passed |
Correctness
- Reused scale correctness report:
benchmarks/results/controlled-ema-variant-scale-side-by-side-v1/2026-07-26T22-35-28-384Z/controlled-ema-variant-scale-side-by-side-v1.correctness.json. - Persistent correctness status:
passed. - Persistent mismatch count:
0in the first sample; all samples require the same gate.
Boundary Ratio Metrics
| Ratio | Numerator boundary | Denominator boundary | Value | Note |
|---|---|---|---|---|
| freqtradePersistentWorkflowTo2SignalsInProcessWorkflowRatio | single-process strategy-list total workflow median | 2Signals in-process total workflow median | 271.85 | boundary ratio only; not an engine equivalence claim |
| freqtradeCliWorkflowToFreqtradePersistentWorkflowRatio | separate-process CLI total workflow median | single-process strategy-list total workflow median | 6.45 | boundary ratio only; not an engine equivalence claim |
Artifacts
- 2Signals result JSON:
benchmarks/results/controlled-ema-variant-scale-btcusdt-5m-v1/2026-07-26T22-27-15-168Z/2026-07-26T22-27-15-168Z.controlled-ema-variant-scale-btcusdt-5m-v1.json - Persistent result JSON:
benchmarks/results/controlled-ema-freqtrade-persistent-variant-scale-btcusdt-5m-v1/2026-07-26T22-22-44-618Z/2026-07-26T22-22-44-618Z.controlled-ema-freqtrade-persistent-variant-scale-btcusdt-5m-v1.json - CLI result JSON:
benchmarks/results/controlled-ema-freqtrade-variant-scale-btcusdt-5m-v1/2026-07-26T22-27-23-697Z/2026-07-26T22-27-23-697Z.controlled-ema-freqtrade-variant-scale-btcusdt-5m-v1.json - Persistent docs report:
docs/benchmarks/results/controlled-ema-freqtrade-persistent-variant-scale-btcusdt-5m-v1.md
Limitations
Backtestingis an internal Freqtrade implementation class even though--strategy-listis a public CLI workflow.- The benchmark wrapper patches Freqtrade functions only to record timings and fixture markets; it does not replace backtesting logic.
backtesting.start()includes multiple internal Freqtrade phases and is not a pure engine timer.- The controlled EMA fixture is small and synthetic.
- Results are not marketing claims and should not be generalized to hyperopt, live trading, or larger datasets without separate runs.
Neutral Conclusions
- Freqtrade does provide a natural single-process boundary for this comparison through public
--strategy-listbacktesting. - The persistent boundary reduces repeated process and initialization work by construction, but remains a Freqtrade workflow boundary, not a pure algorithm-only engine benchmark.
- The separate-process CLI boundary remains useful as the user-facing invocation reference.
docs/benchmarks/results/controlled-complex-current-engine-export-v1.mdComplex current-engine exportCurrent-engine complex futures export compared with the frozen Freqtrade reference.What to look for: Dataset scope, indicator comparisons, mask comparisons, trade comparisons and mismatch count.Open
Controlled Complex Current-Engine Export v1
Status: passed. This report creates a fresh current-engine Builder-equivalent 2Signals export from frozen local data and compares it to the fresh Freqtrade frozen boundary reference.
This is a controlled engineering artifact, not a full authenticated /builder UI export. It exists to replace the historical browser-backtester-v18 target with current-engine 2Signals output checked against the fresh per-candle Freqtrade boundary.
Scope
| Field | Value |
|---|---|
| boundary id | controlled-complex-current-engine-export-v1 |
| generated at | 2026-07-27T04:08:40.898Z |
| equivalence json | benchmarks/results/equivalence/2026-07-27T04-08-26-879Z.builder-complex-current-engine-export.equivalence.json |
| current export artifact | .benchmark-artifacts/controlled-complex-current-engine-export-v1/2026-07-27T04-08-26-879Z/2026-07-27T04-08-26-879Z.builder-complex-current-engine-export.json |
| current export SHA-256 | 66155b347ae8ec33b5e59356288e7d14c19995c5f4d2ee3273f086bb7d1e63fd |
| measured commit SHA | b261ffb7469f6a95c3c6611b9340800ea988caab |
| dataset status | passed |
| final status | passed |
| marketDataHash | 8187f41a5104f2dbae03adcd34e13611bfbff17ec17bf9948f8fa2ef36cf79c1 |
Boundary
| System | Boundary |
|---|---|
| 2Signals | controlled current-engine Builder-equivalent export from fresh BacktestService on frozen OHLCV/funding artifacts |
| Freqtrade | fresh frozen boundary reference: benchmarks/results/equivalence/2026-07-27T03-50-24-007Z.builder-complex-freqtrade-frozen-boundary.equivalence.json |
Trade Correctness
| Comparison | Level | Summary |
|---|---|---|
| Current 2Signals export vs fresh Freqtrade boundary | semantically_equivalent | 123 compared trades, 0 missing in source, 0 missing in target, 0 mismatched fields |
Per-Candle Correctness
Status: passed. Dataset correctness is checked once for the unique frozen dataset hash; strategy correctness compares indicators, masks, signal timestamps, trades and numeric trade metrics.
| Metric | Value |
|---|---|
| unique datasets checked | 1 |
| dataset status | passed |
| dataset candle count | 181447 |
| OHLCV values compared | 907235 |
| strategy status | passed |
| indicator values compared | 2903152 |
| mask values compared | 725788 |
| signal timestamps compared | 19937 |
| trades compared | 123 |
| trade metric fields compared | 1722 |
| mismatch count | 0 |
Per-Pair Artifact Summary
| Pair | Status | Candles | Indicator values | Mask values | Signal timestamps | Trades | Mismatches |
|---|---|---|---|---|---|---|---|
| 1000SATS/USDT:USDT | passed | 25921 | 414736 | 103684 | 2737 | 15 | 0 |
| NEIRO/USDT:USDT | passed | 25921 | 414736 | 103684 | 2733 | 12 | 0 |
| PENGU/USDT:USDT | passed | 25921 | 414736 | 103684 | 2831 | 30 | 0 |
| PEOPLE/USDT:USDT | passed | 25921 | 414736 | 103684 | 2918 | 18 | 0 |
| RENDER/USDT:USDT | passed | 25921 | 414736 | 103684 | 2683 | 14 | 0 |
| STX/USDT:USDT | passed | 25921 | 414736 | 103684 | 3182 | 19 | 0 |
| XVG/USDT:USDT | passed | 25921 | 414736 | 103684 | 2853 | 15 | 0 |
Timing Boundary
| Phase | Duration |
|---|---|
| 2Signals BacktestService | 2.47 s |
| Full current export workflow | 14.07 s |
Artifacts
| Artifact | Path or Value |
|---|---|
| current export JSON | .benchmark-artifacts/controlled-complex-current-engine-export-v1/2026-07-27T04-08-26-879Z/2026-07-27T04-08-26-879Z.builder-complex-current-engine-export.json |
| 2Signals per-candle paths | 7 |
| Freqtrade reference per-candle paths | 7 |
| Freqtrade reference boundary JSON | benchmarks/results/equivalence/2026-07-27T03-50-24-007Z.builder-complex-freqtrade-frozen-boundary.equivalence.json |
Limitations
- This step does not execute Freqtrade. It uses the latest fresh Freqtrade frozen boundary JSON as the reference.
- This is a Builder-equivalent current-engine export, not a full auth, route and browser UI export.
- Timing is reported only for the current 2Signals export workflow and should not be compared to Freqtrade process timings from this document alone.
docs/benchmarks/results/controlled-complex-freqtrade-frozen-boundary-v1.mdComplex Freqtrade frozen boundaryFresh Freqtrade frozen boundary for the complex futures strategy. Useful for phase timings and artifact scope.What to look for: Freqtrade phase timings, artifact export boundary and controlled local-data assumptions.Open
Controlled Complex Freqtrade Frozen Boundary v1
Status: passed. This report reruns Freqtrade from the local frozen complex futures data and compares it to a fresh 2Signals run on the same market-data hash.
This is a controlled engineering artifact, not a marketing comparison. It separates the fresh Freqtrade boundary from the older exported Freqtrade target stored in the Builder diagnostics fixture.
Scope
| Field | Value |
|---|---|
| boundary id | controlled-complex-freqtrade-frozen-boundary-v1 |
| generated at | 2026-07-27T03:51:44.193Z |
| equivalence json | benchmarks/results/equivalence/2026-07-27T03-50-24-007Z.builder-complex-freqtrade-frozen-boundary.equivalence.json |
| measured commit SHA | b261ffb7469f6a95c3c6611b9340800ea988caab |
| dataset status | passed |
| final status | passed |
| marketDataHash | 8187f41a5104f2dbae03adcd34e13611bfbff17ec17bf9948f8fa2ef36cf79c1 |
| fundingDatasetHash | 54d5e30b8af6ce48f5c6e019b8a726b988828d0333c429a839e406b6afbc2130 |
Boundaries
| Engine | Boundary |
|---|---|
| 2Signals | fresh 2Signals BacktestService run from frozen local OHLCV/funding artifacts |
| Freqtrade | fresh Freqtrade Backtesting run from the same local Freqtrade feather OHLCV/funding/mark artifacts and the same generated strategy snapshot |
Dataset
| Metric | Value |
|---|---|
| candles | 181447 |
| funding rows | 2952 |
| 2Signals trades | 123 |
| fresh Freqtrade trades | 123 |
Correctness
| Comparison | Level | Summary |
|---|---|---|
| 2Signals fresh vs Freqtrade fresh | semantically_equivalent | 123 compared trades, 0 missing in source, 0 missing in target, 0 mismatched fields |
| Freqtrade fresh vs exported Freqtrade target | mismatched | 123 compared trades, 0 missing in source, 0 missing in target, 15 mismatched fields |
Per-Candle Correctness
Status: passed. Dataset correctness is checked once for the unique frozen dataset hash; strategy correctness compares indicators, masks, signal timestamps, trades and numeric trade metrics.
| Metric | Value |
|---|---|
| unique datasets checked | 1 |
| dataset status | passed |
| dataset candle count | 181447 |
| OHLCV values compared | 907235 |
| strategy status | passed |
| indicator values compared | 2903152 |
| mask values compared | 725788 |
| signal timestamps compared | 19937 |
| trades compared | 123 |
| trade metric fields compared | 1722 |
| mismatch count | 0 |
Per-Pair Artifact Summary
| Pair | Status | Candles | Indicator values | Mask values | Signal timestamps | Trades | Mismatches |
|---|---|---|---|---|---|---|---|
| 1000SATS/USDT:USDT | passed | 25921 | 414736 | 103684 | 2737 | 15 | 0 |
| NEIRO/USDT:USDT | passed | 25921 | 414736 | 103684 | 2733 | 12 | 0 |
| PENGU/USDT:USDT | passed | 25921 | 414736 | 103684 | 2831 | 30 | 0 |
| PEOPLE/USDT:USDT | passed | 25921 | 414736 | 103684 | 2918 | 18 | 0 |
| RENDER/USDT:USDT | passed | 25921 | 414736 | 103684 | 2683 | 14 | 0 |
| STX/USDT:USDT | passed | 25921 | 414736 | 103684 | 3182 | 19 | 0 |
| XVG/USDT:USDT | passed | 25921 | 414736 | 103684 | 2853 | 15 | 0 |
Per-Candle Artifact Paths
| System | Path count | First path |
|---|---|---|
| 2Signals | 7 | .benchmark-artifacts/controlled-complex-freqtrade-frozen-boundary-v1/2026-07-27T03-50-24-007Z/per-candle-artifacts/2signals/STX_USDT_USDT.2signals.per-candle.json |
| Freqtrade | 7 | .benchmark-artifacts/controlled-complex-freqtrade-frozen-boundary-v1/2026-07-27T03-50-24-007Z/per-candle-artifacts/freqtrade-normalized/1000SATS_USDT_USDT.freqtrade.per-candle.json |
Timing Boundary
| Phase | Duration |
|---|---|
| 2Signals BacktestService | 2.45 s |
| Freqtrade child process duration | 23.82 s |
| Freqtrade Backtesting.start() | 20.32 s |
| Freqtrade Backtesting initialization | 170.51 ms |
| Freqtrade result parsing | 119.31 ms |
| Freqtrade per-candle artifact export | 39.97 s (outside measured backtest boundary) |
| Freqtrade workflow without artifacts | 25.26 s |
| Freqtrade workflow with artifact export | 65.23 s |
| Full benchmark test wall time | 80.19 s |
Freqtrade Artifacts
| Artifact | Path or Value |
|---|---|
| version | Operating System: macOS-27.0-x86_64-i386-64bit<br>Python Version: Python 3.12.8<br>CCXT Version: 4.5.42<br><br>Freqtrade Version: freqtrade 2026.3-dev-efabf7f4f |
| git SHA | efabf7f4f75535f87417ddddfd99c1b3019b878e |
| strategy | .benchmark-artifacts/controlled-complex-freqtrade-frozen-boundary-v1/2026-07-27T03-50-24-007Z/user_data/strategies/Backtest_cmru0eefi00169k1qgphqz2vl.py |
| strategy SHA-256 | b5a3859e77cf0efdff63f1a9789fecfbc98c42177cf21392e9812dcfd9dda18a |
| config | .benchmark-artifacts/controlled-complex-freqtrade-frozen-boundary-v1/2026-07-27T03-50-24-007Z/config.json |
| config SHA-256 | fe172f7d7b2a0e5710094cae638177534c5bff9e61ddbe221b190446261139f7 |
| result zip | .benchmark-artifacts/controlled-complex-freqtrade-frozen-boundary-v1/2026-07-27T03-50-24-007Z/user_data/backtest_results/backtest-result-2026-07-27_05-50-55.zip |
| stdout | .benchmark-artifacts/controlled-complex-freqtrade-frozen-boundary-v1/2026-07-27T03-50-24-007Z/freqtrade.stdout.log |
| stderr | .benchmark-artifacts/controlled-complex-freqtrade-frozen-boundary-v1/2026-07-27T03-50-24-007Z/freqtrade.stderr.log |
Funding Diagnostics: Fresh 2Signals vs Fresh Freqtrade
No funding/profit mismatches were detected in the fresh comparison.
Funding Diagnostics: Fresh Freqtrade vs Exported Target
| Trade | Pair | Open | Close | Rows | Formula fee | Fresh Freqtrade fee | Exported target fee | Delta |
|---|---|---|---|---|---|---|---|---|
| RENDER/USDT:USDT#122 | RENDER/USDT:USDT | 2026-06-27T01:50:00.000Z | 2026-07-21T00:00:00.000Z | 141 | -0.29646553 | -0.29646553 | -0.29814793 | 0.0016824 |
| 1000SATS/USDT:USDT#120 | 1000SATS/USDT:USDT | 2026-07-03T22:45:00.000Z | 2026-07-21T00:00:00.000Z | 100 | -0.58864158 | -0.58864158 | -0.6027719 | 0.01413032 |
| PENGU/USDT:USDT#119 | PENGU/USDT:USDT | 2026-07-10T04:35:00.000Z | 2026-07-21T00:00:00.000Z | 62 | 0.15031215 | 0.15031215 | 0.13547167 | 0.01484049 |
| NEIRO/USDT:USDT#121 | NEIRO/USDT:USDT | 2026-07-14T16:05:00.000Z | 2026-07-21T00:00:00.000Z | 35 | -0.14320288 | -0.14320288 | -0.15565357 | 0.0124507 |
| PEOPLE/USDT:USDT#118 | PEOPLE/USDT:USDT | 2026-07-15T21:10:00.000Z | 2026-07-21T00:00:00.000Z | 13 | -0.11328614 | -0.11328614 | -0.14003348 | 0.02674733 |
Limitations
- The Freqtrade boundary is still a local Python process with Freqtrade initialization, strategy loading and result serialization included in the reported child-process timing.
- The report uses local Freqtrade feather data; it does not fetch from Binance during measurement.
- The funding formula section is diagnostic only. Correctness status is based on the fresh trade comparison, not on replacing engine output with the diagnostic formula.
docs/benchmarks/results/benchmark-findings-v1.mdBenchmark findingsHigher-level benchmark findings and limitations. Use this as a sanity check before making claims.What to look for: The methodology caveats, safe interpretations and next benchmark gaps.Open
Benchmark Findings V1
Status: final methodological audit for
controlled-ema-2signals-variant-scale-btcusdt-5m-v2.
This document freezes the publication-safe interpretation of the current benchmark artifacts. It does not add new benchmark data, does not change raw results, and does not change runner, scenario, cache or engine behavior.
Evidence Sources
- Scale v2 report:
docs/benchmarks/results/controlled-ema-2signals-variant-scale-btcusdt-5m-v2.md - Scale v2 raw result:
benchmarks/results/controlled-ema-2signals-variant-scale-btcusdt-5m-v2/2026-07-26T11-09-07-054Z/2026-07-26T11-09-07-054Z.controlled-ema-2signals-variant-scale-btcusdt-5m-v2.json - Scale v2 correctness report:
benchmarks/results/controlled-ema-2signals-variant-scale-btcusdt-5m-v2/2026-07-26T11-09-07-054Z/controlled-ema-2signals-variant-scale-btcusdt-5m-v2.correctness.json - Dataset metadata:
benchmarks/results/controlled-ema-2signals-variant-scale-btcusdt-5m-v2/2026-07-26T11-09-07-054Z/dataset.metadata.json - Strategy metadata:
benchmarks/results/controlled-ema-2signals-variant-scale-btcusdt-5m-v2/2026-07-26T11-09-07-054Z/strategy.metadata.json - Benchmark implementation and report renderer:
benchmarks/comparison/controlled-ema-btcusdt.bench.ts - Production render matrix:
benchmarks/results/builder-production-like-production/2026-07-23T15-05-03-641Z/benchmark-matrix.md
Tested System Boundary
The scale v2 timing boundary is
2signals-node-service-sequential-variant-scale-v2.
It includes:
- local frozen candles already available in process;
- per-variant
BacktestService.runBacktest; - indicator computation and cache lookup through the benchmark cache mock;
- rule and signal evaluation;
- trade simulation;
- result preparation performed by the service path;
- benchmark sequence orchestration and diagnostics around the sequential sweep.
It excludes:
- browser UI, chart rendering and React rendering;
- IndexedDB and production browser cache layers;
- exchange, Supabase, Apollo and network requests;
- Freqtrade execution;
- correctness artifact generation and export;
- visualization and whitepaper/pitch-deck rendering.
totalDurationMs for a scale sweep starts immediately before the sequential
variant loop and ends after every variant result is available. It includes
per-variant wrapper overhead and diagnostics around the loop. The per-variant
median comes from each internal runTwoSignalsEngine sample's
totalDurationMs; that inner metric starts after variant-specific signal/config
construction and ends after BacktestService.runBacktest.
Publication interpretation: this is a Node/service workflow benchmark, not a full product latency benchmark and not a pure mathematical indicator benchmark.
Dataset And Strategy Scope
Dataset:
| Field | Value |
|---|---|
| Exchange | binance |
| Pair | BTC/USDT |
| Timeframe | 5m |
| Candle count | 620 |
| Start | 2023-12-31T07:20:00.000Z |
| Backtest start | 2024-01-01T00:00:00.000Z |
| End | 2024-01-02T10:55:00.000Z |
| Timezone | UTC |
| Source version | synthetic-v3 |
| Dataset hash | 499155587500a60de08fe8edd922bcd432d5ce36e80b106814898955264ae5fe |
Strategy variant space:
| Dimension | Values |
|---|---|
| Version | ema-grid-v2 |
| Fast EMA | 20 through 69 |
| Slow EMA | 200, 180, 220, 160, 240 |
| Operators | crossed_above/crossed_below, crossed_above/crossed_above, crossed_below/crossed_above, crossed_below/crossed_below |
| Variant order | slow period, operator pair, fast period |
The v2 grid uses slow EMA combinations around EMA(200) because 1000 meaningful unique variants cannot be produced from fast EMA 20-69 alone on the 620-candle fixture.
Correctness Summary
Correctness is executed before timing and outside the measured benchmark phase.
Dataset correctness is now reported separately from strategy correctness. Dataset correctness is executed once for the unique dataset hash and confirms metadata, timestamp boundaries, an OHLCV checksum and a dedicated fixture-to-adapter OHLCV comparison.
| Unique datasets checked | Dataset status | Dataset candle count | Adapter candle comparisons | OHLCV value comparisons | OHLCV checksum |
|---|---|---|---|---|---|
| 1 | passed | 620 | 620 | 3100 | 5f0a3cdc7c19d03ece613d36f94877c4e39f26e532d94c97cc9f989c28b86867 |
Strategy correctness compares variant-dependent outputs only: EMA series, entry/exit masks, signal timestamps, trades, fees, P/L and result hashes. It does not recount the same OHLCV candles for every variant.
| Variants | Result-hash validation | Strategy validation | Variants checked | Variants passed | Sampled strategy variants | Indicator values compared | Mask values compared | Signals compared | Trades compared | Result metrics compared | Mismatches |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 10 | full for every variant | full for every variant | 10 | 10 | 10 | 12400 | 12400 | 20 | 10 | 10 | 0 |
| 100 | full for every variant | deterministic sampled | 100 | 100 | 10 | 12400 | 12400 | 20 | 6 | 100 | 0 |
| 500 | full for every variant | deterministic sampled | 500 | 500 | 20 | 24800 | 24800 | 40 | 10 | 500 | 0 |
| 1000 | full for every variant | deterministic sampled | 1000 | 1000 | 30 | 37200 | 37200 | 60 | 16 | 1000 | 0 |
Aggregate correctness status: passed for 1 unique dataset, 1610 checked strategy variants, 86800 indicator values, 86800 mask values, 140 signal timestamps, 42 trade comparisons, 1610 result-metric comparisons and 0 mismatches.
Correctness confirms:
- deterministic internal equivalence between baseline and candidate 2Signals artifacts for the checked scope;
- dataset correctness for the unique dataset hash exactly once;
- full result-hash stability for every variant in 10/100/500/1000 levels;
- full strategy equality for the 10-variant level;
- sampled strategy equality for the 100/500/1000 levels.
Correctness does not confirm:
- full strategy-artifact validation for every 100/500/1000 variant;
- equivalence to Freqtrade for 100/500/1000 scale levels;
- browser rendering correctness;
- production IndexedDB/cache correctness;
- behavior on real exchange data beyond this frozen fixture.
Production Render Findings
The production render benchmark is separate from scale v2. Its latest
production-like run is builder-production-like-render-v1, executed through the
repeatable production script in:
benchmarks/results/builder-production-like-production/2026-07-23T15-05-03-641Z/benchmark-matrix.md
Boundary:
- production build via
next buildandnext start; - benchmark route enabled only with
ENABLE_PRODUCTION_BENCHMARK_ROUTES=true; - real
BacktestDashboardChartComponent; - real
BacktestChartPrimaryandSyncedChart; - real
BacktestResultsMetrics; - real
BacktestResultsTradesandBacktestResultsTradesTable; - minimal provider shell and frozen fixtures;
- no full auth flow, Apollo subscriptions, exchange fetch or Supabase fetch.
Production-like measured results:
| Scenario | Samples | Presentation median | Fully-rendered median | Fully p95 | Correctness |
|---|---|---|---|---|---|
cold-initial-run | 10 | 29 ms | 249.3 ms | 257.6 ms | passed |
warm-identical-rerun | 10 | 9.5 ms | 233.9 ms | 242.2 ms | passed |
operator-change | 10 | 18.2 ms | 233.6 ms | 242.6 ms | changed |
indicator-parameter-change | 10 | 18.4 ms | 240.9 ms | 243 ms | changed |
pair-return-open-a | 10 | 25.6 ms | 249.9 ms | 250.4 ms | passed |
pair-return-open-b | 10 | 17.4 ms | 234.6 ms | 249.3 ms | changed |
pair-return-return-a | 10 | 7.2 ms | 233.2 ms | 241.9 ms | passed |
Publication interpretation: these are production-like fully-rendered UI
latencies for the benchmark harness, not full authenticated /builder user-flow
latencies.
2Signals Variant Scaling Findings
Scale v2 measured levels use different measured run counts:
- 10 variants: 3 warm-ups, 10 measured runs;
- 100 variants: 3 warm-ups, 10 measured runs;
- 500 variants: 3 warm-ups, 5 measured runs;
- 1000 variants: 3 warm-ups, 3 measured runs.
The cold full-sweep scale curve:
| Variants | Measured runs | Cold median | Cold median / variant | Per-variant engine median | Cold p95 | Cold stddev | Warm median | Warm median / variant |
|---|---|---|---|---|---|---|---|---|
| 10 | 10 | 16.85 ms | 1.69 ms | 1.52 ms | 17.27 ms | 0.30 ms | 15.38 ms | 1.54 ms |
| 100 | 10 | 153.30 ms | 1.53 ms | 1.40 ms | 159.57 ms | 2.35 ms | 147.22 ms | 1.47 ms |
| 500 | 5 | 768.75 ms | 1.54 ms | 1.37 ms | 801.70 ms | 14.41 ms | 777.26 ms | 1.55 ms |
| 1000 | 3 | 1582.08 ms | 1.58 ms | 1.37 ms | 1719.45 ms | 75.54 ms | 1744.60 ms | 1.74 ms |
Growth factors:
| From | To | Variant growth | Cold time growth | Deviation from ideal linear | Interpretation |
|---|---|---|---|---|---|
| 10 | 100 | 10.0x | 9.10x | -9.0% | below ideal linear in this range |
| 100 | 500 | 5.0x | 5.01x | +0.3% | approximately linear |
| 500 | 1000 | 2.0x | 2.06x | +3.0% | slightly above ideal linear here |
Publication interpretation: the data supports "approximately linear in the tested range" for the stated Node/service cold full-sweep boundary. It does not support the broader phrase "linear scalability" without the tested-range and boundary qualifiers.
Cold Vs Warm Interpretation
Definitions:
- Cold sweep: cache is cleared before the sweep starts. This does not mean there is no reuse inside the sweep. Related variants can create cache entries that later variants reuse within the same cold sweep.
- Warm identical sweep: the identical variant space is run again after the cold sweep. Measured cache reads hit, but the workflow still executes per-variant orchestration, rule/signal work, trade simulation, metrics shaping, diagnostics and result object traversal.
Why warm is not faster for 500 and 1000:
| Level | Scenario | Total median | Cache lookup | Indicators | Rules/signals | Simulation | Metrics | Cache hit rate | Status |
|---|---|---|---|---|---|---|---|---|---|
| 500 | cold | 768.75 ms | 2.42 ms | 49.22 ms | 69.22 ms | 140.89 ms | 7.02 ms | 73% | confirmed |
| 500 | warm | 777.26 ms | 2.50 ms | 43.51 ms | 58.68 ms | 143.28 ms | 3.79 ms | 100% | confirmed |
| 1000 | cold | 1582.08 ms | 4.71 ms | 90.47 ms | 135.16 ms | 277.15 ms | 11.21 ms | 76% | confirmed |
| 1000 | warm | 1744.60 ms | 5.25 ms | 100.18 ms | 116.17 ms | 293.81 ms | 7.80 ms | 100% | confirmed |
Confirmed:
- warm reads hit the benchmark cache for the measured cache reads;
- rule/signal handling, simulation and result preparation still execute for every variant;
- cold sweeps have nonzero cache hit rates because reuse occurs inside the sweep;
- 500 and 1000 warm runs have higher total median than cold in this raw run.
Supported inference:
- the larger warm totals are consistent with measurement noise, JIT state, garbage collection behavior, memory pressure, larger cache object graphs and diagnostic overhead;
- 1000 warm has higher variance (
187.12 msstddev) than 1000 cold (75.54 msstddev), so one should not infer that warm execution is inherently slower from this single local run.
Unknown:
- isolated diagnostics overhead;
- isolated memory-measurement overhead;
- isolated cleanup overhead per measured sweep;
- whether an
--expose-gcrun with a stable memory baseline would change the cold/warm ordering.
Frozen Freqtrade Boundary References
The current frozen Freqtrade references are 10-variant boundary references only:
| Boundary | Variant count | Total workflow median | Interpretation |
|---|---|---|---|
Freqtrade --strategy-list | 10 | 5.38 s | one CLI workflow for the 10-variant reference boundary |
| Freqtrade separate process per variant | 10 | 35.27 s | sequential local CLI processes, one per variant |
Publication interpretation: these references must not be extrapolated to 100/500/1000 variants and must not be presented as equivalent to the 2Signals scale v2 Node/service boundary.
Memory And Cache Findings
Metric definitions:
| Metric | Exact meaning | Measurement API | Reliable for publication | Limitation |
|---|---|---|---|---|
| Heap before | process.memoryUsage().heapUsed immediately before a measured sweep | Node process.memoryUsage() | Yes, as a local pre-sweep process snapshot | Not a stable clean-process baseline; includes Node, Vitest, loaded modules and prior benchmark state |
| Heap after | process.memoryUsage().heapUsed immediately after a measured sweep | Node process.memoryUsage() | Yes, as a local post-sweep process snapshot | Affected by GC/JIT/runtime allocation timing |
| Observed sweep heap high-water mark | max(heap before, heap after) for a measured sweep, aggregated across samples | Node process.memoryUsage() | Supported with qualification | Not a continuously sampled peak and not total system memory |
| Cleanup heap delta | heapUsed after cleanup - heapUsed before cleanup; raw JSON field remains retainedHeapBytes for backward compatibility | Node process.memoryUsage() | Yes, after renaming and with qualification | Not retained heap from a stable baseline; values around 832-848 B are tiny local deltas during cleanup |
| Memory growth | heap after sweep - heap before sweep | Node process.memoryUsage() | Supported with qualification | Can be negative; not reliable as retained memory without stable baseline and forced GC |
| Bytes per variant | memoryGrowthBytes / measuredVariantCount | Derived from local process snapshots | Diagnostic only | Noisy and can be negative; not a capacity-planning metric |
| Bytes per unique indicator series | memoryGrowthBytes / uniqueIndicatorCacheEntries | Derived from local process snapshots and cache mock stats | Diagnostic only | Depends on aggregation and cache state; not a true object-retention metric |
| Serialized cache size | Buffer.byteLength(JSON.stringify(selectedEntries), "utf8") for benchmark cache mock entries | Node Buffer.byteLength plus JSON serialization | Yes, as benchmark mock serialized payload size | Not IndexedDB size, not browser cache size and not total process memory |
GC interpretation:
- the code calls
global.gc?.()around sweeps and cleanup when available; - this run recorded
gcAvailable=0in samples andgcRan=falsein cleanup diagnostics; - therefore no publication claim should say that GC was forced in this run.
Baseline interpretation:
- raw samples contain local
heapBeforeSweepBytesandheapAfterSweepBytes; - there is no stable isolated process baseline before the whole benchmark;
- there is no continuously sampled peak;
- there is no memory-only run that separates module loading, JIT, correctness, report generation and timing execution.
Minimum future memory-only run:
- launch a fresh Node process with
--expose-gc; - initialize modules, TA-Lib and frozen fixture once;
- force GC and record several idle baselines;
- run cold and warm full sweeps without correctness artifact generation;
- record before, after and after-cleanup snapshots;
- report cache bytes as a share of heap delta.
Cache diagnostics:
| Variants | Measured samples | Reused indicator series | Recomputed indicator series | Unique indicator entries median | Result misses | Unique result entries median | Cache size max |
|---|---|---|---|---|---|---|---|
| 10 | 50 | 730 | 130 | 12 | 110 | 10 | 835.9 KiB |
| 100 | 50 | 5730 | 530 | 52 | 460 | 45 | 5.29 MiB |
| 500 | 25 | 14955 | 275 | 54 | 470 | 94 | 14.12 MiB |
| 1000 | 15 | 18030 | 168 | 55 | 405 | 135 | 21.33 MiB |
The decreasing recomputed-series total at larger levels is not evidence that larger sweeps do less work overall. It is explained by two methodological facts:
- 500 and 1000 levels have fewer measured samples than 10 and 100;
- the finite EMA variant grid saturates reusable fast/slow indicator series, so additional variants increasingly reuse already computed series.
Eviction diagnostics are not available because the benchmark cache mock has no
eviction policy. Cleanup diagnostics confirm that benchmark cache entries were
cleared after each scale level in this run, with staleResultsAfterCleanup=0.
Methodological Limitations
- One local synthetic BTC/USDT 5m fixture with 620 candles.
- One local machine and Node/Vitest process.
- Different measured run counts across scale levels: 10/10/5/3.
- Scale v2 is Node/service only and excludes UI, IndexedDB and network.
- Memory metrics are local process diagnostics, not production memory usage.
- GC was not forced in the raw scale v2 run.
- Instrumentation overhead is not isolated as its own benchmark.
- Strategy correctness is sampled for 100/500/1000; dataset OHLCV correctness is checked once per unique dataset hash through the dataset adapter check.
- Freqtrade references are frozen 10-variant boundary references only.
- No claim is made about 500/1000 Freqtrade behavior.
Publication-Safe Claims
Supported
- In the tested Node/service boundary, 2Signals completed all measured v2 samples and correctness gates successfully.
- The tested dataset was BTC/USDT 5m with 620 frozen candles and the exact hash listed above.
- Correctness passed for 1 unique dataset and 1610 checked variants by full result-hash validation, with 0 mismatches across dataset correctness and full/sampled strategy checks.
- The cold full-sweep medians were
16.85 ms,153.30 ms,768.75 msand1582.08 msfor 10/100/500/1000 variants respectively. - The production-like Builder benchmark separately measured fully-rendered latency using the real production chart, metrics and trades components inside a controlled provider shell.
- Benchmark cache cleanup removed entries after each scale level in this run.
Supported With Qualification
- 2Signals scale v2 is approximately linear in the tested range for the stated Node/service cold full-sweep boundary.
- Per-variant cost is stable in the tested range when interpreted inside the Node/service boundary and with different run counts disclosed.
- Warm cache reuse is effective for measured cache reads, but warm total duration is not guaranteed to be lower because non-cached per-variant work still runs.
- Memory and cache size grow with scale in the local benchmark process, but the current memory data is diagnostic and not a stable retained-memory claim.
- Freqtrade 10-variant references can be cited only as frozen boundary references with their exact workflow names.
Not Yet Supported
- "Linear scalability" without "approximately", "tested range" and explicit boundary qualifiers.
- Any "10x faster" style claim.
- Full production
/builderuser-flow latency. - Full strategy-artifact correctness for every 100/500/1000 variant; only sampled strategy artifacts are checked at those levels.
- Cross-engine Freqtrade equivalence for 100/500/1000 variants.
- Extrapolated Freqtrade timings for 100/500/1000 variants.
- Total browser memory, IndexedDB storage size or production cache footprint.
- Cache eviction behavior.
- Claims that the raw scale v2 run used forced GC.
Remaining Research Questions
- What is the retained memory delta under a dedicated memory-only run with
--expose-gc? - How does the scale behavior change on larger real market datasets?
- How much of fully-rendered UI latency is chart drawing, marker rendering, metric rendering and trade table rendering at larger variant/result sizes?
- What is the comparable Freqtrade boundary for 100/500/1000 variants, if any, without changing Freqtrade semantics?
- How does production IndexedDB/cache behavior compare to the Node benchmark cache mock?
- Which diagnostics overheads become material at 1000 variants and above?