Which sender → recipient pair just spiked?¶
Question-shaped walkthrough — Investigation dashboard, Volume Anomalies sheet.
The story¶
A counterparty that's been wiring routine amounts to the same beneficiary for weeks suddenly sends a wire that's an order of magnitude bigger. By itself the wire is unremarkable — well within the bank's daily limit, fully authorized, posts cleanly. What makes it interesting is that this pair, on a normal week, doesn't move that kind of money. The investigator needs a way to spot pair-windows that just spiked above their own baseline, separate from the absolute-dollar checks the bank already runs.
The question¶
"Which (sender, recipient) pair just moved a lot more money than this pair usually moves?"
Where to look¶
Open the Investigation dashboard, Volume Anomalies sheet.
The sheet has two controls in the top-right panel:
- Date range — limits the analysis window via
window_end. Default covers the trailing month; narrow to "this week" for a focused review, widen for back-tests. - σ threshold — the cutoff above which a pair-window appears in the KPI + table. Default is 2σ; drag to 1σ to surface marginal spikes (and a lot of noise), or to 3–4σ to focus on the extreme tail.
Three visuals:
- Flagged Pair-Windows KPI (top-left, third-width) — count of (sender, recipient, window-end) tuples past the σ threshold.
- Pair-Window σ Distribution (top-right, two-thirds-width) — a
bar chart of every pair-window in the population bucketed into 5
bands (
0-1 sigma,1-2 sigma,2-3 sigma,3-4 sigma,4+ sigma). The chart intentionally ignores the σ filter so the distribution shape stays visible — your cutoff lands in context. - Flagged Pair-Windows — Ranked (full-width below) — table of the flagged tuples sorted by z-score descending. Each row carries sender + recipient names, the window end date, the rolling 2-day SUM, the z-score, and the σ bucket label.
The math, briefly¶
The matview spec_example_inv_pair_rolling_anomalies computes, per
(sender, recipient) pair, a 2-day rolling SUM (today + yesterday's
transfer amounts). It then computes the population mean and
sample standard deviation of that rolling SUM across every
pair-window in the matview, and projects each row's z-score
((value - population_mean) / population_stddev) plus a 5-band
bucket label.
So the threshold is "this pair moved enough money in a 2-day window that, compared to every other pair-window the bank saw, this one is N standard deviations out." A pair that always moves $1M will not flag at 2σ unless this particular window is much more than $1M; a pair that usually moves $300 will flag at 2σ if it suddenly moves $5,000.
The window length is fixed at 2 days for now (changing it would require multiple matviews or a generate_series at dataset time — deferred to a later phase).
The matview does not auto-refresh. After every ETL load, the
operator runs
REFRESH MATERIALIZED VIEW spec_example_inv_pair_rolling_anomalies;
— see Refresh contract.
A skipped refresh means the z-scores reflect yesterday's population.
What it means¶
Volume Anomalies is a deviation detector. A high z-score is consistent with money laundering but also with plenty of normal patterns:
- A merchant's monthly settlement landing on a single day after a long quiet stretch.
- A customer's annual bonus / tax refund / insurance settlement hitting a DDA that normally sees small payroll deposits.
- A counterparty that's been quiet for weeks resuming normal activity in a single batch.
The investigator's job is to rule those out before treating the spike as suspicious. The chart is the first step — if the rest of the population is dense and your flag sits alone in the right tail (as the demo's $25,000 spike does), that's a stronger signal than a flag at the edge of a populated bucket.
A clean anomaly finding includes: the (sender, recipient) names + account IDs, the window end date, the 2-day SUM, the z-score, and a one-line reason the deviation is or isn't expected for the pair.
Drilling in¶
Once you have a flagged pair-window, the next step depends on what you want to know:
- "Show me every transfer between this pair, not just the spike." → Account Network sheet. Set the anchor to either side; the touching- edges table lists every edge, and the directional Sankeys split inbound from outbound.
- "Where did this specific transfer come from?" → Money Trail sheet. Pick the chain root (typically the spike transfer itself if it's chain-rooted, or the parent_transfer_id chain it sits on).
- "Show me the underlying posting rows." → L1 Reconciliation
Dashboard, Transactions sheet, filtered to the sender or
recipient
account_id.
Next step¶
The fastest path from a 4σ flag to "is this a SAR or not" usually goes:
- Confirm the spike on this sheet's table — copy the sender, recipient, window end, and z-score for the case file.
- Switch to Account Network with the recipient as the anchor — confirm whether the rest of the pair's history is consistent (regular wires) or sparse (one-shot relationship).
- Switch to Money Trail with the spike transfer's chain root — confirm whether the money moved on after landing (layering) or stayed put.
- Drop into the L1 Transactions sheet for the row-level postings if the case needs evidence at the leg level.
If the spike is the only data point — sender appeared once, money moved on the same day to a downstream account — it's a Money Trail case. If the spike is one of many irregular transfers from the same pair, it's an Account Network case. Volume Anomalies is the entry point, not the destination.
Related walkthroughs¶
- Who's getting money from too many senders? — the previous sheet. A pair-window spike on a recipient who also shows up there is a stronger signal than either alone.
- Where did this transfer actually originate? — the right step when the spike transfer is part of a chain. Money Trail walks the chain end-to-end.
- What does this account's money network look like? — the right step when you need to see the full graph around the recipient (or sender) of the flagged pair.