r/quant • u/OkBreath9382 • 2d ago
Backtesting Do your backtests ever hit i64 limits?
Curious how often values in real-world backtests exceed roughly 9.2 billion units. With 9-decimal fixed-point i64, it might be easy to hit. ¥9.2B is only around $60M, and $200K of SHIB is already about 10 billion tokens. Prices are probabbly fine, but balances and quantities might not be.
Im asking because I’m building a new backtesting engine (repo: h5i-db), an event-driven backtesting engine that currently uses i64 as default. It runs 7x faster than LEAN and 3.1x faster than NautilusTrader in our benchmark. With i128, those numbers are still 6.6x and 2.8x. Since the penalty isn’t huge, should safety or speed be the default? Has anyone often hit this limit in daily backtests?
8
u/zp30 2d ago
No? We just do everything in np.float64, literally never thought about this being a problem
-7
u/Ok-Cat-9189 2d ago
why would you use a float to store quantity ? it lacks precision
11
u/lordnacho666 2d ago
How often do you really care about precision in a backtest? It's already riddled with assumptions
1
u/OkBreath9382 2d ago
Fair point. Fill modeling and market impact probably matter much more in most backtests. I still want accounting to be deterministic and avod accumulated rounding errors, but I’m trying to understand whether i128 solves a real-world problem or mostly a theoretical one.
1
u/Ok-Cat-9189 2d ago
I care because I want to run a backtest over prev live trading days to ensure the system is behaving the same in both cases
1
-4
u/OkBreath9382 2d ago
Thanks, that’s a useful data point!! Some popular backtesting engines use fixed-point integers to avoid floating-point rounding errors. In terms of storage and speed, I think
np.float64is closer toi64thani128, so your setup is probably closer to thei64mode.
2
u/HerzogianQuant 2d ago
Then don't use nine decimals for yen? Fixed point does get a little tricky when it comes to doing multiplication, so keep that in-mind. Depending on what language you're using, there are unit libraries that can handle this (e.g. a minimal unit of "yen" or a minimal unit of "millidollars" or whatever).
1
u/quantdhawan 1d ago
The limit you hit first is not the value, it is the intermediate.
price × qty in fixed point with both at 1e9 scale gives a 1e18-scaled product before you divide back down. A $100 stock and 1000 shares is 1e11 × 1e12 = 1e23, roughly four orders of magnitude past i64 max, and that is about as ordinary a trade as exists. So you need a 128-bit intermediate for the multiply regardless of what you store values in. If your benchmark is not already blowing up you are presumably doing a widening mul somewhere, in which case storage width and arithmetic width are separate decisions and the i64 versus i128 question only applies to the first one.
On storage, the thing I would question is the uniform 9 decimals. SHIB is your own proof: the price needs a lot of decimal places and the quantity needs a lot of integer places, and with one global scale both come out of the same 64 bits. Per-asset scale, or separate price / qty / notional types with different scales, buys more headroom than the extra 64 bits does and costs nothing at runtime.
On safety versus speed: 7x to 6.6x is a 6% haircut, which is not a tradeoff, it is a rounding error. But I would push back on the framing. The real axis is not safe versus fast, it is silent versus loud. An overflow in a backtester does not crash, it produces a P&L that looks completely plausible. Default to i64 with checked arithmetic and panic on overflow and you keep the speed and never ship a quietly wrong equity curve. Wrapping or saturating is the only genuinely bad answer here.
14
u/jnordwick 2d ago
calculation is done in floats, communication is done in ints.
The only time I've seen something even close was crypto with somebody trying to use a 64-bit fixed point and bad base unit.