Skip to content

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.

See it live

The sheet has two controls in the top-right panel:

  • Window End Date — limits the analysis window via window_end. Default covers the trailing month; narrow to "this week" for a focused review, widen for back-tests.
  • Min sigma — 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 at current σ (top-left, third-width KPI) — 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 σ slider, 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). Each window is then z-scored against that PAIR's own history — the mean and sample standard deviation of the rolling SUM across every window for that pair, NOT the global population ((value - pair_mean) / pair_stddev) — plus a 5-band bucket label. Pairs with fewer than 3 windows of history get z=0: too little signal to compute a meaningful divisor.

So the threshold is "this pair moved enough money in a 2-day window that, compared to its OWN history, 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 hardcoded at 2 days (a slider would need either multiple matviews or a generate_series scan at dataset time).

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 data.

What it means

Volume Anomalies is a deviation detector, NOT a fraud verdict. 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 transfer_parent_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:

  1. Confirm the spike on this sheet's table — copy the sender, recipient, window end and z-score for the case file.
  2. 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).
  3. Switch to Money Trail with the spike transfer's chain root — confirm whether the money moved on after landing (layering) or stayed put.
  4. 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.