Arcobaleno — a check that carries on past the ring Arcobaleno Research
Backtest Forensics/ Fixed scope, fixed price

Is the number real?

Before anyone puts money behind a trading strategy, someone should check that its track record is actually true. That is the whole job. Every example on this page is a mistake we found in our own research, and published against ourselves.

Most backtests aren't wrong. They're just unchecked.

A backtest is a trading strategy run against past market data to see what it would have made. That one number decides everything that follows — whether to fund it, how much to risk on it, whether to walk away.

The trouble is that people check the things they thought to check. Mistakes survive in the places nobody thought to look: a filter that doesn't do what its name says, a fee copied from somewhere else instead of measured, a list that sorts itself differently every time the program runs.

Not one of the problems below needed new data or a cleverer model. Every one was sitting in our own code, and we could have found any of them on a day we thought to look. That is rather the point: this is what checking finds.

Nine findings, from our own research

Each case study names the dated internal document it came from.

Click any finding to open it

01 Repeatability

The result changed every time it ran

The reported result
−1.3191%
Average return per period, published as the strategy's performance.
What it really was
A different number every run
Same code, same data, no answer that came back twice.

The code ranked assets and bought the best ones. When two assets tied, something had to break the tie — and the program broke ties differently each time it was started. Different assets went into the portfolio on different runs.

Ties weren't some rare edge case. About 55% of this exchange's funding payments sit at exactly the same floor value, so any two assets resting on that floor looked identical to the ranking code.

Same code, same dataResult it produced
Run 1−1.3679%
Run 2−1.2256%
Run 3−1.2569%

In the periods where the runs disagreed, the typical gap was 1.57 percentage points. That isn't rounding. That's a different portfolio.

Why it matters Nobody could have reproduced this number — including us, running our own code on our own machine. Every decision that followed rested on a figure that would not come back. The fix was one line.
Internal: research/runs/r17-corrected-holdout/AMENDMENT_001.md
02 Bad data

One bad price produced a 192% annual return

What the data provider sent
172,635%
One day's annual return, for one investment pool.
What that pool normally earned
0.91%
The figure the same provider sent on every other day.

That single day fed into thirty separate monthly averages, and produced a result of +192.66% a year. The pool held two of the largest and most closely linked crypto assets, where a return like that isn't merely unlikely — it can't happen.

Every safety check passed. The checks all looked at the averages, and the bad number got in before the averages were built. On screen it looked like an exciting outlier, not like broken data.

The research already contained the right test. It had been run — on two pools, on one day. That's a spot check. Run across everything, it catches the bad day immediately.

Why it matters A spot check and a real safeguard look the same when you read the code. The difference is whether it runs on every row. A number any human would catch in a second can be completely invisible to software that was never asked to look.
Internal: research/runs/amm-lp-v1/ · standing lesson 23
03 Cost arithmetic

Three strategies closed over a cost that was 20x too high

Costs the code charged
≈2.0%
Per period. Added up across positions, while profit was averaged across them.
Costs actually incurred
0.10%
Per period. Overcharged by roughly twenty times.

The effect was backwards on its face: spreading the same pot of money across more assets made it look more expensive to trade. It can't. Splitting a fixed amount across more positions makes each position smaller. We checked the arithmetic across all 590 periods of three sets of records.

Corrected, the strategies looked transformed. On the standard risk-adjusted score — where below zero means it lost money — one went from −8.73 to +0.34, another from −2.83 to +1.39.

All three stayed shut. Those flattering new numbers came from the very data the strategies were built on, and the margin of error was wide enough to include zero — so the improvement might be nothing at all. The only honest test was data the strategy had never seen. Against that, the best of the three failed outright, losing money both before and after the stretch it was built on. It was over-fitted, not worn out.

