How every number on the public Trading History page is computed. Counting rules, exclusions, statistical formulas, and disclosed incidents. Verifiable and reproducible.
The Trading History page reads from three Postgres tables in our database:
trade_cards — every signal Soar has ever published (asset, direction, entry zone, T1, T2, stop, conviction, timestamps).card_outcomes — per-card resolution rows (T1 hit, T2 hit, stop hit, expired) written by the resolution cron.sessions — the publishing session each signal belongs to.The aggregation logic lives in src/app/api/recent-trades/route.ts; statistical formulas in src/lib/trackRecordStats.ts. Both are open in the repo.
Filters applied at query time:
card_type = 'trade' — excludes watching/context cards.sort_order >= 0 — excludes hidden / quarantined cards.clerk_user_id IS NULL — excludes per-user on-demand reports (only site-wide pipeline cards).session_number > 0 — excludes ad-hoc user-research sessions.status = 'published' — only published sessions.A signal's outcome is determined by which level price touches first, in this priority order:
Per-signal gain is computed direction-aware:
gain_pct = ((exit_price − entry_mid) / entry_mid) × 100 × direction_sign
where direction_sign = +1 for long, −1 for short
entry_mid = midpoint of the published entry_zone
exit_price = T2 / T1 / stop level depending on outcomeSoar publishes a signal in a session, then carries it forward to subsequent sessions until it resolves or retires. Each session re-publish creates a new trade_cards row, but they share an outcome timestamp because the resolution cron stamps the entire lineage at once when price crosses a level.
To avoid double-counting carry-forward clones, we dedup on the lineage key:
lineage_key = (asset, direction, timeframe, resolved_at)
Cards with identical resolved_at collapse to a single trade for stats. A re-entry on the same asset after a stop-out has a different resolved_at and counts separately.
The full per-session list shown on the page (vs. the deduped stats) is intentional — admins can see every session appearance for audit purposes; stats use the deduped lineage.
Every metric on the page has a single canonical implementation in src/lib/trackRecordStats.ts. Formulas:
Hit rate = wins / (wins + losses). Confidence interval uses the Wilson score interval (Wilson 1927), the industry standard for small-sample binomial proportions:
p = wins / n center = (p + z²/(2n)) / (1 + z²/n) margin = (z × √(p(1−p)/n + z²/(4n²))) / (1 + z²/n) CI95 = [center − margin, center + margin] where z = 1.96 for 95% confidence
Wilson is asymmetric and stays inside [0,1] even at p≈0 or p≈1, where the naive Wald interval breaks.
mean = Σ gain_pct / n σ = √(Σ(gain_pct − mean)² / (n − 1)) ← Bessel correction for unbiased estimator SEM = σ / √n ← standard error of the mean
PF = Σ positive_returns / |Σ negative_returns| PF > 1 → net profitable PF > 1.5 → healthy PF > 2 → strong PF < 1 → losing
Expectancy = (winRate × avgWin) − (lossRate × avgLoss) Positive → system is +EV per signal even before sizing.
Per-signal Sharpe annualized at 1825 trades/year (≈ 5 closes/day × 365 days). Risk-free rate = 0% because Soar is a signal-only product with no capital deployed:
Sharpe = (mean / σ) × √(trades_per_year) trades_per_year = 1825 ← Soar publishing cadence
Caveat: this is a per-signal Sharpe, not a portfolio-time-weighted Sharpe. Comparable to itself across windows; not directly comparable to fund Sharpe figures.
Like Sharpe but uses downside-only deviation (penalizes losses, ignores upside vol). Better for the asymmetric distributions Soar's track record shows:
σ_downside = √(Σ negative_returns² / count_negative) Sortino = (mean / σ_downside) × √(trades_per_year)
Largest peak-to-trough decline of the running-sum cumulative index over the window. Captures the worst stretch.
The headline cumulative number is a running sum, not a compounded portfolio return. We start at 100 and add each closed signal's gain_pct in resolution-time order:
index₀ = 100 indexᵢ = indexᵢ₋₁ + gain_pctᵢ
Why running sum and not compounding: Soar publishes signals; users decide capital deployment. Compounding would imply serial reinvestment into one rolling pot, which is not what the product is. Running sum is the honest "if every signal got 1 unit of capital, here's the per-signal additive total."
SPY benchmark is fetched from Yahoo Finance daily closes over the same window and indexed to 100 at the first signal close. Alpha = Soar cumulative − SPY cumulative.
Soar's engine has gone through significant versions. The default 14-day window reflects the current engine. The all-time view includes earlier versions whose behavior is not representative of today's engine. Per-version performance:
| pipeline_version | Closed | Win rate | Sum return |
|---|---|---|---|
| 1.0 (oldest) | 68 | 7.4% | −79.19% |
| 3.1 (mid) | 53 | 24.5% | −16.09% |
| 6.28.3.x | 31 | 70.0% | +224.37% |
| v7.x (current) | — | building | building |
Why we show the older versions at all:hiding them would be cherry-picking. The all-time toggle exists for full transparency, but is labeled clearly so visitors don't mistake the all-time number for the current engine's expected output. The 14-day default is the right framing for "what does today's engine do."
On 2026-05-08 we identified two paper-trade rows on the asset DASH (Dash crypto, ticker DASH) that booked +354.06% and +352.33% gains. Audit confirmed the exit prices ($168.50, $168.81) came from DoorDash stock (also ticker DASH), not Dash crypto. Dash crypto traded between $34–$50 over the relevant window and never touched $168.
Root cause: the trade-closure cron at src/app/api/cron/check-trades/route.ts:24-106 had an incomplete crypto-ticker map. DASH was missing, so the price lookup fell through to the Nasdaq stocks API, which returned DoorDash. The bug pattern is the same one that caused the v6.30.9.23 logo issue (DoorDash logo shown on Dash crypto card).
Fix: the two affected rows are quarantined (is_test=true) and excluded from the canonical engine_comparison_running_totals rollup. Phantom impact on Soar's all-time running sum: +$7,063.90 of fake gains removed. Adjusted all-time net P&L: +$10,231.80 → +$3,167.90 on the $25K reference balance (from +40.93% → +12.67%).
The Trading History page on this site reads from trade_cards.hit_price_t2 (the published target level), not from the corrupted exit-price feed, so the page's computed gain for those DASH rows was always the legitimate ~+15% T2 hit, not the +354% phantom. The phantom only affected the engine-comparison admin canonical rollup. Both surfaces now reconcile.
Disclosure rationale: showing the scar publicly is the credibility play. We found a bug, we're telling you about it, here's the fix and the impact.
sort_order < 0) — operator-flagged for data-quality review.is_test = true) — synthetic data + the disclosed DASH incident rows.Three layers of independent verification:
/api/recent-trades/csv. Rerun any computation; we don't aggregate-and-hide.MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr). Once anchored, the root cannot be modified without leaving cryptographic evidence. Anyone can call /api/verify/:signal_id to get an inclusion proof and independently confirm a signal existed at a given time with given parameters.The most recent 20 Merkle anchors written by the Soar engine. 20 of 20 are committed on Solana mainnet (the rest are local-only, awaiting their next chain tick).
Anchor wallet (verifiable on Solscan): 9yWYok7GmHHYk6VQiJGn3ddhifsPDh6HPVfUU6FjWaXN · View on Solscan ↗
| Anchored | Leaves | Root (sha256) | Chain |
|---|---|---|---|
| May 24, 6:05 PM | 5 | 50b72b23344e…85bc46d0 | ⛓ Solana ↗ |
| May 24, 3:05 PM | 3 | 7067519c7143…8d89eff4 | ⛓ Solana ↗ |
| May 24, 12:05 PM | 3 | a61316c05ea0…1352cd36 | ⛓ Solana ↗ |
| May 24, 4:05 AM | 1 | 6a70cbfc87b6…21ea0838 | ⛓ Solana ↗ |
| May 23, 9:05 PM | 1 | 3e9b1913c875…ea1dc6ce | ⛓ Solana ↗ |
| May 23, 6:05 PM | 3 | bd581e6b6934…a40d749e | ⛓ Solana ↗ |
| May 23, 3:05 PM | 8 | 9ae50b8607ef…b9d54d4f | ⛓ Solana ↗ |
| May 23, 12:05 PM | 3 | 9318c05147ad…621227ae | ⛓ Solana ↗ |
| May 23, 10:05 AM | 1 | 61902e7c952c…342b91b8 | ⛓ Solana ↗ |
| May 23, 9:05 AM | 1 | 173a34275814…d52b91b2 | ⛓ Solana ↗ |
| May 22, 9:05 PM | 1 | 31d17683df29…88b17d3f | ⛓ Solana ↗ |
| May 22, 6:05 PM | 1 | 793ceddaf548…b3301c70 | ⛓ Solana ↗ |
| May 22, 1:05 PM | 1 | cbdf4bdee148…d4ccebd2 | ⛓ Solana ↗ |
| May 22, 12:05 PM | 5 | ff097ba573c4…056dd9c2 | ⛓ Solana ↗ |
| May 22, 2:05 AM | 1 | d7a3b2cf1593…6db105e1 | ⛓ Solana ↗ |
| May 21, 9:05 PM | 5 | 38b86a318ee6…5e47d6b8 | ⛓ Solana ↗ |
| May 21, 8:05 PM | 1 | b0ea9aac9b2e…7388feba | ⛓ Solana ↗ |
| May 21, 7:05 PM | 1 | 52b5cbe1975e…e57b1e10 | ⛓ Solana ↗ |
| May 21, 6:05 PM | 1 | 0d47aa5c04c5…15b30fc6 | ⛓ Solana ↗ |
| May 21, 5:05 AM | 2 | 968bafc71998…5809d501 | ⛓ Solana ↗ |
How to verify yourself: take any signal's leaf_hash from /api/verify/:signal_id, walk the Merkle siblings on that response up to the root_hex, then read the on-chain memo at the matching Solscan link above. The memo content (soar:trc:<root_hex>) is the same root your inclusion proof rolls up to. If they match, the signal existed at the timestamp shown — anyone can prove this without trusting Soar.
Hypothetical / simulated performance. The track record measures signal-quality outcomes against the prices and levels Soar published. It is not a record of actual trades placed by Soar or any user. No actual capital is or has been deployed against this record. Real-world results depend on capital deployment, sizing, slippage, and fees that this page does not model.
Soar is not a registered investment adviser. Nothing on this page is investment advice, an offer to buy or sell securities, or a recommendation tailored to any individual. Past performance is not indicative of future results.
Methodology version: v7.5.22. Last updated: 2026-05-14. On-chain anchoring went live on Solana mainnet 2026-05-09 — every hourly Merkle root is now publicly verifiable.