Risk Level
HIGH
Location
core/src/exchanges/kalshi/normalizer.ts:167,176 and core/src/exchanges/kalshi/websocket.ts:261,328
Code
// normalizer.ts lines 166-168 (REST order book)
asks = (data.no_dollars || []).map((level) => ({
price: Math.round((1 - parseFloat(level[0])) * 10000) / 10000,
size: parseFloat(level[1]),
}));
// websocket.ts lines 260-262 (WS snapshot)
asks = (data.no_dollars_fp || []).map((level: [string, string]) => ({
price: Math.round((1 - parseFloat(level[0])) * 10000) / 10000,
size: parseFloat(level[1]),
}));
// websocket.ts line 328 (WS delta)
price = Math.round((1 - rawPrice) * 10000) / 10000;
Problem
Kalshi YES/NO markets require inverting NO prices to get the YES equivalent (yesPrice = 1 - noPrice). The subtraction 1 - parseFloat(...) is pure float arithmetic. Math.round(x * 10000) / 10000 is a band-aid that coerces the result to 4 decimal places but still via float multiplication and division.
These prices are stored in the live order book and used for quoting. A wrong price in the book means wrong spread, wrong best bid/ask, and wrong execution simulation.
Example Failure
noPrice string = "0.4450"
parseFloat("0.4450") = 0.445
1 - 0.445 = 0.5549999999999999 (IEEE 754: not 0.555)
* 10000 = 5549.999999999999
Math.round(...) = 5550
/ 10000 = 0.555 ← happens to be correct here
noPrice string = "0.3330"
1 - 0.333 = 0.6669999999999998
* 10000 = 6669.999999999998
Math.round(...) = 6670
/ 10000 = 0.667 ← correct by luck
noPrice string = "0.1115"
1 - 0.1115 = 0.8885000000000001
* 10000 = 8885.000000000001
Math.round(...) = 8885
/ 10000 = 0.8885 ← correct, but purely by luck; at 4dp the rounding is fragile
With 4 decimal places the band-aid usually works but is not guaranteed for all possible Kalshi prices.
Suggested Fix
import Decimal from 'decimal.js';
price: new Decimal(1).minus(level[0]).toDecimalPlaces(4).toNumber()
Found by automated float safety audit
Risk Level
HIGH
Location
core/src/exchanges/kalshi/normalizer.ts:167,176andcore/src/exchanges/kalshi/websocket.ts:261,328Code
Problem
Kalshi YES/NO markets require inverting NO prices to get the YES equivalent (
yesPrice = 1 - noPrice). The subtraction1 - parseFloat(...)is pure float arithmetic.Math.round(x * 10000) / 10000is a band-aid that coerces the result to 4 decimal places but still via float multiplication and division.These prices are stored in the live order book and used for quoting. A wrong price in the book means wrong spread, wrong best bid/ask, and wrong execution simulation.
Example Failure
With 4 decimal places the band-aid usually works but is not guaranteed for all possible Kalshi prices.
Suggested Fix
Found by automated float safety audit