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.
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:
Affected, and the tag that moves:
MIDPXPEG MKTPEG MIDTRAIL,TRAIL LIMIT,TRAIL PCTWhich 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#173for 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.