Skip to content

orders: six order types send an optional tag in a different wire position depending on which encoder builds them #375

Description

@userFRM

Problem

Six order types put an optional tag in a different position depending on which encoder builds the message. The per-type encoders append it after tag 204; the shared extended-attribute encoder (send_order_ex) emits it in among the order-type tags, before 59.

Same tags, same values, different order:

MIDPX   own: … 40=MIDPX|59=0|167=STK|100=ISLAND|6210=ISLAND|15=USD|204=0|44=100
      shared: … 40=MIDPX|44=100|59=0|167=STK|100=ISLAND|6210=ISLAND|15=USD|204=0

TRAIL   own: … 40=P|99=0.5|211=0.5|18=a|59=0|…|204=0|6117=90
      shared: … 40=P|99=0.5|211=0.5|18=a|6117=90|59=0|…|204=0

Affected, and the tag that moves:

type tag
MIDPX 44, the price cap
PEG MKT 211, the offset
PEG MID 211 and the two mid-offset tags 8403/8404
TRAIL, TRAIL LIMIT, TRAIL PCT 6117, the initial stop trigger

Which path an order takes depends only on whether the caller set an extended attribute or a non-DAY time-in-force, so the same order type goes out with two different field orders depending on something unrelated to its type.

The per-type encoders are the ones carrying capture citations for these tags — ib-agent#173 for 6117, and the position after 204 is what the other per-type arms use. So the shared encoder is the one that differs from what was observed.

Impact

Any order of those six types carrying an extended attribute — a bracket link, an OCA group, outside-RTH, a GTD expiry, or simply a non-DAY tif — is sent with a field order the capture does not show. The other fifteen order types are byte-identical between the two paths, so this is not a general "field order does not matter" situation; it is six arms that were written differently from their siblings.

Whether the gateway is order-sensitive for these particular tags is not established. That is the reason to make them agree rather than to assume it does not matter.

Solution

Emit the optional tags after 204 in send_order_ex, where the per-type encoders put them, so both paths produce the same message. Cover it with a test that encodes each type both ways and compares the frames, so the two cannot separate again.

Notes

Read from v0.7.1 (9367845). Reproducible offline by encoding each type through both paths and comparing the frames with the sequence number and timestamps removed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions