Configuring & Starting Up¶
Objective¶
By the end of this chapter you will have a working exchange with at least one gateway and three tradeable symbols, ready to accept orders. In addition you have become familiar with the three tools:
pm-config-genused to automatically generate configuration file based on options and flags.pm-cverifierused to verify an existing (possibly hand-crafterd) configuration file for errors or missing settingspm-config-deployused to compile a verified configuration file and install it as the artifactpm-engine/pm-scheduleractually read
Background reading
Prerequisites¶
- EduMatcher installed and
pm-setupcompleted (see 00 — Installation & Setup).
Background¶
EduMatcher requires two essential processes:
- pm-engine — the matching engine.
- pm-scheduler — drives session phase transitions.
A gateway (pm-alf-console) connects traders to the engine.
Neither process reads engine_config.yaml directly, and neither accepts a
config path on its command line. engine_config.yaml is the file you
author and edit; what they actually read is a compiled artifact at
$EDUMATCHER_DATA_DIR/ref_data/engine_config.json, produced by
pm-config-deploy (see 00 — Installation & Setup for
where that directory comes from). This chapter's exercises follow that exact
pipeline: author → verify → deploy → start.
The artifact carries its own tamper and staleness checks: every load recomputes a SHA-256 over the artifact's own content and refuses to start if it no longer matches what was recorded at compile time, and every process separately checks the artifact's recorded hash of the source YAML against the YAML currently on disk, warning (but still starting) if you edited the source and forgot to redeploy. Exercise 12 walks through both.
Exercise 1: Create a Minimal Configuration¶
Create a file called engine_config.yaml in your working folder (the one you
set up in chapter 00; on the container route that is
~/.edumatcher/data/training on your computer, which you reach as
/data/training after cd /data/training inside ./edumatcher.sh shell).
Every file this chapter and the next ones create or edit — generated.yaml,
schedule.yaml, mm_aapl.yaml and the rest — lives in that same folder, and
every command that reads one is run from it.
symbols:
AAPL:
tick_decimals: 2
last_buy_price: 150.00
last_sell_price: 150.00
MSFT:
tick_decimals: 2
last_buy_price: 420.00
last_sell_price: 420.00
TSLA:
tick_decimals: 2
last_buy_price: 250.00
last_sell_price: 250.00
participants:
- id: TRADER01
description: "Alice — first trader"
role: TRADER
- id: TRADER02
description: "Bob — second trader"
role: TRADER
- id: GW_ADMIN
description: "Exchange operator"
role: ADMIN
- id: ADMIN_CLI
description: "One-shot command-line operator"
role: ADMIN
Use GW_ADMIN for the interactive pm-admin console and
ADMIN_CLI for pm-admin-cli. Each configured participant ID can have only
one live connection; attempting to use GW_ADMIN from both tools at once is
refused with Gateway already connected: GW_ADMIN.
Why tick_decimals, not tick_size
A symbol's price granularity is given as a number of decimal places,
not a tick size: tick_decimals: 2 means prices move in units of 0.01.
The engine matches on integer ticks internally, which is why it is
expressed this way.
last_buy_price / last_sell_price seed the reference price used by the
price-collar checks. Without them a symbol has no reference and its collar
is never enforced — which is exactly the trap Chapter 11 Exercise 2 depends
on avoiding.
Keys the engine does not recognise — tick_size, last_price,
description on a symbol — are silently ignored rather than rejected, so
a typo here fails quietly. pm-cverifier in Exercise 3 is how you catch
that.
Checkpoint: file saved, YAML is valid (no tabs!).
This file is only the authored source — nothing reads it yet. pm-engine
will not see any of this until you compile and install it with
pm-config-deploy in Exercise 5.
Exercise 2: Generate a Config with pm-config-gen¶
Instead of writing YAML by hand, you can use the pm-config-gen helper to
scaffold a configuration. Try generating an equivalent config:
pm-config-gen \
--symbols AAPL MSFT TSLA \
--symbol-opts AAPL:tick_decimals=2 \
--symbol-opts MSFT:tick_decimals=2 \
--symbol-opts TSLA:tick_decimals=2 \
--participants TRADER01:TRADER TRADER02:TRADER GW_ADMIN:ADMIN ADMIN_CLI:ADMIN \
--static-band 0.10 \
--dynamic-band 0.05 \
--sessions-enabled \
--output generated.yaml --force
This writes generated.yaml beside your hand-written file — it does not
replace it — with:
- Three symbols (AAPL, MSFT, TSLA) with 2-decimal tick precision.
- Two trader gateways and two admin gateways (one for each operator client).
- Static and dynamic price collars pre-configured.
- Session schedule enabled (PRE_OPEN → CONTINUOUS → CLOSED).
Inspect the generated file:
Compare it with your hand-written engine_config.yaml. Two differences
matter. The generated file spells out many settings you left to their
defaults, with a comment on each — a good way to discover what can be
configured. And it has no reference prices (last_buy_price /
last_sell_price): pm-config-gen cannot know what a stock is worth, and the
verifier warns about it (C001) — run pm-cverifier generated.yaml once you
have met the verifier in the next exercise. Price collars and
several later exercises need those prices, so keep using your hand-written
engine_config.yaml for the rest of the training; generated.yaml is for
reference.
Dry-run mode
Add --dry-run to preview the output without writing a file:
Adding market-maker gateways
You can include MM gateways in the same command:
pm-config-gen \
--symbols AAPL MSFT TSLA \
--participants TRADER01 TRADER02 GW_ADMIN:ADMIN ADMIN_CLI:ADMIN MM_AAPL_01:MARKET_MAKER \
--enforce-mm-obligations \
--output mm-example.yaml --force
Chapter 02 explains what a market maker needs in the configuration.
Checkpoint: generated.yaml has the same three symbols and four participants as your hand-written engine_config.yaml.
Exercise 3: Validate the Config with pm-cverifier¶
Before starting runtime processes, verify the file:
Check the verdict and exit code:
Expected for this chapter config:
- Verdict is
WARN, with one warning,M032: no read-only API credential is defined underapi_gateways. That credential is what the browser dashboards use; this configuration starts no API gateway until Chapter 25, so you can leave the warning alone for now. Below it you will see a fewINFOadvisories (M004,C003,C004,C007) — suggestions, not problems. - Exit code is
0when there are no warnings/errors,1when warnings exist, and2when hard errors exist. Here it is1, because ofM032.
Run it on generated.yaml as well and compare: that file has the same
M032, plus the C001 warning about the missing reference prices that
Exercise 2 told you to expect.
CI-style validation
Treat warnings as failures and emit machine-readable output:
Focus only on actionable items
Hide info-level advisories while iterating:
Checkpoint: you can run pm-cverifier, read the verdict, and interpret its exit code.
Exercise 4: Practice Fixing Verifier Findings¶
Create a temporary broken config and use pm-cverifier to diagnose it:
Edit engine_config.bad.yaml and intentionally introduce two issues:
- Remove the
GW_ADMINgateway entry. - Set one symbol's
tick_decimalsto an invalid value like12.
Run verifier:
You should see only one finding:
S010error (invalidtick_decimals).
Where is the missing admin gateway? The verifier works in layers — YAML
syntax, then the schema of every field (S codes), then the rules between
fields (M codes), then completeness advice (C codes) — and it stops after
the first layer that finds an error, because later checks would be judging a
file it already knows is broken. Fix tick_decimals and run it again: now
you see
M013warning (no gateway with roleADMIN), alongside theM032warning from Exercise 3.
Both M013 and the M032 you already know are now reported. Put the
GW_ADMIN entry back and rerun until only M032 remains.
Checkpoint: you can reproduce a verifier finding, map it to a check code, and clear it by fixing the config.
Exercise 5: Compile and Deploy the Config with pm-config-deploy¶
Verified YAML is still just a file on disk — no process reads it until it is compiled and installed. Check that it compiles without installing anything:
Expected output:
Now actually deploy it:
Expected output:
Compiled /home/you/training/engine_config.yaml
to /Users/you/.local/share/edumatcher/ref_data/engine_config.json
3 symbol(s), 3 gateway(s).
Restart any running processes to pick it up.
Confirm where it landed:
Expected behavior:
--checkvalidates and reports symbol/gateway counts but writes nothing- deploying overwrites the previous
ref_data/engine_config.jsonatomically — a process reading it mid-deploy sees either the old configuration or the new one, never a half-written file - if
engine_config.yamlfails validation, deploy fails and prints[ERROR] ...followed byNothing was deployed.; any previous deployment is left untouched - deploying does not restart any already-running
pm-engine/pm-scheduler— they must be (re)started to pick up the new artifact, which Exercise 6 does next
Checkpoint: you can explain, in one
sentence, the difference between engine_config.yaml and
$EDUMATCHER_DATA_DIR/ref_data/engine_config.json.
Exercise 6: Start the Engine¶
Open a terminal and run:
pm-engine takes no config path on its command line — it always reads
whatever is currently deployed at $EDUMATCHER_DATA_DIR/ref_data/engine_config.json,
which is exactly the artifact Exercise 5 just installed.
--verbose shows the engine's informational log lines; without it the engine
prints only warnings and errors. Expected output includes lines like these
(timestamps and paths will differ):
... INFO edumatcher.engine.main - Loaded config from .../ref_data/engine_config.yaml (3 symbol(s): AAPL, MSFT, TSLA; 3 gateway id(s))
... INFO edumatcher.engine.main - Session handling: enabled (startup state: CLOSED)
... INFO edumatcher.engine.main - Listening on PULL=tcp://127.0.0.1:5555 PUB=tcp://127.0.0.1:5556
Session handling: enabled means the engine starts in the CLOSED phase and
waits to be told when the day begins: your configuration does not set
sessions_enabled, and its default is true.
If monitoring is configured but pm-monitor is not running, the
pm-monitor … not accepting beacons diagnostic is DEBUG and appears only when
you start a process with -vv. It is rate-limited and does not affect the
exchange.
The stable way to confirm the engine actually loaded your config, independent
of log wording, is to query it from a gateway once connected (Exercise 8) with
SYMBOLS — if it lists AAPL, MSFT, and TSLA, the engine started correctly
regardless of what the startup banner said.
Checkpoint: engine is running without errors.
Exercise 7: Start the Scheduler¶
In a second terminal:
Like the engine, the scheduler prints only warnings and errors unless you pass
--verbose. It runs one day's timetable from the deployed configuration
and exits when the day ends. Your configuration has no schedule: block, so
the built-in weekday timetable applies (pre-open 09:00, opening auction
09:25, continuous 09:30, closing auction 16:00, closed 16:05; Saturdays,
Sundays and bank holidays closed). What you see therefore depends on when you
start it:
- inside trading hours it first catches up, sending the transitions that were already due, and then waits for the next one:
- on a weekend it reports that the day is closed and exits at once;
- outside hours on a weekday it catches up straight to
CLOSED.
To skip the wait and drive the sequence immediately, restart it with --now:
Expected output (timestamps trimmed; between the transitions you also see a
Waiting 5s for … line, and a harmless pm-monitor warning may follow Done.):
... INFO edumatcher.scheduler.main - --now mode: sending all transitions with 5.0s delays
... INFO edumatcher.scheduler.main - -> PRE_OPEN
... INFO edumatcher.scheduler.main - -> OPENING_AUCTION
... INFO edumatcher.scheduler.main - -> CONTINUOUS
... INFO edumatcher.scheduler.main - -> CLOSING_AUCTION
... INFO edumatcher.scheduler.main - -> CLOSED
... INFO edumatcher.scheduler.main - Done.
--now starts the day's sequence from this moment instead of the configured
wall-clock times; --delay 5 gives you five seconds between phases.
--now runs the whole day
--now does not stop at continuous trading: it carries on through the
closing auction to CLOSED, about half a minute later, and exits. That is
fine for watching the phases go by, but afterwards the market is closed
and orders are rejected with MARKET_CLOSED. Exercise 10 shows how to
open it again by hand, which is how the following chapters keep it open.
If nothing was deployed
pm-scheduler refuses to guess a schedule the engine has never seen. If
Exercise 5 was skipped, it exits immediately with a fatal error naming
pm-config-deploy, instead of silently falling back to a built-in
timetable.
Checkpoint: you ran pm-scheduler --now and saw it send all five transitions, ending with Done.
Exercise 8: Connect a Gateway¶
In a third terminal:
You should see:
Gateway TRADER01 connected. — Alice — first trader Type HELP for commands. Tab=complete ↑↓=history Ctrl-A/E=line start/end
[TRADER01]>
Try typing ORDERS — it should report no resting orders for this gateway.
Checkpoint: gateway prompt is interactive and connected.
Exercise 9: Verify the Setup¶
From the gateway prompt, confirm the three symbols are available by attempting a tiny limit order:
If you have just done Exercise 7, the scheduler's --now day ended in CLOSED,
so you will see this first:
That is the engine working as designed, not a fault. Open the market in the next exercise (the last part of it, "Open the market for the chapters ahead"), then come back and send the same order again. Now you should see an acknowledgement (the order rests since no matching ask exists):
Repeat for MSFT and TSLA to confirm all three books are active.
Checkpoint: all three symbols accept orders (after the market is open).
Exercise 10: Connect the Operator Console¶
Two different consoles — this trips everyone up once
EduMatcher has two interactive consoles, and they accept different
commands. Mixing them up is the most common early mistake, because the
error is just Unknown command.
pm-alf-console |
pm-admin |
|
|---|---|---|
| Who it is | A trader | The exchange operator |
| Prompt | [TRADER01]> |
[GW_ADMIN|ADMIN]> |
| Commands | NEW, AMEND, CANCEL, STATUS, ORDERS, POS, QUOTE, QLEGS, SYMBOLS, SESSION, INDEX |
BOOK, ORDERS|GW=, HALT, HALT_SYM, RESUME_SYM, CANCEL_SYM, KILL|GW=, KICK, QCANCEL, SESSION|STATE=, SESSION_STATUS, SCHEDULE, GATEWAYS, VOLUME |
| Sees the whole book? | No — only its own orders | Yes |
A trader cannot inspect the order book, halt a symbol, or move the session.
Those are operator powers, and they live in pm-admin.
Throughout this guide, a prompt of [GW_ADMIN|ADMIN]> means "type this in
the pm-admin terminal"; anything else means the trader console.
In a fourth terminal, start the operator console. Note this is
pm-admin, not pm-alf-console:
GW_ADMIN must be a gateway with role: ADMIN in your configuration — your
hand-written file from Exercise 1 has one.
Now look at the order book, which no trader console can do:
You should see a book snapshot (possibly with the 1-lot bid from Exercise 9).
Try two more operator queries:
GATEWAYS lists every configured gateway and whether it is connected;
SESSION_STATUS reports the current trading phase.
Open the market for the chapters ahead¶
Chapters 02–05 need the market in continuous trading, whatever the time of
day. Stop pm-scheduler (Ctrl-C in its terminal) and move the phase yourself:
[GW_ADMIN|ADMIN]> SESSION|STATE=PRE_OPEN
[GW_ADMIN|ADMIN]> SESSION|STATE=CONTINUOUS
[GW_ADMIN|ADMIN]> SESSION_STATUS
SESSION_STATUS should now report CONTINUOUS. The engine only accepts the
phase changes of a real trading day, in order — from CLOSED the only legal
step is PRE_OPEN — so it takes two commands. Chapter 06 explains this
"freeze and advance" technique properly; whenever a later exercise says the
market must be open, this is how you open it.
Now go back to Exercise 9 and send the three 1-lot test orders (AAPL, MSFT, TSLA) if you have not yet.
Clear the test orders¶
Those three 1-lot bids at 0.01 are still resting, and they survive engine
restarts. Left in place, they would show up in the order books and in
ORDERS in every later chapter. Remove them with the operator's kill switch,
which cancels everything one gateway has resting (chapter 08 explains it):
It answers KILL OK TRADER01 orders=3 quotes=0; the cancellations also
show on the TRADER01 console as CANCELLED … reason=KILL_SWITCH.
Engine restarts disconnect your consoles
Several exercises below (and in later chapters) restart pm-engine. When
the engine connection is detected as lost, each console prints
Engine connection was lost; logging out. and exits. Consoles do not
reconnect by themselves, so start them again before continuing. See
"After every engine restart" in the
guide introduction.
Checkpoint: pm-admin is connected, BOOK|SYM=AAPL
shows the book, and you can state which of the two consoles a given command
belongs to.
Keep both terminals open from here on
Every later chapter assumes you have a trader console and an operator console available. Leaving both running saves restarting them — except after an engine restart, when each must be started again (see above).
Exercise 11: Inspect Enriched SYMBOLS Metadata¶
From any connected gateway:
Besides the symbol names, the table shows each symbol's tick size and its market-maker obligation settings — whether they are enforced, the maximum spread in ticks and the minimum quoted quantity:
Checkpoint: you can read the tick size and the market-maker settings of each symbol from the SYMBOLS output.
Exercise 12: Break — and Recognise — the Artifact's Hash Checks¶
The compiled artifact records two independent SHA-256 hashes in its meta
block: content_sha256 (the artifact against itself) and source_sha256
(the artifact against the engine_config.yaml it was built from). This
exercise reproduces both failures on purpose, so you recognise the real
message the first time you see it instead of the first time it costs you an
afternoon. See Configuration — Verifying the Deployed
Artifact
for the full explanation this exercise is drilling.
Part A — trip the content-digest check (an error).
In the engine's terminal, stop it with Ctrl-C. Then hand-edit the
deployed artifact directly — something pm-config-deploy never does and
nothing should:
python3 -c "
import json
p = '$EDUMATCHER_DATA_DIR/ref_data/engine_config.json'
data = json.load(open(p))
data['engine']['symbols']['AAPL']['tick_decimals'] = 4
json.dump(data, open(p, 'w'), indent=2)
"
Start the engine again in the same terminal:
Expected: the engine refuses to start. It prints a Python traceback; read its
last line, which reports that the compiled config's payload no longer
matches its recorded content digest and names pm-config-deploy, not manual
editing, as the fix.
Recover by recompiling the (untouched) source that is still sitting next to the artifact, then start the engine again:
(The engine restart disconnected your consoles; restart them before using them again.)
A second, different message can come from the same digest check
The content-digest check actually distinguishes two separate causes for
the same mismatch, and reports each with a different message. What you
just triggered — editing the payload's values — is reported as
compiled config has been modified since it was compiled (payload digest
... does not match the recorded ...). If instead the artifact's on-disk
bytes are untouched but a newer/older build of EduMatcher declares a
different set of configuration fields than the artifact was compiled
with, you get a different message: compiled config is intact but was
compiled against a different configuration schema ... Nothing has been
edited — run pm-config-deploy to recompile it. Both are fixed the same
way (pm-config-deploy), but only the second one means nobody touched
anything — the check tells the two apart by separately hashing the
payload exactly as it sits on disk, so don't go hunting for an edit that
never happened if you see that second message after, say, upgrading
EduMatcher itself without redeploying.
Part B — trip the source-staleness check (a warning).
Leave this engine running. In another terminal, edit the authored YAML and deliberately skip the deploy step — this only changes the file on disk, it does not affect the already-running engine:
sed -i.bak 's/tick_decimals: 2/tick_decimals: 3/' engine_config.yaml # changes every symbol: each has its own tick_decimals line
Now stop the engine (Ctrl-C) and start it again without redeploying:
Expected: the engine starts anyway, but logs a warning that
engine_config.yaml has changed since the running configuration was
compiled and that the exchange is still serving the previous one. Confirm
with SYMBOLS from a gateway (restart your trader console first, as the engine
was restarted) that the symbols still report the old tick size (0.01, not
0.001) — the warning told the truth, nothing was silently applied.
Restore the file and redeploy to clear the warning:
Why the two checks fail differently
A hand-edited artifact is refused outright because a process cannot tell
a malicious edit from a benign one, and either way the file no longer
means what it claims to. A stale source file is only a warning because
the deployed artifact is still perfectly valid — you just have an edit
sitting uncommitted next to it. pm-config-deploy is the only fix for
either case.
Checkpoint: you have seen both the content-digest error and the source-staleness warning fire for real, and can state which of the two blocks startup and which only warns.
Exercise 13: Weekday / Weekend / Holiday Scheduling¶
Exercise 2's --sessions-enabled config (and your hand-written one) used the
built-in default schedule — the same five times every day, Monday through Friday, with
Saturday, Sunday and bank holidays all CLOSED. Real exchanges are rarely
that uniform: some run a short Friday, some trade weekends, and all of them
close (or shorten hours) on bank holidays that fall on an otherwise-ordinary
weekday. pm-config-gen can generate all three variations, and this
exercise walks through each. The generated files go to a separate
schedule.yaml, so your hand-written engine_config.yaml — the one with
reference prices that later chapters need — stays untouched.
Resolving which schedule applies to a given calendar day always happens in this order:
- If the day is a bank holiday in the configured
locale.country, theholidays:block applies — orCLOSED, if no--holidaysblock was generated. - Otherwise, the day's own entry applies:
mon..fri(fromweekdays:, unless overridden by--weekend) orsat/sun(fromweekend:, only if--weekendwas passed).
Any day left with no resolved entry — including Saturday and Sunday by
default — is CLOSED all day, exactly like today's config already leaves
them.
Add a weekend session.
By default pm-config-gen leaves Saturday and Sunday CLOSED. Pass
--weekend to give them their own (shorter) session:
pm-config-gen \
--symbols AAPL MSFT TSLA \
--symbol-opts AAPL:tick_decimals=2 \
--symbol-opts MSFT:tick_decimals=2 \
--symbol-opts TSLA:tick_decimals=2 \
--participants TRADER01:TRADER TRADER02:TRADER GW_ADMIN:ADMIN ADMIN_CLI:ADMIN \
--static-band 0.10 \
--dynamic-band 0.05 \
--sessions-enabled \
--weekend \
--weekend-pre-open 10:00 \
--weekend-opening-auction 10:25 \
--weekend-continuous 10:30 \
--weekend-closing-auction 14:00 \
--weekend-closing-end 14:05 \
--output schedule.yaml --force
Inspect the generated schedule: block — Saturday and Sunday now carry
their own five transition times instead of being absent.
Add a holiday session, and set the country.
Pass --holidays to give bank holidays a schedule of their own instead of
CLOSED (a common real-world case is a reduced half-day rather than a full
close). This command is the previous one plus the --holidays… and
--country flags, so the file it writes has all three features:
pm-config-gen \
--symbols AAPL MSFT TSLA \
--symbol-opts AAPL:tick_decimals=2 \
--symbol-opts MSFT:tick_decimals=2 \
--symbol-opts TSLA:tick_decimals=2 \
--participants TRADER01:TRADER TRADER02:TRADER GW_ADMIN:ADMIN ADMIN_CLI:ADMIN \
--static-band 0.10 \
--dynamic-band 0.05 \
--sessions-enabled \
--weekend \
--weekend-pre-open 10:00 \
--weekend-opening-auction 10:25 \
--weekend-continuous 10:30 \
--weekend-closing-auction 14:00 \
--weekend-closing-end 14:05 \
--holidays \
--holidays-pre-open 10:00 \
--holidays-opening-auction 10:25 \
--holidays-continuous 10:30 \
--holidays-closing-auction 13:00 \
--holidays-closing-end 13:05 \
--country DE \
--output schedule.yaml --force
--country is what tells pm-scheduler which calendar of bank holidays
to check a date against before it decides whether the holidays: block
even applies — it generates the locale.country key in the config's
locale: block. It accepts a country name ("Sweden") or an ISO 3166-1
alpha-2 code ("DE"), and it does only that — it has no effect on the
session timezone (that is the sibling locale.session_timezone key,
generated by --session-timezone, out of scope here). Get it wrong and the
consequence is silent, not a crash: an unrecognised value makes
pm-cverifier raise a M026 warning, and at runtime pm-scheduler logs a
warning and falls back to "Sweden" — so a Germany-based deployment left
at the default, or given a typo'd country name, will silently follow the
Swedish holiday calendar instead, trading straight through a local bank
holiday it should have been closed for (or vice versa). There is no
separate validation step for this — run pm-cverifier (Exercise 3) after
any change to locale.country or the schedule and read its output, don't
just deploy.
Verify the country was picked up. The summary should read Sessions enabled
— 7 of 7 days scheduled, holidays overridden, and there should be no M026
(the M032 and C001 warnings are the ones you already know, and this file
has no reference prices, as in Exercise 2):
Deploy it:
Restart pm-engine (Ctrl-C, then start it again) so that it reads the new
artifact, restart pm-admin (it was disconnected by the restart), and ask the
operator console for the schedule the engine is really running:
SCHEDULE prints the weekly table — five transition times for each of Mon–Sun
and a final Holidays column. Saturday and Sunday now read 10:00 / 10:25 /
10:30 / 14:00 / 14:05 and the Holidays column 10:00 / 10:25 / 10:30 /
13:00 / 13:05. (The trader console's SESSION only reports the current
phase, not the timetable.)
When you have seen it, put your training configuration back and restart the
engine, because schedule.yaml has no reference prices and Chapter 11 needs
them:
Restart pm-engine once more (Ctrl-C, then pm-engine), restart your trader
and operator consoles, and reopen the market with SESSION|STATE=PRE_OPEN and
SESSION|STATE=CONTINUOUS, as at the end of Exercise 10.
weekend: and sat:/sun: are mutually exclusive
--weekend generates a single shared block for both days. There is no
pm-config-gen flag for giving Saturday and Sunday different hours —
that requires hand-editing the generated sat:/sun: keys directly in
engine_config.yaml (see Session Scheduling — Configuring the
schedule).
A config that sets both weekend: and an individual sat:/sun: block
is rejected at load — they say two different things about the same day.
Checkpoint: generated config has a
weekend: block, a holidays: block, and locale.country: DE;
pm-cverifier reports no M026 warning; SCHEDULE in pm-admin shows the
weekend and Holidays columns filled in; and your hand-written
engine_config.yaml is the deployed configuration again.
Summary¶
You now have:
- A configuration file defining 3 symbols and 3 gateways.
- A repeatable verifier workflow (
pm-cverifier) to catch config problems before startup. - A compiled, deployed configuration (
pm-config-deploy) thatpm-engineandpm-scheduleractually read. - A running engine, scheduler, and at least one trader gateway.
- Confirmation that all symbols accept orders.
- Firsthand experience of the artifact's content-digest error and
source-staleness warning, and which fix (
pm-config-deploy) clears both. - A schedule with weekend trading, a bank-holiday session, and the correct
locale.countryfor its holiday calendar — and the ability to tell, frompm-cverifier, whenlocale.countryisn't one.
Reflection¶
Why does the engine, scheduler, and each gateway all run as separate processes connected over ZMQ sockets, instead of one monolithic program? What would you lose (or gain) operationally if the scheduler crashed while the engine kept running?
pm-engine and pm-scheduler never accept a config path, and neither reads
engine_config.yaml directly. What problem does forcing every process
through one compiled artifact (pm-config-deploy) solve that letting each
process parse its own copy of the YAML would not?
Exercise 12's two checks fail at different severities — one refuses to
start, the other only warns. Why is a hand-edited artifact treated as more
serious than a stale source file, given that both mean the running
configuration is not what engine_config.yaml currently says?
An unrecognised locale.country doesn't stop the config from deploying —
it only warns, both from pm-cverifier (M026) and from pm-scheduler at
runtime, then silently falls back to Sweden's holiday calendar. Why might a
design choose "warn and fall back" here instead of refusing to deploy, the
way an invalid or incomplete schedule block does? What's different about
getting locale.country wrong versus getting the schedule times wrong?