How attribute & float buckets are built
How the per-attribute (float / fade / pattern) buckets on the attribute-price endpoints are constructed, and why bucket widths differ per market.
Buckets are not an invented Skinpricer scheme. Each market is bucketed to match how that market itself segments the data, then anchored to the standard CS2 exterior bands.
buff163: Buff's own native float ranges
We ingest Buff's native float feed, so the float buckets ARE Buff's own non-uniform ranges (not fixed-width). The bands per exterior:
steamcommunity, marketcsgo, csfloat, dmarket: uniform 0.01 bins
These markets use uniform 0.01-wide bins across 0 to 1: bucketIndex = floor(floatValue * 100), min = index/100, max = (index+1)/100. e.g. Field-Tested on Steam is 0.15 to 0.16, 0.16 to 0.17, … 0.37 to 0.38. That's finer than Buff and a different scheme. Never assume a fixed bin width across markets.
Shared rules
Exterior clamping: every float bucket is scoped to the item's exterior band; a bucket never crosses an exterior boundary. Bands are half-open [min, max) (minInclusive: true, maxInclusive: false).
Beyond float: items are also bucketed by fade percentage and by pattern / paint-seed tier (Doppler phases and gems appear as variant / tag buckets). An item can carry combined float+fade ranges in one bucket.
Always read the per-bucket dimensions object for the exact min/max + inclusivity; don't infer bounds from the bucket label, since widths differ per market.
How do your buckets compare to other APIs?
They are not a single shared scheme. We mirror each market's own segmentation, so Buff buckets are non-uniform while Steam / others are uniform 0.01-wide. Normalize on dimensions.float.min / dimensions.float.max rather than matching labels across markets.
These buckets power /v1/attribute-prices/latest, its history, and the buff163-scoped latest / history reads.