25 min

Intraday liquidity: what immediacy costs

Gross settlement means each payment needs its full value in reserves at the moment it settles, so timing and ordering, not daily totals, set the liquidity bill.

Where you are. Module 1 handed you miniledger v1; this module has begun industrialising it. Lesson 1 built the workbench - six banks, thirty customers, and one seeded day of 300 payments that every rail in the module replays. Lesson 2 split clearing from settlement. Lesson 3 built the first engine: the RTGS rail, where each arriving payment settles at once, in full, in central-bank reserves, or waits in a strict first-in-first-out queue until reserves arrive. That lesson ran on a generous setting - enough reserves posted that the day closed with one payment delayed and a peak queue of one. This lesson asks the question a bank’s treasurer asks next: how much is enough, and what exactly is it buying?

Five runs, one number changed

Rerun lesson 3’s morning. Same rail, same slice of the seeded day - the first 50 payments, arriving between minute 7 and minute 244 - and only one number changed between runs: the opening endowment each of the six treasuries posts. Five levels, from a thin 500 per bank to a lavish 8,000, each replayed against a fresh world.

Every run ends green. assert_world passes five times: every settled payment landed as module 1’s three balanced postings, every sheet squares, total reserves are conserved to the unit. No error, no imbalance, no missing money, at 8,000 and at 500 alike. If correctness were the whole story, 500 would be the obvious setting and this lesson would be a footnote. Yet something plainly got worse at the thin end. At 2,000 and above, every payment settles the moment it arrives. At 1,000, seven miss their moment and three are still waiting at the close. At 500, eighteen miss their moment and sixteen never settle at all. Nothing failed; everything got later. The thing the thin runs lost is not on any balance sheet, and buying it back has a name and a price.

The idea in one paragraph

Intraday liquidity is the reserves a bank parks so its outgoing payments can settle the moment they arrive. Gross settlement is why the tank must be full: each payment needs its whole face value in central-bank money at its own settlement moment, not at the close - that was lesson 3’s rule - so what matters is never the day’s totals but the sequence, because every incoming payment refills the payer’s tank mid-day and every outgoing one drains it. A bank whose receipts happen to land just before its payments needs almost nothing parked; the same bank with the same totals in the opposite order needs cover for every gap. The reserves are not spent - at the close they are still there, shifted only by the day’s net - but holding them idle all day costs what they could otherwise earn, and the sweep you are about to run measures what each level of parking buys: fewer payments waiting, a shallower queue, nothing stranded at the close.

The bill is set by timing, not totals

The morning slice moves 12,678 in face value across the six banks - stylised units from the seeded fixture, as always. Two totals look like candidates for the bill, and both are wrong.

Gross outflow is the ceiling. Fir pays out 3,346 over the morning; if nothing ever flowed in, that is what Fir would need parked at open. But things flow in all morning - Fir also receives 2,447 - and each incoming settlement refills Fir’s reserves at that instant, ready to fund the next outgoing payment. That recycling is why 2,000 per bank settles the entire morning on arrival, even for Fir.

Net outflow is the floor. Dogwood pays out 3,221 and receives 1,808: net down 1,413 on the morning. However kindly the day is ordered, a bank that posts less than its net outflow cannot settle everything: reserves cannot go negative, so some of its payments must strand. Post 1,000 per bank and Dogwood sits below its floor - no ordering could save its whole morning.

Between the floor and the ceiling, ordering decides where the bill lands. That is the whole claim of this lesson’s summary line, and the fixture makes it concrete: the same 50 payments, the same totals, and the bill swings with nothing but the interleaving of ins and outs.

One bank’s day, drawn

Here is the shape of the trade, drawn from the whole seeded day rather than just the morning slice: Alder’s reserve level, minute by minute, replayed against two opening balances.

image/svg+xml Matplotlib v3.11.1, https://matplotlib.org/ 0 200 400 600 800 1000 1200 1400 minute of the day 0 1000 2000 3000 4000 one bank's reserves (stylised day) generous reserves: shallow dips thin reserves: the trajectory scrapes zero
one bank's reserve trajectory under generous and thin reserves

The generous line dips when Alder’s payments cluster and refills when receipts arrive, and it never comes near empty: every outgoing payment found the tank full at its moment. The thin line tells the other story. It hits zero early and then rides it, and each stretch spent scraping along zero is a stretch during which Alder’s outgoing payments could move only at the pace of its receipts - immediacy surrendered, minute by minute. Same day, same flows, same close; the only difference is how much of the day Alder’s payments spent waiting.

The sweep, row by row

Now the measurement. Replay the morning at all five levels and tabulate what each run cost - this is exactly what your exercise prints:

reserves posted | delayed (of 50) | unsettled at close | peak queue
            500 |              18 |                 16 |         16
           1000 |               7 |                  3 |          3
           2000 |               0 |                  0 |          0
           4000 |               0 |                  0 |          0
           8000 |               0 |                  0 |          0

Three columns, three symptoms of the same shortage. Delayed counts payments that missed their arrival moment - the latency bill. Unsettled at close counts the ones still sitting in the queue when the day ends: still promises, not yet facts, in lesson 7 of module 1’s terms. Peak queue is the deepest the backlog ever got. Read down any column and the story is monotone: posting more reserves never delays more payments.

The 1,000 row rewards a closer look. Seven payments missed their moment, four of those later settled from the queue as receipts refilled their banks, and three stranded. Two of the three are Dogwood’s - below its floor, doomed by arithmetic. The third is Fir’s, and its reason is nastier: at the close Fir holds 473, more than enough to cover its stranded payment of 372, but that payment sits behind Dogwood’s two in the strict first-in-first-out queue, and the rail only ever retries the head. A coverable payment stuck behind an uncoverable one. Hold that thought for lesson 6, which studies what happens when a whole cycle of banks ends up waiting like this, each unable to pay until it is paid.

And then the bottom rows: 2,000, 4,000 and 8,000 print identical zeros. Immediacy was fully bought at 2,000; the next 6,000 per bank buys nothing the table can see.

Review

Timing sets the bill, not totals

Two totals look like they should set the bill, and both are wrong. Gross outflow is the ceiling: what a bank would need parked at open if nothing ever flowed in. Net outflow is the floor: post less than that and reserves would have to go negative, so some payments must strand no matter how kindly the day is ordered. Between the floor and the ceiling, ordering decides where the bill lands. Take one bank, two payments, and a day that nets to zero either way: pay first and you need the money parked, receive first and the same immediacy is free. Identical totals, opposite bills.

Parked, not spent

The reserves a bank parks for the day are not consumed. At the close they are still there, shifted only by the day’s net. What they cost is what they could otherwise have earned while sitting idle, and that is the price of immediacy. Watch one bank’s reserve level minute by minute and the trade is visible. A generous opening balance dips when payments cluster and refills when receipts arrive, and never comes near empty. A thin one hits zero early and then rides it, and every stretch spent scraping along zero is a stretch where that bank’s payments could move only at the pace of its receipts.

Check yourself

1. The morning moves 12,678 in face value, and Fir alone pays out 3,346 - yet 2,000 per bank settles every payment on arrival. Where does the missing cover come from?

From the other payments. Every incoming settlement refills the payee bank’s reserves at that instant, and the refilled reserves fund the next outgoing payment. Fir receives 2,447 across the same morning, interleaved with its outflows, so its tank tops up repeatedly between payments. Gross outflow is what a bank would need if nothing ever flowed in - a ceiling, not the bill. The bill depends on when the inflows land relative to the outflows, which is the lesson’s whole point.

2. The 500 row reads 18 delayed but only 16 unsettled at close. What happened to the other two?

They settled from the queue. A delayed payment is not a dead payment: it waits in the FIFO, and after every settlement the rail retries the queue head, because that settlement moved reserves to some bank that may now cover it. Two of the eighteen were rescued that way when receipts refilled their banks; sixteen waited for inflows that never came in time. Delay is a spectrum - minutes for the lucky, the whole day for the stranded - and the two columns measure its two ends.

3. At 1,000, Fir closes the day holding 473 while its own payment of 372 sits unsettled. Why does the rail not simply settle it?

Because the queue is strictly first-in-first-out and the rail only ever retries the head. The head is Dogwood’s payment of 390, which Dogwood’s remaining 10 cannot cover, so everything behind it waits - including Fir’s perfectly coverable 372. The discipline that makes the queue fair also lets one uncovered payment block covered ones behind it. Lesson 6 studies the extreme of this: a cycle of banks each waiting to be paid before paying, and the offsetting trick that cuts through it.

4. The 2,000 row and the 8,000 row print identical zeros. In what sense is the 8,000 day four times as expensive?

The bill is not in the table. Both days bought total immediacy, but the 8,000 day parked an extra 6,000 per bank that bought nothing - zero delay was already zero. Parked reserves are priced by what the cash could otherwise earn in module 1’s parking spots, so the extra pile is pure carrying cost. The treasurer’s target is the smallest posting that still buys the immediacy the bank needs - which is why the trade-off deserves the finer sweep lesson 5 gives it.

5. The 500 run raised no error and assert_world passed, with sixteen payments stranded. Why is a green ledger not the same as a finished day?

The invariants police money, not time. Balanced postings, mirrored tiers, conserved reserves - every payment that settled obeyed all of them, and a queued payment breaks none of them, because it has not touched a ledger yet: it is still a promise, not a fact. Refusing to settle is always safe by correctness standards. The cost of thin reserves lives entirely in the clock, which is why liquidity has to be measured, not asserted.

Do this

Ten minutes, from module-02-domestic-rails. Two pieces from earlier lessons must be in place: the fixture (code/fixture_day.json, written by lesson 1’s workbench - if the script exits asking for it, run python3 code/rails_workbench.py first) and your completed offer from lesson 3’s code/rtgs_rail.py, which this script imports.

Open code/intraday_cost.py. run_day is written for you: it builds a fresh world at the given reserve level, replays the 50 payments through a fresh rail, and returns what the level cost as (delayed, unsettled, peak). The TODO(you) is the sweep loop: for each level in levels, call run_day - a fresh world every time, so the runs cannot contaminate each other - and collect one row (level, delayed, unsettled, peak), returned in levels order.

python3 code/intraday_cost.py

The table prints, then the asserts pin the shape of the trade: one row per level, posting more reserves never delays more payments, the 500 row waits more than the 8,000 row, and the top level empties the queue before the close. Green ends with the line

intraday liquidity is the price of immediacy: post fewer reserves and payments wait - timing and ordering, not daily totals, set the bill

The completed sweep is solutions/intraday_cost.py; compare after your run is green.

What you can now do. You can measure what settling everything immediately costs in parked reserves: replay the same day at any reserve level and read the three symptoms of thinness - payments missing their moment, a deepening queue, promises stranded at the close - and explain why the bill lands between a floor set by each bank’s net outflow and a ceiling set by its gross, at a point chosen by nothing but the ordering of flows. You can also say what the money spent on immediacy actually is: not money spent at all, but money parked, priced by what it could otherwise earn. Two loose threads lead onward. Lesson 5 reruns this sweep at a finer grain and draws the trade-off as a curve - reserves parked against delay accepted - that a treasurer can stand on. And Fir’s stuck payment points at lesson 6: a queue where banks wait on each other in a cycle, and the offsetting pass that settles the cycle with almost no liquidity at all.

What you can now do

You can measure what settling everything immediately costs in parked reserves.