<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vinh Nguyen</title>
    <description>The latest articles on DEV Community by Vinh Nguyen (@vinhnguyenthanhdn).</description>
    <link>https://dev.to/vinhnguyenthanhdn</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3996295%2Fb7f14877-ff5b-4a11-9079-1527575e0cce.jpg</url>
      <title>DEV Community: Vinh Nguyen</title>
      <link>https://dev.to/vinhnguyenthanhdn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vinhnguyenthanhdn"/>
    <language>en</language>
    <item>
      <title>How I verify a crypto backtest is real: trade-for-trade parity, bit-for-bit data, and a look-ahead test with teeth</title>
      <dc:creator>Vinh Nguyen</dc:creator>
      <pubDate>Sun, 09 Aug 2026 03:30:16 +0000</pubDate>
      <link>https://dev.to/vinhnguyenthanhdn/how-i-verify-a-crypto-backtest-is-real-trade-for-trade-parity-bit-for-bit-data-and-a-look-ahead-i5j</link>
      <guid>https://dev.to/vinhnguyenthanhdn/how-i-verify-a-crypto-backtest-is-real-trade-for-trade-parity-bit-for-bit-data-and-a-look-ahead-i5j</guid>
      <description>&lt;p&gt;Most public trading repos show you a backtest with a nice equity curve. The hard part isn't producing the curve — it's knowing whether the curve is real. So I spent most of my time building the machinery that decides that, and I've open-sourced it: &lt;a href="https://github.com/vinhnguyenthanhdn/ai-crypto/" rel="noopener noreferrer"&gt;github.com/vinhnguyenthanhdn/ai-crypto&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Python 3.10+, MIT. No real orders are ever placed; every execution path is simulated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation parity, verified trade-for-trade
&lt;/h2&gt;

&lt;p&gt;The single biggest source of false confidence in a backtest is that the thing you tested and the thing you run are not the same program.&lt;/p&gt;

&lt;p&gt;So the research reference engines and the production strategy cores are written &lt;strong&gt;independently&lt;/strong&gt;, then reconciled against each other: &lt;strong&gt;963/963, 515/515 and 1,079/1,079 trades matched with zero mismatches&lt;/strong&gt;, with equity agreeing to 8 decimal places.&lt;/p&gt;

&lt;p&gt;That reconciliation runs as a check, not as a one-off claim.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data verified bit-for-bit
&lt;/h2&gt;

&lt;p&gt;9 years of market history: 942,025 5-minute candles plus 1,508 checksum-verified derivatives archives. Every artifact records a SHA-256 dataset hash, so any result can be tied back to the exact bytes it was computed from.&lt;/p&gt;

&lt;p&gt;The price cache was reconciled against the venue API across &lt;strong&gt;3,277 days and matched bit-for-bit&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A look-ahead test that provably has teeth
&lt;/h2&gt;

&lt;p&gt;It's easy to write a look-ahead check that passes because it can't detect anything.&lt;/p&gt;

&lt;p&gt;So I deliberately injected look-ahead into a passing contract and measured what happened: training return inflated from &lt;strong&gt;+563% to +4,201%&lt;/strong&gt;. The test can see the bug when the bug is there. That's the part most look-ahead checks never demonstrate.&lt;/p&gt;

&lt;p&gt;Costs are verified the same way — measured at −0.29985% on a flat round trip against a stated 0.30%, confirming they're charged exactly once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accelerated paper replay through the real lifecycle
&lt;/h2&gt;

&lt;p&gt;3,277 days of history driven through the &lt;strong&gt;production&lt;/strong&gt; SQLite state store, position sizing and accounting. Only the market clock is simulated — everything else is the code that runs live.&lt;/p&gt;

&lt;p&gt;Result: 77 ENTRY / 77 EXIT / 77 ledger rows, zero orphaned entries, zero positions left open.&lt;/p&gt;

&lt;h2&gt;
  
  
  Event-sourced state with full lineage
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Append-only &lt;code&gt;event_log&lt;/code&gt; and &lt;code&gt;feature_snapshot&lt;/code&gt;, plus an idempotent &lt;code&gt;equity_ledger&lt;/code&gt; keyed by trade ID.&lt;/li&gt;
&lt;li&gt;Position and risk computed from &lt;strong&gt;real equity&lt;/strong&gt;, not notional assumptions.&lt;/li&gt;
&lt;li&gt;Every feature snapshot records source exchange, market type, symbol, timeframe, transformation version and the strategy package that consumed it — so any logged decision can be reconstructed from raw candle to logged trade.&lt;/li&gt;
&lt;li&gt;Atomic run locking via SQLite &lt;code&gt;BEGIN IMMEDIATE&lt;/code&gt; with owner token and heartbeat; a dead process's lease is reclaimed immediately instead of waiting out a stale timeout.&lt;/li&gt;
&lt;li&gt;Market-data freshness is enforced: stale collector ticks hard-fail or force a fresh fetch rather than silently reusing an old snapshot.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Costs measured instead of assumed
&lt;/h2&gt;

&lt;p&gt;I sampled 4,695 order book snapshots and pulled base-tier venue fees from official sources. The real half-spread came out at &lt;strong&gt;0.0077 bps&lt;/strong&gt;, not the 5 bps my own config had assumed — my round-trip cost assumption had been about &lt;strong&gt;3× too high&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Worth knowing if you're calibrating a cost hurdle from a blog post rather than from the book.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frozen contracts and a documented search
&lt;/h2&gt;

&lt;p&gt;Parameters are selected on the training split only, the contract is frozen, then validation and test are opened once. Every candidate must survive round-trip costs stressed to at least 2× base.&lt;/p&gt;

&lt;p&gt;Under that protocol I ran &lt;strong&gt;29,373 parameter configurations across ~40 strategy families&lt;/strong&gt;, and every one of them is written up — contract, dataset range, cost assumptions, verdict — as ~100 result artifacts. Including the rejections, which is the part that's usually missing and the part that saves you re-walking a dead end.&lt;/p&gt;

&lt;h2&gt;
  
  
  The repo also audits itself
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;docs/code-audit.md&lt;/code&gt; splits the codebase into a &lt;strong&gt;research path&lt;/strong&gt; that is independently verified and trusted, and a &lt;strong&gt;runtime path&lt;/strong&gt; with confirmed defects — including a BUY threshold that is arithmetically unreachable and a look-ahead bug in the swing detector. Those are catalogued with file and line references rather than quietly patched, so you know which numbers to trust.&lt;/p&gt;

&lt;p&gt;The same honesty applies to the headline outcome: none of the 29,373 configurations cleared the promotion gates. Median gross edge across 13,654 rejected configs is −0.021%, so it isn't a cost problem — there's nothing there to rescue. The full evidence is in the repo, and I'd rather publish that than a curve I can't defend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env

.venv/bin/python3 scripts/run_backtest.py        &lt;span class="c"&gt;# bar-close scan&lt;/span&gt;
.venv/bin/python3 scripts/dashboard_server.py    &lt;span class="c"&gt;# local dashboard&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;API keys are optional and must be read-only — the system works on public market data alone.&lt;/p&gt;

&lt;p&gt;Contributions welcome, and if you find a hole in the methodology I'd genuinely like to hear it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/vinhnguyenthanhdn/ai-crypto/" rel="noopener noreferrer"&gt;github.com/vinhnguyenthanhdn/ai-crypto&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>opensource</category>
      <category>datascience</category>
    </item>
  </channel>
</rss>