Why it matters A wrong cost assumption is dangerous in both directions — it buries strategies that work and flatters ones that don't. Finding the bug is half the job. Refusing to let it raise the dead is the other half, and it's the half someone with a stake in the answer will skip.
Internal: research/runs/cost-floor-v1/ · research/runs/r17-corrected-holdout/VERDICT.md
04 Stale data

A filter for recent data that never read a date

The safeguard, as written
Count the rows
Named and trusted as the check that kept out stale data.
What it actually checked
Nothing about time
It never read a date. Frozen data stayed eligible indefinitely.

A data migration quietly froze 65 files — they simply stopped updating. Because the filter counted rows instead of reading dates, those frozen assets stayed eligible for about 26 days. The strategy's holdings changed completely from one week to the next, which read like the strategy responding to the market. It was the data breaking underneath it.

Then a second freeze was found inside the restarted clock: three more assets stopped updating on the same day, and one was bought into a portfolio a full week after it had already gone dead.

Underneath that sat the worst of it. One position the strategy held had not traded at all — zero out of 1,441 minutes with a single trade in them. A full-size position, booked at a profit, describing a trade nobody on earth could have made.

Why it matters A filter named after a job does not necessarily do that job. And when a strategy suddenly starts behaving differently, the first thing to suspect is the data — not the market.
Internal: research/runs/weekend-drift-selection-audit/ · standing lessons 50, 74
05 What trading really costs

One cost, three documents, three different numbers

Measured at the screen price
0.26%
Cheaper than the strategy assumed. Looks reassuring.
Measured by filling a real order
0.48%
Dearer than it assumed. The two don't just differ in size — they differ in direction.

The price on your screen is the price for a tiny trade. Put a real order through and you eat into worse and worse prices as you go. On this basket the screen price suggested a cost of 0.004%–0.033%, while getting in and back out actually cost 0.28%–0.78%. A measurement taken at the screen price cannot see that, at all.

So we went back and audited every cost assumption in the research. It found this:

A standing study had assumed the worst possible round trip on that exchange was 0.31%. Filling real orders, 40 of 122 assets cost more than that at $10,000 apiece — the worst of them 0.92%. And those were the easiest-to-trade assets available.

That study's own follow-up note had already tried to fix it with a textbook formula — and overshot by about 1.8× the other way, exactly as the note itself suspected it might. Measured properly, the truth sat between the two. The original conclusion survived at the size it was written for, and failed at ten times that size.

Why it matters Trading cost is something to measure, not something to inherit. And it is worst precisely where a ranking rule tends to pick, because ranking rules choose for returns — not for how easily something can be bought and sold.
Internal: research/runs/cost-model-audit-v1/VERDICT.md · standing lessons 75, 76
06 Repeatable, not reproducible

A headline that was really a range

Published, and repeatable
One number
Same answer on every run. Quoted to two decimal places.
What it actually was
A 4.2-point range
The published figure sat at its 96th percentile.

The strategy is event-driven and holds a fixed maximum number of positions. On the worst days far more signals arrive at once than there are slots — the busiest single hour had 194. Something has to choose which ones get in, and that choice was being made by the arbitrary order the sorting step happened to leave the data in. 72% of all events shared their hour with at least one other.

Two of our own programs, same data, same settings, produced annual returns 1.4 percentage points apart. Both were running correctly. So we re-ran it 300 times, shuffling only within each tied hour: the standard deviation of the answer was 0.76 points, and the best ordering beat the worst by 4.2.

Worse than the number itself: a cross-check had already been run and had passed. One study cited the other's agreement as proof its simulator reproduced the original. The two figures were 1.4 points apart, and the gap was hidden inside a rounding in the summary. A verification step read as independent confirmation when it was two programs sharing one defect.

Why it matters A figure that comes back identical every time still is not necessarily reproducible — it can be one fixed draw from a range nobody has measured. And what survived matters as much: the risk-adjusted return, the drawdown and the sizing conclusion were all unchanged. The headline was overstated by 1.2 points; the reasoning underneath it was sound. An audit that only reports damage is not worth buying.
Internal: research/runs/cascade-selection-v1/asof-rerun-2026-08-26/ · 300 draws per arm persisted
07 A number or a range

