Build1 distinct publisher3 min readUpdated
A developer building a pairs-trading backtest found two of his own plans disagreeing on how many times to shift a series. His fix was a test that fires a price spike into the future.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
A developer writing a backtest engine for a pairs-trading strategy discovered that his own planning documents disagreed about how many times to lag a series, and instead of settling it by eyeballing the diff he wrote tests that assert on time ordering [s1c6][s1c7][s1c11]. That matters because the bug he was hunting does not crash, does not raise an exception, and tends to make the numbers look better [s1c1][s1c4].
The failure mode is lookahead bias: letting even a sliver of tomorrow's close into today's math, at which point the strategy behaves like a prophet, the backtest numbers glow, and it melts on contact with live trading [s1c2][s1c3]. The mechanical fix is small. In pandas it is `shift(1)`, reproducing the real-world lag in which today's decision fills tomorrow [s1c5].
Small enough to get wrong twice. According to the writeup, the overall plan said to shift the hedge ratio beta by one bar and shift the position too so it fills the next day, while a later handoff note from the same author asked whether that was a double delay [s1c6][s1c7]. It was: shift for beta, shift again for the position, and the engine is two days late [s1c8].
This is the part worth internalising. Too few shifts is cheating and too many is trading a day late; both quietly move the numbers and neither raises an error [s1c9]. Cheating inflates returns, over-delay deflates them, and what lands on your screen either way is a plausible-looking Sharpe ratio that sails through review [s1c10]. The author says plainly that he is not confident he would catch one extra `shift(1)` in code review, so he stopped trying to [s1c11].
What he did instead has two parts. First, pin the rule to one sentence: the realized PnL of bar t depends only on information up to the close of day t-1 [s1c12]. Signal math (beta, spread, z-score, the buy/sell decision) may use everything up to today's close, and exactly one shift lives in the PnL calculation [s1c13]. Collecting the lag in a single place makes a double delay structurally impossible [s1c14]. Second, he stopped trusting the docstring, on the grounds that a policy written in prose is a promise and promises get broken by the author three months later [s1c15].
The tests are the interesting artefact. Test one takes the same price series twice, injects a single giant spike (price +500 percent) on a future day into one copy only, computes beta and z-score for both, and asserts that every value before the spike is exactly identical using numpy's `array_equal`, not approximately equal [s1c16]. If the beta window is reaching forward, the spike bleeds backwards and the comparison breaks [s1c17]. He also asserts that beta on the spike day does change, which is what catches an extra shift added later out of kindness [s1c18]. Test two builds synthetic data where the z-score crosses the entry threshold on day 5 and requires PnL to be zero on day 5 and start on day 6 [s1c19]. Taken together, the two assertions leave exactly one shift as the only configuration that passes: fewer and PnL appears on day 5, more and the spike day stops moving [s1d1].
Watch the failure that came with it. A sanity test asserting that a mean-reverting series should turn a profit failed on first run, because with only 10 trades the RNG seed happened to land on the loss side [s1c20]. Thirty minutes went into suspecting the engine before the test data was suspected, and the fix was swapping in synthetic data that reliably profits [s1c21][s1c22]. Assertions about time ordering are deterministic; assertions about economic outcomes are a coin flip you have to tune. Green tests here buy one specific claim, which is that there is no time-direction cheating after a refactor [s1c23]. They do not buy a working strategy.
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
The scariest bug in a backtest is not a crash but accidentally using tomorrow's price; the worst kind of bug is the one that makes you feel good, because if anything the numbers get better.
Lookahead bias is letting even a sliver of tomorrow's close leak into today's math, which turns the strategy into a prophet.
With lookahead bias the backtest numbers glow, and then the strategy melts on contact when shipped live.
The code never throws a single exception when lookahead bias is present.
The no-cheating implementation comes down to sliding a series over by one (shift(1) in pandas), reproducing the real-world lag in which today's decision shows up in tomorrow's trade.
The author's overall plan, written a few days earlier, said to shift the hedge ratio beta by shift(1) and to shift the position too so it fills the next day.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Detailed and internally checkable, but single-source and unreproducible
The mechanism is described precisely enough to be evaluated on its own terms — the invariant, the placement of exactly one shift(1), the array_equal exact-match assertion, the spike-day change assertion, and the day-5/day-6 PnL boundary — and the two-sided bracketing of the shift count follows logically from the assertions as stated. That earns real credit. Against it: one publisher, one self-reported item, no linked code or repository, no prior-art citation, and no quantified effect on the strategy's metrics, so nothing here has been independently replicated.
One practitioner's own engine
The only adoption signal in the supplied material is the author's disclosure that he applied the invariant and the two tests inside his own pairs-trading backtest engine. There is no library, no release, no third-party user, no download or usage figure, and no evidence any other team has taken up the pattern.
Punchy headline, largely disciplined body
The framing generalizes one anecdote into a claim about code review at large, and the derived guarantee ('no time-direction cheating') is stronger than two tests covering two behaviours can strictly support — nothing here rules out other lookahead vectors such as data revisions, survivorship, or intraday timestamp misalignment. Offsetting that, the author hedges explicitly ('I can at least say'), volunteers his own flaky-test mistake, and sells no product, so overstatement is mild rather than promotional.
Personal-brand incentives only; no commercial stake disclosed
The item is an individual engineering write-up on a developer-blogging platform. No product, service, fund, vendor tool, or employer interest is being promoted, and the only visible incentive is attention and credibility from a well-told craft story — which plausibly shapes the sharpened headline and the confessional structure. No sponsorship or affiliation is disclosed in the supplied material.
Moderate: verifiable reasoning, one unverified source
Confidence is held mid-range because the technical claims rest on standard pandas and numpy semantics that a reader can reason about directly, and the internal logic of the two tests is coherent. It is capped by the cluster's structure: a single publisher, a single self-reported item, no code to inspect, no independent corroboration, and no measured outcome for the strategy the engine evaluates.
build
Before you spend quota on an agent skill, make it pass an eval harness1 distinct publisher
build
A 20-digit ID went into a JSON repair tool and a different number came out1 distinct publisher
build
A completer that scores 0.546 on its eval scores 0.070 on the thing users see1 distinct publisher
build
Your LLM cache probably never fires, because it hashes spelling instead of meaning1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 20, 2026