Skip to content

ield mein: best_5_buy_data and best_5_sell_data fields are swapped in SNAP_QUOTE (Mode 3) parsing #71

Description

@myaifairtrading-cyber

TITLE: best_5_buy_data and best_5_sell_data fields are swapped in SNAP_QUOTE (Mode 3) parsing

BODY:

Bug Description

In smartWebSocketV2.py, the _parse_binary_data method incorrectly swaps
the best_5_buy_data and best_5_sell_data keys after parsing them. The
internal parsing function correctly identifies buy vs sell levels using the
flag field (0 = buy, 1 = sell), but the final assignment swaps them:

best_5_buy_and_sell_data = self._parse_best_5_buy_and_sell_data(binary_data[147:347])
parsed_data["best_5_buy_data"] = best_5_buy_and_sell_data["best_5_sell_data"]   # ← swapped
parsed_data["best_5_sell_data"] = best_5_buy_and_sell_data["best_5_buy_data"]   # ← swapped

This means any application consuming parsed_data["best_5_buy_data"]
directly is actually receiving ASK-side (sell) levels, and
parsed_data["best_5_sell_data"] is actually receiving BID-side (buy) levels.

Why this is confirmed (not a misunderstanding of field naming)

  1. The internal _parse_best_5_buy_and_sell_data method correctly buckets
    levels by the flag field: flag == 0 appends to best_5_buy_data,
    flag == 1 appends to best_5_sell_data. This bucketing is correct
    per the SNAP_QUOTE packet spec.
  2. Immediately after this correct bucketing, the caller assigns the
    result keys in reverse — parsed_data["best_5_buy_data"] is set from
    the function's best_5_sell_data output, and vice versa.
  3. We confirmed this in production by comparing parsed values against the
    actual order book for liquid NFO futures contracts during market hours:
    prices coming out under the best_5_buy_data key were consistently
    HIGHER than prices under best_5_sell_data — which is only possible if
    the labels are inverted, since asks must be >= bids in a valid book.

Impact

Any consumer of this library that uses best_5_buy_data/best_5_sell_data
directly for spread calculation, order book imbalance, liquidity checks, or
order flow imbalance (OFI) computation will get inverted results — e.g. an
imbalance signal that should indicate buying pressure will read as selling
pressure, and vice versa. This is a silent correctness bug, not a crash,
so it's easy to miss without explicitly cross-checking price ordering.

Suggested Fix

Remove the swap in _parse_binary_data — assign directly without crossing
the keys:

parsed_data["best_5_buy_data"] = best_5_buy_and_sell_data["best_5_buy_data"]
parsed_data["best_5_sell_data"] = best_5_buy_and_sell_data["best_5_sell_data"]

Happy to provide a sample tick payload (with account-identifying details
redacted) demonstrating the price-ordering inversion if useful for
verification.

Note on backward compatibility

Since this bug may have existed for a while, some downstream applications
may have already written their own compensation logic (reading
best_5_sell_data as the true buy side and vice versa). Fixing this in
the library would silently break that compensation for existing users.
Recommend either:
(a) fixing it with a clear changelog/version bump and migration note, or
(b) adding a new correctly-labeled field set (e.g. bid_5_data/ask_5_data)
alongside the existing (buggy) ones, deprecating the old keys gradually.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions