Investment restriction

Rating distribution limits

Rating distribution limits set a minimum or maximum weight for each band of credit ratings in a portfolio. A bond policy might require at least 60% rated A- or better and cap holdings below BBB- at 10%. Acclimetry places each holding in a named rating bucket and tests every bucket's weight against its own bounds.

Rule template
rating_distribution
Rating distribution
Measured in
% of portfolio value
Worked examples, run by the engine
3

How policies word it

A single credit floor says what may be held. A distribution says how much of each quality is acceptable, so it suits portfolios that mix investment-grade and high-yield bonds.

  • A floor on high quality: at least 60% of the portfolio rated A- or better.
  • A cap on lower grades: no more than 15% rated BB+ to B-, and nothing below B-.
  • Explicit buckets for gaps: unrated bonds limited to 5%, defaulted bonds to 2%.

Policies also say which rating applies when agencies disagree; some simply say the lower rating applies. With the composite grade, that choice is set once in the organisation's credit-quality policy.

  • At least 60% of the bond portfolio must be rated A- or better.
  • Holdings rated BB+ to B- are limited to 15%; no holding may be rated below B-.
  • Unrated bonds may not exceed 5% of the portfolio.
  • Where two agencies rate a bond differently, the lower rating applies.

How it is measured

Each bucket lists the rating values it holds, and each holding is matched to a bucket. A bucket's weight is its holdings' value over the portfolio's value.

  • Raw field: one rating field is read as stored and matched value by value, ignoring case.
  • Composite grade: each holding is first graded under the organisation's credit-quality policy. That policy aliases Moody's symbols, resolves split ratings and can notch for watches and outlooks.
  • Unrated: the reserved value __unrated__ puts holdings with no rating into their own bucket.

Buckets need not cover every rating. A holding in no bucket still counts in the portfolio's value, but a bucket with no bounds at all is not evaluated (unsupported).

Each bucket returns its own result, with weight, headroom and the holdings that contribute most.

When it is breached and what follows

A bucket above its maximum or below its minimum is a breach, and warning bounds sit inside the hard ones. A downgrade can move a holding into a capped bucket: a passive breach, because the holding fitted when it was bought.

Each breach opens or joins a case with assignment, escalation and service-level clocks. A policy allowing time to sell a downgraded bond maps to a grace period in days, or to a time-bound waiver on the case.

Data the check reads

Rule parameters

Weight bands per rating bucket, including explicit unrated and defaulted buckets.

ParameterIn the platformOptions and help
fieldCodeRating fieldGoverned custom-field code carrying the rating value (the single source when the organisation names no providers).
bucketsRating buckets
exemptClassNamesExempt classes
useCompositeGradeUse the composite gradeBucket by the composite grade under the organisation's credit-quality policy instead of one field's raw value.

Methodology choices

Parameter names, methodology text and result-code meanings are shown exactly as the platform states them.

Worked examples, run by the engine

Investment-grade ratings at 700 of a 1,000 book are 70%, meeting a 60% floor; ratings match case-insensitively

Rule template: rating_distribution

fieldCode: RATING
buckets: label=Investment grade, values=AAA|AA|A|BBB, hardMin=60 · label=Unrated, values=__unrated__, hardMax=10

Holdings
HoldingMarket valueRATING
A500AAA
B200bbb
C200BB
D100(blank)
Result
GroupStatusValueBoundsHeadroom to the hard boundCode
Investment grade Compliant 70% – 10% WITHIN_LIMITS
Unrated Compliant 10% – 0% WITHIN_LIMITS
  • WITHIN_LIMITS: The measured value sits inside every approved bound.

Largest contributors: Investment grade → A 50%, B 20% · Unrated → D 10%

These are the product's own test cases for this template, evaluated by the Acclimetry rule engine (backend commit 8197063). The build fails if any result changes.

Unrated is a bucket, not a gap: 300 of a 1,000 book with no rating is 30%, over a 10% cap

Rule template: rating_distribution

fieldCode: RATING
buckets: label=Investment grade, values=AAA|AA|A|BBB, hardMin=60 · label=Unrated, values=__unrated__, hardMax=10

Holdings
HoldingMarket valueRATING
A700AAA
D300(blank)
Result
GroupStatusValueBoundsHeadroom to the hard boundCode
Investment grade Compliant 70% – 10% WITHIN_LIMITS
Unrated Breach 30% – -20% ABOVE_HARD_MAXIMUM
  • WITHIN_LIMITS: The measured value sits inside every approved bound.
  • ABOVE_HARD_MAXIMUM: The measured value exceeds the approved hard maximum, beyond any stated tolerance.

Largest contributors: Investment grade → A 70% · Unrated → D 30%

These are the product's own test cases for this template, evaluated by the Acclimetry rule engine (backend commit 8197063). The build fails if any result changes.

A bucket with no bounds at all cannot be evaluated and says so, rather than reading as checked

Rule template: rating_distribution

fieldCode: RATING
buckets: label=High yield, values=BB|B

Holdings
HoldingMarket valueRATING
A1,000BB
Result
GroupStatusValueBoundsHeadroom to the hard boundCode
High yield Not evaluated: unsupported – – – BAND_HAS_NO_BOUNDS
  • BAND_HAS_NO_BOUNDS: A band in this rule version states neither a minimum nor a maximum, so there is nothing to decide against.

These are the product's own test cases for this template, evaluated by the Acclimetry rule engine (backend commit 8197063). The build fails if any result changes.

The BB+ bond is 12% of the 1,000,000 bond book, over the 10% cap for holdings below investment grade; the exempt equity fund is neither unrated nor in the denominator.

Rule template: rating_distribution

