When to Use
Use this skill when building or auditing an order path into Deutsche Börse Xetra
(MIC XETR) over the T7 Enhanced Trading Interface (ETI) — a little-endian
binary protocol with FIX 5.0 SP2 semantics. It covers the checks that must happen
on the client side, before a message leaves your process:
- Is the limit price on the RTS 11 tick for this instrument's liquidity band?
- Are the ETI field values in their documented numeric domains (
Side,TradingCapacity,OrderOrigination, short-code qualifiers)? - Is the price encoded as the scaled integer ETI actually carries?
- Is the 24-byte ETI request header framed correctly, with a gap-free
MsgSeqNum?
When NOT to Use
- Not a transport. Nothing here opens a socket, logs on to a gateway, or sends
an order.
ready_to_sendmeans "passed local validation", never "the exchange has it". Session establishment, throttling, heartbeats, and recovery are out of scope. - Not a full message encoder. It frames the header, not the message body. Body layouts are release-specific — take them from the ETI Cash Message Reference for the release you are certified against.
- Not a source of liquidity bands. The RTS 11 band is per-instrument reference data you must supply from the venue's Reference Data file. This skill will not guess it, because it cannot be inferred from the price.
- Not for Eurex derivatives. Eurex runs T7 too, but with its own message reference, product identifiers, and account-type conventions.
Prerequisites
- T7 ETI session and user credentials;
SenderSubIDis the T7 User ID. - Instrument reference data:
SecurityID(tag 48),MarketSegmentID(tag 1300), and the instrument's RTS 11 liquidity band (1–6). The ISIN is for human readability — the wire identifies instruments numerically. - Your firm's RTS 24 short codes, already uploaded to the venue's short/long code database with a valid-from date.
- The ETI Cash Message Reference for your target release.
Workflow
- Resolve the liquidity band before pricing anything. Read it from venue reference data. It changes annually: ESMA publishes ADNT figures and venues apply the new bands from the first Monday of April (RTS 11 Art. 3(4), as amended by Delegated Regulation (EU) 2023/960 — the original text said 1 April). On changeover, Xetra deletes resting orders whose limits no longer comply, so re-price or re-submit rather than assuming your book survived.
- Look up the tick in the RTS 11 Annex matrix — 19 price bands × 6 liquidity bands. Never from price alone. At €62.50 the tick is €0.01 in band 6 but €0.50 in band 1; a price-only rule silently accepts prices the venue rejects for illiquid names.
- Validate field domains before the tick check. An invalid quantity or side
makes the tick question meaningless, so report the first real defect rather than
a downstream symptom.
Side(tag 54) is1/2, not"BUY"/"SELL".TradingCapacity(tag 1815) is1Customer (Agency),5Principal (Proprietary),6Market Maker,9Riskless Principal,10Retail Customer (Agency) — numeric, and not the lettersP/A/M. - Encode the price as an integer with 8 implied decimals. ETI
PriceTypeis an 8-byte signed integer scaled by 10^8. Refuse a price that needs more than 8 decimals instead of rounding it — rounding sends a price the caller did not ask for. - Frame the header and advance
MsgSeqNumonly on success.BodyLenis the whole message length including the BodyLen field itself (24 + body). A rejected order must not consume a sequence number, because a gap is a session-level fault. - Pick a template that still exists. The R14.0 change log schedules
New Order Single (
10100) and its short layout (10125) for decommissioning with ETI 14.1 in mid-2026, naming New Order Single or Multi Leg (10138) and10139as replacements. Confirm against the reference for your release.
Full procedure: see
references/workflows.md. Standards reference: seereferences/standards.md. Printable pre-flight checklist: seeassets/checklist.md.
Common Pitfalls
- Treating the tick size as a function of price. This is the single most expensive mistake here. RTS 11 indexes the tick by price band and liquidity band. A hard-coded price-only ladder accepts off-tick prices for illiquid instruments and reports the wrong rounding increment even where the accept/reject verdict happens to agree.
- Float modulo for tick checks.
-5.0 % 0.001 == 0.0in Python, so a naive float check passes negative prices; and0.1as a float is0.1000000000000000055…, which is not a multiple of any tick. UseDecimal, and validate that the price is positive as its own check. - Sending
P/A/Mas the capacity. Those are leading characters of the ETIAccountfield (tag 1, valid characters1-9,A,G,M,P), which books positions. The MiFID capacity is the numericTradingCapacity(tag 1815). They are different fields with different purposes. - Assuming one "MiFID short code" field. There are several distinct fields:
OrderOrigination(1724, value5= order received from a direct access customer) flags DEA;ExecutingTrader(25123) withExecutingTraderQualifier(25124,22Algo /24Human) andPartyIdInvestmentDecisionMakerwith its qualifier (21222) carry the RTS 24 short codes. A short code only resolves if the matching long code was uploaded to the venue beforehand — unresolved combinations surface in the TR160/TR161/TR166 reports. - Burning a sequence number on a rejected order.
MsgSeqNummust increase by exactly one per request on a session. - Sending the ISIN as the instrument identifier. T7 ETI uses the numeric
SecurityID(tag 48) plusMarketSegmentID(tag 1300). - Conflating ETI with market data. ETI is order entry. Level 2 depth comes from the separate T7 Market Data Interface (MDI) multicast feeds.
- Copying field offsets across releases. Offsets and field widths change —
OrderQtymoved from 4 to 8 bytes between Release 5.0 and Release 14.0. Only the header layout has held stable.
Verification
rts11_tick_size("62.50", 6)$\implies$Decimal("0.01");rts11_tick_size("62.50", 1)$\implies$Decimal("0.5"). Both are read directly off the RTS 11 Annex row50 ≤ price < 100.- Instantiate
DeutscheBorseXetraApiEngine(sender_sub_id=98765). Submit an order forDE0007100000at €62.50, qty 500,liquidity_band=6,trading_capacity=5$\implies$STATUS_OK,price_eti_int == 6_250_000_000,side_wire_value == 1. - The same order at €62.503 $\implies$
INVALID_TICK_SIZE. At €62.53 withliquidity_band=1$\implies$INVALID_TICK_SIZE(tick €0.50). - Negative or zero price, non-positive quantity, an unknown side, and a letter
trading_capacity$\implies$INVALID_ORDER_FIELD, and none of them consume a sequence number. header.pack()$\implies$ exactly 24 bytes, withBodyLenat offset 0 andTemplateIDat offset 4, little endian.- Run
python -m unittest discover -s skills/deutsche-borse-xetra-api-integration/scripts.