Nine versions, and none could be told apart from zero

The rule, as first measured
42.8% a year
A convincing-looking edge across nine configurations.
Its honest range
−9.0% to +126.4%
Includes zero. As did all nine.

Measuring how confident you are entitled to be usually means reshuffling the daily results thousands of times and seeing how wide the outcomes spread. That assumes each day is independent of the last. This rule held the same position for days at a time, so consecutive days moved together — and treating them as independent counts the same evidence over and over, making the range far too narrow.

Reshuffling in blocks of ten days instead, which keeps that clumping intact, every one of the nine configurations had a range that included zero. Splitting the history in half pointed the same way: performance fell in every version, one from a risk-adjusted score of 0.88 to 0.09.

It is worth saying what the problem was not. Trading costs barely mattered: the score went 0.98 before fees, 0.95 at normal fees, 0.85 at four times normal fees. This failed on uncertainty, not on costs — which is exactly the wrong place to have been looking.

Why it matters Nothing was wrong with the returns. What was wrong was the confidence attached to them — and confidence is what someone actually acts on. We stopped pursuing it, which is a result, and getting it in an afternoon is cheaper than getting it from the market.
Internal: research/runs/deribit-iv-screen-v1/VERDICT.md Part A2 · moving-block bootstrap, block 10 days, n 2000
08 How much evidence there really is

Two thousand trades, six weeks of evidence

The track record, as described
2,050 trades
238 assets, six and a half years.
Independent observations
6 weeks
Behind the best-looking result in the study.

The strategy only fires during rare market-wide episodes, so its trades arrive in a small number of clusters — and every trade inside a cluster is the same event happening to different assets. Counting distinct weeks instead of trades, the strongest result in the study rests on six weeks in six and a half years. About one independent observation a year.

The trap that sets is not theoretical. The obvious improvement — sit out the small isolated events, save room for the broad ones — tested better on data held back for the purpose (0.88 → 1.46) and worse on the data it was built with (1.16 → 0.70). A rule that improves on unseen data is the opposite of the usual warning sign and reads like a discovery. Its entire advantage rested on two crash weeks. We did not adopt it.

Why it matters Trade count is not evidence count, and the gap between them is where false confidence lives. A strategy can be genuinely profitable and still have almost no evidence behind it — those are different questions, and a big number of trades only answers one of them.
Internal: research/runs/cascade-selection-v1/VERDICT.md · per-trade means net of 2 × 4.5bp
09 Positions left open

Profitable only if you ignore what it still holds

Counting completed trades only
8 of 8 profitable
Every configuration tested made money.
Also valuing what it still held
0 of 8 profitable
The same eight. The sign flips in all of them.

The strategy places a ladder of buy orders below the price and sells above. Each completed round trip books a small gain — but when the price falls and keeps falling, the buys fill and the matching sells never do, so the position sits there losing. At the end of a test period, what do you do with the lots still open? Value them at the current price, or leave them out because they never closed?

We ran all eight configurations both ways across 20,032 test windows. The accounting choice flips the sign in every configuration. The gap tracks exactly what you would expect: the configurations holding the most unsold lots show the widest gap, one going from +2.4% counting only closed trades to −5.1% counting everything.

One note on how we treated our own claim. The original study made this point in a single line and asserted the counterfactual without ever computing it — the code tracked both figures and saved only their sum. We measured it before publishing this, and the assertion turned out to be conservative: it said “most configurations”, the answer is all of them. Being right by luck is not the same as having checked.

Why it matters The mechanism books small wins and holds its losses, so discarding what is still open deletes the losses and keeps the wins. The result is not wrong by a little — it is the opposite sign. And nothing looks broken in the output, because nothing went wrong computationally. We simply chose, probably without noticing it was a choice.
Internal: research/runs/grid-trading-v1/fc7-realized-2026-09-11/ · 20,032 windows, each verified against the original engine

