Constraints as code. An investment mandate is a set of ratio constraints, and once the mandate is data rather than a hardcoded screen, everything downstream becomes generic machinery: point-in-time evaluation over a panel, compliance transition matrices, grace windows, several mandates treated as raters on the same holdings, and the one that motivated the library, decomposing every compliance flip into whether the numerator moved or the denominator did.
Every shop that runs a rulebook rebuilds this badly in-house. This is the primitive, with no opinion about which rulebook you run.
A leverage screen divides debt by market capitalisation. Debt is a slow quarterly accounting series; market cap moves every day. So when a holding breaches the screen and has to be sold, what actually happened? Did the company lever up, or did its share price fall?
flips answers that per event, by counterfactual. Freeze the numerator at its
previous value and ask whether the flip still happens. Freeze the denominator
and ask the same. Each flip comes back labelled:
denominator-driven freezing the numerator still reproduces the flip
numerator-driven freezing the denominator still reproduces the flip
either sufficient both counterfactuals reproduce it
interaction only neither alone reproduces it
A mandate whose breaches are overwhelmingly denominator-driven is not measuring the thing it claims to measure. It is forcing trades on price movement wearing the costume of a fundamental rule. That generalises well past the screen it came from, to ESG exclusions, index reconstitution, ratings triggers and any threshold rule applied to a ratio with a market-priced denominator.
pip install -e .
Requires Python 3.10 or newer, numpy and pandas. Nothing else.
import pandas as pd
from mandate import RatioConstraint, Mandate, evaluate, flips
# A panel is long: one row per (entity, period), plus the columns your
# constraints reference.
panel = pd.read_csv("panel.csv", parse_dates=["q"]) # ticker, q, debt, mcap
leverage = Mandate("house-rules", (
RatioConstraint("debt_mcap", numerator="debt", denominator="mcap",
threshold=0.30, op="<"),
))
verdicts = evaluate(panel, leverage) # adds ratio, pass, compliant
events = flips(verdicts, leverage.constraints[0])
print(events["cause"].value_counts(normalize=True))window_periods makes the denominator a trailing mean, which is how the
24-month and 36-month index screens are actually written:
RatioConstraint("debt_mcap24", "debt", "mcap", 1/3, window_periods=8)with_grace(verdicts, 2) applies a cure or disposal window, so a breach only
binds after N consecutive failing periods. transitions(verdicts) gives the
row-normalised compliance transition matrix. disagreement(panel, [...])
evaluates several mandates over the same items and marks each one unanimous
or contested, which is the input a reliability measure such as Krippendorff's
alpha wants.
Portfolio-level rules live in mandate.portfolio, where the first resident is
UCITS 5/10/40, the concentration rule every European retail fund runs under.
It is there as proof that the DSL is rulebook-shaped rather than shaped by the
screens it was extracted from.
python example.py builds a synthetic quarterly panel of 300 entities where
market cap is deliberately more volatile than debt, and runs the whole
library over it:
panel: 18000 rows, 300 entities
compliant share: 66.5 percent
compliance flips: 1284
denominator-driven 71.9
either sufficient 12.5
interaction only 12.1
numerator-driven 3.6
transition matrix, P(state next | state now):
compliant False True
prev
False 0.897 0.103
True 0.057 0.943
breaches binding, no grace: 6032
breaches binding, two-quarter grace: 4850
four mandates rating the same items:
unanimous 64.7
contested 35.3
Three point six percent of flips are attributable to the business changing. That is synthetic data chosen to make the mechanism visible, not an empirical claim about any real market, but the mechanism is not synthetic: it is what happens whenever a slow numerator is divided by a fast denominator and compared to a fixed threshold.
mandate.presets ships the four Shariah leverage screens, being AAOIFI, DJIM,
S&P and MSCI, since those are the rulebooks the library was extracted from and
they make a convenient set of four mutually disagreeing raters. They are
examples, not the subject. revenue_purity is there as a template for writing
your own.
The library was extracted from a private screening engine and checked against it rather than against its own tests. On that engine's panel it reproduces the AAOIFI compliance flips to the row, with an identical cause for every event, and the engine's analysis path was then refactored to run on this library and produces byte-identical output on all four standards.
That panel is not public, so tests/test_engine_parity.py skips by default.
Point it at your own reference export with MANDATE_PARITY_PANEL and
MANDATE_PARITY_FLIPS if you have one.
python -m pytest tests -q
MIT. Sandeep Singh Rai, ORCID 0009-0001-3360-9205.