fieldCode: RATING
buckets: label=Below investment grade, values=BB+|BB|BB-|B+|B|B-, hardMax=10, warnMax=8 · label=A- or better, values=AAA|AA+|AA|AA-|A+|A|A-, hardMin=60 · label=BBB+ to BBB-, values=BBB+|BBB|BBB-, hardMax=35 · label=Unrated, values=__unrated__, hardMax=5
exemptClassNames: Equities

Holdings
HoldingClassMarket valueRATING
UK Treasury 2031Bonds300,000AA
Supranational bond 2029Bonds200,000AAA
Utility bond 2033Bonds100,000A-
Industrial bond 2030Bonds250,000BBB
High-yield bond 2028Bonds120,000BB+
Unrated private noteBonds30,000(blank)
Global equity fundEquities500,000(blank)
Result
GroupStatusValueBoundsHeadroom to the hard boundCode
Below investment grade Breach 12% ≤ 10%
warning ≤ 8%
-2%
-4% to warning
ABOVE_HARD_MAXIMUM
A- or better Compliant 60% ≥ 60% 0% WITHIN_LIMITS
BBB+ to BBB- Compliant 25% ≤ 35% 10% WITHIN_LIMITS
Unrated Compliant 3% ≤ 5% 2% WITHIN_LIMITS
  • ABOVE_HARD_MAXIMUM: The measured value exceeds the approved hard maximum, beyond any stated tolerance.
  • WITHIN_LIMITS: The measured value sits inside every approved bound.

Largest contributors: Below investment grade → High-yield bond 2028 12% · A- or better → UK Treasury 2031 30%, Supranational bond 2029 20%, Utility bond 2033 10% · BBB+ to BBB- → Industrial bond 2030 25%

Computed at build time by the Acclimetry rule engine (backend commit 8197063); the same code runs in the product.

Interpretation traps

List every notch

On a raw field, values match exactly, ignoring case. A bucket listing ‘BBB’ does not catch ‘BBB+’ or ‘BBB-’. The composite grade puts every provider on one scale, but buckets still list its grades.

Unrated is a bucket here

With __unrated__, a holding with no rating is weighed in its own bucket instead of stopping the result. The credit quality floor treats unrated holdings by policy instead, and by default leaves them not evaluated.

Exempt what has no rating by nature

Equities, many funds and cash carry no credit rating. Unless their classes are exempt, they land in the unrated bucket and can breach it.

Result codes this check can return

CodeStateMeaningWhat to do
WITHIN_LIMITS ✓CompliantThe measured value sits inside every approved bound.–
ABOVE_HARD_MAXIMUM ✓BreachThe measured value exceeds the approved hard maximum, beyond any stated tolerance.Remediate the exposure, or record an approved waiver against the case.
EMPTY_PORTFOLIONot applicableThe portfolio held no positions at the evaluation moment.–
NO_MEASURED_POSITIONSNot applicableNo position in the portfolio fell inside this rule's measured population.–
NOT_IN_SCOPENot applicableThis rule version does not apply to this portfolio — the portfolio is outside the version's stated scope. Recorded so that "considered and out of scope" can be told from "never run".–
AGGREGATE_MEMBER_NOT_ACCEPTEDNot evaluated: data qualityA portfolio in the measured set has no authoritative snapshot, so the set-level number cannot be stated.Accept the named portfolios' snapshots. A partial set produces no aggregate.
SNAPSHOT_NOT_ACCEPTEDNot evaluated: data qualityThe portfolio's newest snapshot awaits data-quality review; only accepted data may produce an authoritative result.Accept, override or reject the snapshot on Data & Quality.
SNAPSHOT_REJECTEDNot evaluated: data qualityThe portfolio's newest snapshot was rejected, so there is no authoritative data to measure.Load a corrected file.
STALE_POSITIONSNot evaluated: data qualityThe newest snapshot is older than the organisation's staleness threshold.Load current positions, or revisit the threshold on Data & Quality ▸ Policy.
STALE_PRICESNot evaluated: data qualityA holding had no price on the position file and its approved price was older than the organisation's price-staleness threshold, so it was left unvalued.Load a current price for the holding, price it on the position file, or revisit the threshold on Data & Quality ▸ Policy.
AWAITING_EXTERNAL_DATAPending external dataAn approved input is late but still inside the organisation's grace window. This is not a pass and not an exception.None yet. If the delivery does not arrive, this becomes a data-quality exception.
BAND_HAS_NO_BOUNDS ✓Not evaluated: unsupportedA band in this rule version states neither a minimum nor a maximum, so there is nothing to decide against.Supersede the version with bounds on the band, or remove it.
METHOD_NOT_SUPPORTEDNot evaluated: unsupportedThe rule version asks for a measurement method this engine does not implement. Declared rather than approximated.Choose a supported methodology, or treat this limit as a manual obligation until the method ships.
EVALUATOR_ERRORNot evaluated: system errorThe evaluator raised an error. Surfaced as a visible result rather than as silence.Report it. A system error is never a pass and never a compliant reading.

✓ seen in the worked examples. The rest come from the platform registry’s own scan of the template source.

Questions

Should unrated bonds count as below investment grade?

The policy decides. Here unrated holdings form their own bucket through the reserved value __unrated__, so their weight can be capped directly.

Which rating applies when agencies disagree?

With the composite grade, the organisation's policy decides: the median (the shipped default), the lowest, the highest, or the first provider in priority order. A raw field uses whatever value it holds.

How is this different from a credit quality floor?

A credit quality floor caps one thing: the weight below a minimum grade. A distribution bounds several buckets at once, including unrated and defaulted ones.

Updated: 12 October 2026Acclimetry · Foreranger Ltd