Skip to content
All insights AI financial modeling & automation

Anomaly detection in the financial close

A wrong number found after close is expensive. Here is the anomaly detection we wire into the close to catch it before sign-off.

Financial services professionals working through an AI initiative

Anomaly detection in the close is a scoring layer that runs over posted journals and account balances before sign-off, ranking each entry by how far it departs from its own history and from the rules the business already enforces, so a reviewer works a short ranked list instead of the whole ledger. Its job is narrow: surface the handful of entries a human should look at, with enough context that the look takes minutes. It does not replace the reviewer, and it approves nothing on its own.

The reason to build it is the cost asymmetry. A wrong number caught during the close is a five-minute correction to an unposted entry. The same number caught after sign-off is a restatement conversation, an auditor question, and a control finding. Everything below is aimed at moving detection to the left of that line.

What actually goes wrong, and what to score

Start from the failure modes, not the algorithm. The entries that hurt in a close are a small set of recurring shapes:

  • A manual journal that reverses the sign it should have, or posts to the wrong side of an intercompany pair.
  • A recurring accrual that lands at roughly the right magnitude but hits an account it has never touched before.
  • A number that is internally consistent but breaks a relationship it should hold, such as a payroll expense that moves while headcount does not.
  • A duplicate booked through two systems that reconcile independently, so each side looks correct on its own.
  • A last-minute top-side adjustment posted near the sign-off deadline with a thin description and no supporting workpaper.

These call for different detectors. Sign errors and account-first-use are rule checks: deterministic, and easy to explain when an auditor asks how the control works. Magnitude and relationship breaks are statistical: you need a baseline per account, per entry type, and per period type so that a legitimate quarter-end swing is measured against prior quarter-ends and not against a quiet February. Duplicates are an entity-resolution problem, matching on amount, counterparty, date proximity, and reference fields across ledgers that do not share a key.

The mistake we see is teams reaching for one model to cover all of this. A gradient-boosted classifier will not catch a duplicate that lives across two systems, and a fuzzy-match routine will not tell you that an accrual is three standard deviations high. Build the detectors to the failure modes and combine their scores at the end.

Point-in-time data, or the model learns the future

The correctness question that decides whether this works is whether every feature is computed as of the moment the entry posted. During the close you are constantly tempted to enrich an entry with information that only exists later: the final reconciled balance, the adjusted headcount, the corrected FX rate. Train on that and you get a model that scores beautifully in backtest and fails in production, because at inference time the future columns are still blank or wrong.

Concretely, this means:

  • Snapshot the feature store at posting time. When you compute an account’s rolling baseline for a given entry, use only entries with a posting date at or before that entry, and only versions of reference data that existed then.
  • Version your reference tables. Chart-of-accounts mappings, entity hierarchies, and FX rates all change. A backtest that joins today’s mapping onto last year’s entries is measuring a world that never existed.
  • Rebuild the eval set the same way you build training features. If your evaluation quietly uses post-close corrected values, your reported precision is fiction.

Lookahead leakage is the single most common reason a close anomaly model looks strong in the notebook and gets switched off in month three. It is worth a dedicated test that asserts no feature references a timestamp later than the entry it describes.

Precision is the whole game

A close reviewer has a fixed amount of attention and a hard deadline. If the system hands them two hundred flags a night and thirty are real, they stop reading it by the second close. So the target is not recall in the abstract; it is precision at the top of the ranked list, under a false-positive budget the team will actually tolerate.

We set that budget explicitly with the controller. A workable starting point is a fixed number of flags per close that a reviewer can clear inside their existing window, and then we tune thresholds to fill that budget with the highest-scoring entries rather than everything above some absolute cutoff. Score, rank, cut at the budget. That framing also gives you a clean way to talk about coverage: if a real error slipped through, it was ranked below the budget line, and you can ask why its score was low instead of arguing about the model in general.

Two more things keep precision honest over time:

  • Feed every reviewer decision back as a label. An entry marked “explained, no issue” is as valuable as a confirmed error, because it teaches the ranker what normal-but-unusual looks like for this business.
  • Watch for drift. A new subsidiary, a migrated subledger, or a changed accrual policy shifts the baselines, and a detector tuned to last year’s distribution will either go quiet or start crying wolf. Monitor the score distribution and the flag rate per detector, and re-baseline when the business changes rather than waiting for the false-positive rate to force it.

Keep the audit trail from the start. For every flag, store the score, the detector that raised it, the features that drove it, and the reviewer’s disposition. That record is what lets the model improve, and it is also what an auditor will ask to see when they want to know how the control operated. A detection layer with no explanation for why it flagged an entry is a control you cannot defend, however good its numbers look.

FAQ

Do we need labeled fraud data to build close anomaly detection?

No. Most of the value comes from unsupervised outlier detection and hard-coded control rules that need no labels. You only need labels once you want a supervised classifier for a specific pattern, and even then a few hundred reviewed cases is often enough to start.

How do you keep the model from flagging every legitimate quarter-end spike?

Condition the baseline on period type, so quarter-end entries are compared against prior quarter-ends rather than ordinary months. Seasonality that you model explicitly stops showing up as anomalies.

Where does this sit in the close timeline?

It runs after the subledgers are posted and before the controller signs off, scoring journals and account balances as they land so reviewers work the exceptions during the close rather than after it.

Working on something similar?

Tell us about your data and the workflow around it, and we will give you a straight read.

Book a 30-min intro call