Appendix: RALF Protocol Reference¶
Status: Normative. This appendix is the single source of truth for the RALF wire contract as implemented by
pm-ralf-gwy(ralf_gateway/). For an operational, tutorial-style guide see Post-Trade Dissemination; for the gateway's configuration block see Engine Config Specification §6.4.
1. What RALF is¶
RALF (Reconciliation ALF) is EduMatcher's text post-trade dissemination
protocol. It streams executed-trade and end-of-day events over TCP to external
back-office consumers (clearing, drop-copy, audit). It is served by pm-ralf-gwy,
which subscribes to the engine event bus and re-publishes derived events as RALF
lines. RALF is read-only: clients subscribe and receive; they never submit orders.
2. Scope & conformance¶
This document defines the client-visible wire behaviour of RALF version token
RALF1: framing, message set, fields, roles, sequencing, timeouts, and errors. The
key words MUST, MUST NOT, SHOULD, and MAY are used per RFC 2119.
A conforming client or gateway MUST implement the message set in §6 with the field
constraints in §6 and §10. Behaviour not stated here is unspecified. Where the
current implementation deviates from what a robust protocol would require, the
deviation is called out with a ⚠ Known deviation note and tracked in the
project's suspected-bugs report.
3. Transport & session model¶
| Property | Value |
|---|---|
| Transport | TCP |
| Default port | 5580 (post_trade_gateway.port) |
| Encoding | UTF-8 text lines |
| Delimiter | \n |
| Version token | RALF1 |
| Connection model | long-lived, one authenticated session per connection |
| Direction | gateway → client for all data; client → gateway for control only |
A session proceeds: connect → HELLO → WELCOME → one or more SUB/UNSUB →
event stream + heartbeats → EXIT/disconnect. A client MUST send HELLO before
any other message; a non-HELLO first message is rejected with
ERR|CODE=AUTH_REQUIRED.
4. Wire format¶
Every message is one line:
MSGTYPEMUST be uppercase ASCII fromA-Z,0-9,_.- Fields are
|-delimited; each field is split into key/value on the first=. - A parser MUST ignore unknown fields (forward compatibility) except where a field is required for validation.
- Values do not contain
|or\n.
Reserved cross-message keys (present on most messages):
| Key | Meaning |
|---|---|
CH |
Channel: CLEARING, DROP_COPY, or AUDIT |
SYM |
Symbol filter (control) or event symbol (data); * = all |
SEQ |
Channel-local monotonic message sequence (see §8) |
TS |
UTC ISO-8601 timestamp with milliseconds and Z suffix |
5. Message catalog¶
| Message | Direction | Purpose |
|---|---|---|
HELLO |
client → gw | open session; authenticate role; optional replay checkpoint |
WELCOME |
gw → client | session accepted; negotiated parameters |
SUB |
client → gw | subscribe channel(s) × symbol scope |
UNSUB |
client → gw | remove subscriptions |
SNAP |
gw → client | subscription/recovery baseline (carries current SEQ) |
EXEC |
gw → client | one executed trade (post-trade view) |
EOD |
gw → client | end-of-day per-symbol summary marker |
HB |
gw → client | heartbeat when the stream is quiet |
PING / PONG |
client → gw / gw → client | liveness probe and reply |
EXIT |
gw → client | session terminated (e.g. idle timeout) |
ERR |
gw → client | protocol, entitlement, or replay error |
6. Message definitions¶
HELLO (client → gateway)¶
| Field | Type | Req | Constraints |
|---|---|---|---|
CLIENT |
string | ✔ | external client identifier (logging) |
PROTO |
string | ✔ | MUST equal RALF1 |
ROLE |
enum | ✔ | one of CLEARING, DROP_COPY, AUDIT; MUST be in the gateway's allowed_roles |
LASTSEQ |
int | – | replay checkpoint; requests events with SEQ > LASTSEQ (see §8) |
Missing CLIENT/PROTO/ROLE → ERR|CODE=AUTH_REQUIRED. A ROLE outside
allowed_roles → ERR|CODE=ENTITLEMENT_DENIED. A non-integer LASTSEQ →
ERR|CODE=BAD_MESSAGE.
WELCOME (gateway → client)¶
| Field | Meaning |
|---|---|
PROTO |
negotiated version (RALF1) |
GW |
gateway id (post_trade_gateway.name) |
ROLE |
accepted role |
REPLAY |
replay retention window, seconds (replay_retention_sec) |
HBINT |
heartbeat interval, seconds (heartbeat_interval_sec) |
SUB / UNSUB (client → gateway)¶
| Field | Type | Req | Default | Constraints |
|---|---|---|---|---|
CH |
csv of channels | ✔ | — | each ∈ {CLEARING,DROP_COPY,AUDIT}; entitlement checked (§7) |
SYM |
csv of symbols or * |
– | * |
scope filter |
A subscription is the set of (channel, symbol) pairs. SUB is cumulative; UNSUB
removes matching pairs and is idempotent. After a SUB, the gateway emits one SNAP.
A missing/empty CH → ERR|CODE=INVALID_CHANNEL; an unknown channel →
ERR|CODE=INVALID_CHANNEL; a channel the role may not access →
ERR|CODE=ENTITLEMENT_DENIED.
SNAP (gateway → client)¶
Baseline emitted after a SUB and on replay-miss recovery. Carries CH (the
subscribed channels, comma-joined), SYM, SEQ (the highest current sequence over
the CH set in that SNAP), and TS. RALF SNAP carries no book/position
state — it is a sequence baseline only.
EXEC (gateway → client)¶
One line per executed trade, per subscribed channel.
| Field | Description |
|---|---|
CH SYM SEQ TS |
envelope (§4) |
EXEC_ID |
execution id (engine trade id) |
MATCH_ID |
match id — identical to EXEC_ID in RALF1 |
BUY_ORDER_ID / SELL_ORDER_ID |
resting/aggressing order ids |
BUY_GW / SELL_GW |
buy-side / sell-side gateway ids |
SIDE |
aggressor side (BUY/SELL) |
QTY |
executed quantity |
PX |
execution price (display units) |
A single trade is emitted once per channel (CLEARING, DROP_COPY, AUDIT),
each copy consuming its own SEQ (§8).
EOD (gateway → client)¶
Per-symbol end-of-day marker, derived from the engine system.eod broadcast.
| Field | Description |
|---|---|
CH SYM SEQ TS |
envelope |
TRADE_COUNT |
trades seen for the symbol this session |
EXEC_COUNT |
execution count — identical to TRADE_COUNT in RALF1 |
EOD is emitted once per symbol on all three channels:
CLEARING, DROP_COPY, and AUDIT.
HB, PING/PONG, EXIT¶
HB|TS=… is sent to authenticated clients when the stream is otherwise quiet
(cadence HBINT). A client MAY send PING; the gateway replies PONG|TS=….
EXIT|REASON=…|TS=… signals gateway-initiated termination (e.g. idle_timeout).
7. Roles & entitlements¶
Roles and channels share the same three names. Entitlement rules:
| Role | May subscribe to |
|---|---|
CLEARING |
CLEARING only |
DROP_COPY |
DROP_COPY only |
AUDIT |
any channel (CLEARING, DROP_COPY, AUDIT) |
A role subscribing outside its entitlement receives ERR|CODE=ENTITLEMENT_DENIED.
Only roles listed in post_trade_gateway.allowed_roles may authenticate.
8. Sequencing & recovery¶
SEQ is maintained per channel (CLEARING, DROP_COPY, AUDIT).
- Within one channel,
SEQis strictly increasing by 1 per emitted line. - Across different channels,
SEQvalues are independent and are not globally ordered or globally unique. - Clients MUST do gap detection and ordering within a given
CHstream, not across mixed channels.
LASTSEQ in HELLO is a single integer checkpoint. The gateway applies that same
threshold to each entitled channel independently and replays events where
event.SEQ > LASTSEQ for that event's channel.
Replay. If HELLO carries LASTSEQ, the gateway attempts to resend journalled
events with SEQ > LASTSEQ (per channel, as above) and only for channels the role
is entitled to receive (§7). If LASTSEQ predates the retained journal window for
any entitled channel (replay_retention_sec), the gateway emits
ERR|CODE=REPLAY_MISS followed by a SNAP baseline; the client MUST reset to that
baseline.
⚠ Known deviation — replay is entitlement-filtered but not subscription-filtered
Replay happens during HELLO, before any SUB is processed, so replay cannot
apply symbol/channel subscription state from the current connection. The current
gateway filters replay by role entitlement (§7), but does not filter by
subscriptions.
9. Liveness & timeouts¶
| Parameter | Source | Default |
|---|---|---|
Heartbeat interval (HBINT) |
heartbeat_interval_sec |
1 s |
| Idle timeout | idle_timeout_sec |
5 s |
Replay retention (REPLAY) |
replay_retention_sec |
86400 s |
The gateway sends HB when no other line has been sent within the heartbeat
interval. A session with no inbound activity for the idle timeout is dropped
(EXIT|REASON=idle_timeout). A client whose outbound queue exceeds
max_client_queue receives ERR|CODE=SLOW_CLIENT and is disconnected.
10. Error codes¶
| Code | Meaning / trigger |
|---|---|
AUTH_REQUIRED |
first message was not HELLO, or HELLO missing CLIENT/PROTO/ROLE |
BAD_MESSAGE |
unparseable line, unsupported message type, or malformed field (e.g. non-integer LASTSEQ) |
INVALID_CHANNEL |
SUB with missing/empty or unknown CH |
ENTITLEMENT_DENIED |
role not in allowed_roles, or channel outside the role's entitlement |
REPLAY_MISS |
requested LASTSEQ is older than the retained journal window |
SLOW_CLIENT |
outbound queue exceeded max_client_queue; session disconnected |
ERR carries CODE and a human-readable DETAIL, e.g.
ERR|CODE=REPLAY_MISS|DETAIL=requested seq outside retention.
11. Configuration reference¶
pm-ralf-gwy reads the post_trade_gateway block of engine_config.yaml
(consumed only by this process). Full field law is in
Engine Config Specification §6.4.
| Key | Default | Purpose |
|---|---|---|
name |
ralf-gwy01 |
gateway id in WELCOME\|GW= |
bind_address |
0.0.0.0 |
TCP listen address |
port |
5580 |
TCP listen port |
replay_retention_sec |
86400 |
journal window; advertised as WELCOME\|REPLAY= |
heartbeat_interval_sec |
1 |
HB cadence; advertised as WELCOME\|HBINT= |
idle_timeout_sec |
5 |
inbound-idle disconnect |
max_client_queue |
10000 |
outbound backlog before SLOW_CLIENT |
allowed_roles |
[CLEARING, DROP_COPY, AUDIT] |
roles permitted to authenticate |
12. Conformance notes¶
A conforming RALF1 implementation:
- derives events solely from engine broadcasts:
trade.executed→EXEC,system.eod→EOD. No other event families exist inRALF1. - MUST send
HELLO/WELCOMEbefore any data; MUST reject pre-auth data withAUTH_REQUIRED. - MUST enforce the §7 entitlement matrix on
SUB(live path). - MUST apply per-channel
SEQsemantics from §8 (no globalSEQstream). - MUST advertise
REPLAY/HBINTinWELCOMEmatching its configuration. - SHOULD treat replay as role-entitled but pre-
SUB(therefore not subscription-filtered) on reconnect.
Future revisions may add CORRECT, BUST, ALLOC, and SETTLE event families as
the corresponding engine events become available; they are not part of RALF1.
See also¶
- Post-Trade Dissemination — operational guide and client examples
- RALF Protocol Spy (pm-ralf-spy) — read-only CLI for inspecting the live wire format
- Processes — where
pm-ralf-gwysits - Engine Config Specification —
post_trade_gatewayfield law - External Protocols Overview — ALF/BALF/CALF/RALF at a glance