What these nine have in common

Not one was found by out-thinking whoever wrote the code — and in all nine, that was us. Each came from checking something nobody thought needed checking.

  • 01Running the same code twice.
  • 02Running a check that already existed on every row, instead of one.
  • 03Testing whether the arithmetic actually added up.
  • 04Asking whether a filter does what its name says.
  • 05Measuring a cost instead of assuming one.
  • 06Running the same thing 300 times to see whether the answer was a number or a range.
  • 07Using a measure of confidence that matched how the strategy actually traded.
  • 08Counting the events instead of the trades.
  • 09Asking what happens to the positions that never closed.

What we check

This list comes from mistakes we have actually hit, not from a textbook.

  1. Does it repeat? Run the code twice, on two different machines. Does the same number come back?
  2. Are the dead ones missing? Was the list of assets built as it looked back then, or from the ones still around today? The ones that disappeared are usually the losers.
  3. Are the costs real? Where did the fee figure come from? Is it charged correctly? Was it measured on realistic order sizes, or taken off the screen?
  4. Is the data clean? Was every row checked, or just a sample? Can one bad day poison a long average?
  5. Is the data current? Do the filters meant to exclude stale data actually look at dates?
  6. Was it cherry-picked? Was this version chosen before or after seeing how it performed? Is there genuinely untouched data left to test against?
  7. Could you have traded it? Could every position in the result actually have been bought and sold, at the price used?
  8. What is really being claimed? A single number, or a range? Is the margin of error wide enough to include zero — meaning it might be nothing?

Each check in detail, what we need from you, and the markets we cover →

What it costs

Fixed scope, fixed price. No retainer, nothing ongoing. Every finding comes with a script you can run yourself — we don't claim anything we can't show you.

Triage
$2,500
One strategy, one number. Can we get your headline result out of the code and data you send us? You get a 3–5 page memo: it reproduces, it doesn't, or it does with caveats — and exactly why.
2–3 days
Full audit
$12,000
One strategy, start to finish: where the data came from, how the asset list was built, what trading was assumed to cost, how the version was chosen, and whether the claim holds up. A 15–25 page report, every finding with a script that reproduces it.
5–8 days
Portfolio review
$25,000
Three to six strategies, plus the shared code they all run on. A report for each, and a section on what they have in common — shared bugs are the normal case, not the exception.
12–15 days

The Triage fee is credited in full against a Full audit of the same strategy booked within 30 days. Start small to see how we work; it costs you nothing extra to carry on.

How it works

It starts with a free 30-minute call. If you don't have what's needed to reproduce the result, we'll say so on that call and turn the work down — an audit that can't reproduce anything wastes your money and our time. Otherwise: you send the code, the data or access to it, and the result you're claiming. We quote one of the three prices above. You get the report, plus a follow-up call to walk you through it.

What we need from you, and what suits us best — formats, sizes and the markets we do and don't cover — so you can tell whether it fits before you write to us.

Who this is for

Whoever loses money if the number is wrong. A partner about to fund a strategy built in-house. An allocator checking a manager's track record. A treasury committee being shown a yield product. A founder raising money on a performance claim, before someone else checks it for them.

Arcobaleno Research Backtest forensics & research due diligence
We split the number into what actually produced it
dvt@arcobaleno.cloud

Start with a free 30-minute call. Tell us what the strategy is and what you have — code, data, and the result being claimed. If that isn't enough to reproduce anything, we'll tell you on the call and turn the work down.

Research due-diligence and code-audit services only. This is not investment advice, not a recommendation to buy or sell anything, and not an offer to manage money. Our findings say whether a stated result can be reproduced from the material supplied — they are not an opinion on how any strategy will perform in future. Every case study on this page describes a defect found in our own internal research; no client work is described. Figures are quoted as they appear in the dated internal documents named beneath each case.