Skip to content

DollarDecimal serialization can emit scientific notation (Kalshi may reject) #191

Description

@TexasCoding

Summary

_decimal_to_str(value: Decimal) -> str returns str(value). Python's Decimal.__str__ emits scientific notation whenever the adjusted exponent is >0 or <-6:

>>> str(Decimal('1E+10'))   # '1E+10'
>>> str(Decimal('0.0000001'))  # '1E-7'
>>> str(Decimal('100').scaleb(20))  # '1.00E+22'

The Kalshi API documents <dollars_string> and fixed-point count wire formats with positional digits (examples: "0.5600", "100.00"). Any Decimal whose representation lands in scientific form will be sent to the server as e.g. "1E-2", either rejected with a 400 or — worse — accepted by a permissive parser at a different numeric value.

The risk surface is small for current price ranges (typical Decimals '0.0001''1.0000' stay in positional form), but real for:

  • FixedPointCount on large batch orders (count_fp, volume_fp accumulated cost in big positions)
  • Any arithmetic the user performs on Decimals before passing them in (a.scaleb, a * b with mixed exponents)
  • Future high-precision fields the spec may add

Location

kalshi/types.py:31-33

Evidence

# kalshi/types.py
def _decimal_to_str(value: Decimal) -> str:
    """Serialize Decimal back to string for API requests."""
    return str(value)

Recommended fix

Format positionally:

def _decimal_to_str(value: Decimal) -> str:
    return f'{value:f}'  # forces fixed-point, never scientific

Decimal.__format__('f') handles all finite Decimals correctly and is the documented positional format. Add unit tests covering:

  • Decimal('1E+10')'10000000000'
  • Decimal('1E-7')'0.0000001'
  • Decimal('0').scaleb(20)'0E+20'-like input → positional
  • Decimal('0.5600') round-trip preserves trailing zeros (existing behavior)

Document the positional guarantee in CHANGELOG.

Severity & category

high / correctness

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions