Market Data & Drop Copy¶
Objective¶
Observe real-time market data with the current EduMatcher tools and understand where the engine's drop-copy feed fits into the architecture.
Background reading
Prerequisites¶
- Chapters 01–12 completed.
- Engine and at least one trader gateway active so events are visible.
Background¶
EduMatcher publishes two event streams from pm-engine:
- PUB :5556 — primary market data: books, trades, session state, order events.
- PUB :5557 — drop-copy feed: per-participant fill events for risk, compliance, and back-office consumers.
There is no separate pm-drop-copy process. The engine binds the drop-copy feed
itself when it starts.
Exercise 1: Open a Live Book Viewer¶
Start a live viewer for AAPL:
In a trader gateway, place or cancel a resting order and watch the viewer update:
Checkpoint: pm-viewer changes when the book changes.
Exercise 2: Run the Cross-Gateway Order Monitor¶
Start the order monitor:
Now place orders from both TRADER01 and TRADER02. The monitor should show
resting order state across gateways.
Checkpoint: pm-orders shows orders from multiple gateways.
Exercise 3: Capture Events with pm-audit¶
Start the audit logger in terminal mode:
Execute a trade:
Watch pm-audit print the resulting events. This is the easiest training-safe
way to observe the event stream without writing a custom ZMQ subscriber.
Checkpoint: audit output shows the trade/order lifecycle events.
Exercise 4: Confirm the Drop-Copy Feed Is Bound¶
Restart pm-engine --verbose (and then your trader and operator consoles, and
reopen the market) and look for this startup line in the engine output
(preceded by the usual timestamp, level and logger name):
That confirms the drop-copy publisher is active. It is intended for external
risk/compliance subscribers and publishes topics such as
drop_copy.event.<gateway_id>.
Checkpoint: you can identify the drop-copy socket in engine startup output.
Exercise 5: Watch the Drop-Copy Feed with pm-dc-spy¶
pm-audit, pm-viewer and pm-orders all read the public feed on port
5556 — none of them show the drop-copy feed. EduMatcher ships two tools for
that, and it is worth knowing both:
| Tool | What it is | Use it for |
|---|---|---|
pm-dc-spy |
A CLI that subscribes to the engine's drop-copy PUB socket (5557) | Looking at the feed yourself, right now |
pm-dc-gwy |
A gateway process serving the DC1 protocol over TCP 5590 | Letting an external system consume drop copy, the way a real back office would |
Start the spy:
Then submit a trade from a trader console and watch the fill events appear.
Checkpoint: pm-dc-spy prints a fill
event for a trade you caused, and you can say why an external consumer would
use pm-dc-gwy on 5590 instead of subscribing to 5557 directly.
Exercise 5b: Subscribe to the Raw Socket¶
Understanding what the tools do for you is worth one level down. Connect a
minimal ZMQ subscriber to the same socket pm-dc-spy reads:
The snippet needs the zmq Python package (pyzmq); in a container shell or a Poetry checkout use python/poetry run python, and with pipx use pipx runpip edumatcher's interpreter or pip install pyzmq in a virtual environment.
python - <<'PY'
import json
import zmq
ctx = zmq.Context()
sock = ctx.socket(zmq.SUB)
sock.connect("tcp://127.0.0.1:5557")
sock.subscribe(b"drop_copy.event.")
print("listening on drop_copy.event.*")
for _ in range(10):
topic, payload = sock.recv_multipart()
msg = json.loads(payload)
print(topic.decode(), "seq=", msg.get("seq"), "gateway=", msg.get("gateway_id"),
"event_type=", msg.get("event_type"), "trade_ids=", msg.get("trade_ids"))
PY
While this is running, execute a trade from TRADER01 in another terminal:
You should see one drop_copy.event.<gateway_id> message per participant on
each side of the trade, stamped with a seq that counts that gateway's own events (each gateway has its own counter starting at 1, so the two sides of one trade carry numbers from different streams).
Each message also carries trade_ids, the durable public trade ID that lets a
risk or clearing consumer correlate its private execution with trade.executed.
Checkpoint: you received at least one drop-copy message directly from port 5557, distinct from anything pm-audit printed on port 5556.
Exercise 6: Compare Public Events and Drop-Copy Purpose¶
Execute another trade and compare what each consumer is for:
| Consumer | Source | Purpose |
|---|---|---|
pm-viewer |
PUB :5556 | Human-readable book view |
pm-orders |
PUB :5556 | Cross-gateway resting order monitor |
pm-audit --terminal |
PUB :5556 | Full event stream for inspection/logging |
| External drop-copy client | PUB :5557 | Per-participant fill feed for risk/compliance |
Checkpoint: explain why drop-copy is separate from the public market-data stream.
Exercise 7: Launch the Market Board¶
Start the multi-symbol dashboard:
pm-board is a pure market-data subscriber: it builds its table from the live
book.* and trade.executed topics only and does not read stats.db. It
auto-rotates pages every --interval seconds; Enter, PgUp and PgDn page
manually.
Checkpoint: board shows AAPL, MSFT, and TSLA in one view.
Key Architecture¶
flowchart LR
E[pm-engine]
E -->|PUB :5556| V[pm-viewer / pm-orders / pm-audit / pm-stats]
E -->|PUB :5557| DC[external drop-copy consumers]
V --> B[pm-board / pm-ticker]
Reflection¶
Why does the engine publish drop-copy events on a separate socket
(:5557) rather than mixing them into the same :5556 PUB feed that
viewers, orders, audit, and stats all subscribe to? What operational problem
would arise for a compliance drop-copy consumer if it shared a socket with
high-volume book/viewer traffic?
Further Reading¶
- Messages
- Drop Copy
- Drop-Copy Gateway (
pm-dc-gwy) - Drop-Copy Spy CLI (
pm-dc-spy) - Processes, Environment and Ports
- CALF Protocol Reference
- Market Data Feed
Next: 14 — AI Traders & News
For a fuller hands-on tour of every viewer and observer process, see 18 — Exchange Observer Processes.