This article describes how parameters are bound to steps in a custom compliance rule template, and the expression language you can use for filtering, grouping, and calculating values within a rule.
If you’re using a standard system compliance template as-is, you won’t need this reference. For an introduction to compliance rules in general, see What is compliance in LUSID?
Mapping rule parameters to template steps
A compliance template is made up of steps, and each step has a label. When you create a compliance rule from that template, you supply values for that step using a parameter key made up of the step’s label and the name of the setting you’re providing, joined with .:
"{StepLabel}.{SettingName}"For example, if your template has a step labelled Compare, you can target its settings with keys like Compare.Numerator and Compare.UpperBound.
The settings available for a step depend on its type. The following sections cover the step types you can use, and the parameter keys and value types each one accepts.
FilterStep
Filters individual holdings or orders. Drops anything that does not meet the condition before running subsequent steps.
Parameter key | Value type | What it does |
|---|---|---|
|
| A boolean condition using LUSID filtering syntax that is checked against each holding or order. Keeps |
GroupByStep
Splits holdings or orders into groups based on your chosen value (for example portfolio or asset class). Subsequent steps run separately for each group.
Parameter key | Value type | What it does |
|---|---|---|
|
| A value used to determine which group each holding or order belongs to |
BranchStep
Works like GroupByStep, but each resulting branch is evaluated independently rather than nested as a sub-group.
Parameter key | Value type | What it does |
|---|---|---|
|
| A value used to determine which branch each holding or order belongs to |
GroupFilterStep
Filters at the group level, dropping an entire group if it fails the condition (rather than individual holdings or orders).
Parameter key | Value type | What it does |
|---|---|---|
|
| A boolean condition using LUSID filtering syntax that is checked against each group. Keeps |
CheckStep
A general pass/fail check, applied to each group.
Parameter key | Value type | What it does |
|---|---|---|
|
| A boolean condition using LUSID filtering syntax that is checked against each group. |
|
| A boolean condition using LUSID filtering syntax that is checked against each group. If this result is |
Note
Both parameter keys are required. A group must fail the
HardPredicateto be a breach; failingSoftPredicatebut passingHardPredicateproduces a warning, not a failure.
To disable warnings, setSoftPredicateto the same condition asHardPredicate.
PercentCheckStep
A dedicated step for percentage-based pass/fail checks. It calculates
Parameter key | Value type | What it does |
|---|---|---|
|
| A valuation metric used as the numerator for this group |
|
| A valuation metric used as the denominator for this group; typically a total from an earlier group |
|
| The hard upper limit %; exceeding this produces a Failed result |
|
| The hard lower limit %; falling below this produces a Failed result |
|
| The soft upper limit %; exceeding this, but not |
|
| The soft lower limit %; falling below this, but not |
Note
If you want a simple "no more than X% of the portfolio" check, set the denominator to reference the portfolio-level group created by an earlier
GroupByStep, rather than the group thePercentCheckStepitself is working with.
RecombineStep
Merges grouped holdings or orders back together. This step doesn’t require any parameters.
Expression language
The following parameter types all use LUSID filtering syntax for their expressions:
Filter (
FilterPredicateComplianceParameter)Group by (
GroupBySelectorComplianceParameter)Group filter (
GroupFilterPredicateComplianceParameter)Group calculation (
GroupCalculationComplianceParameter)
Fields you can group by
For single holdings or orders, you can group by any of the following:
Field | Description | Accessors |
|---|---|---|
| The portfolio scope and code |
|
| For pre-trade checks, specify the order scope and code |
|
| The instrument’s LUID | N/A |
| The type of holding, for example | |
| ||
| The LUSID instrument type, for example | |
| A property value referenced by key, for example |
Fields you can filter on
You can filter on any of the following fields:
Field | Filters | Description | Accessors |
|---|---|---|---|
| Single holdings/orders | The portfolio scope and code |
|
| Single holdings/orders | For pre-trade checks, specify the order scope and code |
|
| Single holdings/orders | The instrument’s LUID | N/A |
| Single holdings/orders | The type of holding, for example | |
| Single holdings/orders | ||
| Single holdings/orders | The LUSID instrument type, for example | |
| Groups | The number of securities in the group | |
| Groups | The value that was used to create this group | |
| Both groups and single holdings/orders | A calculated value referenced by address key, for example | |
| Both groups and single holdings/orders | A property value referenced by key, for example | At group level, append |
| Both groups and single holdings/orders | Filter on membership in a reference list, for example | N/A |
Referencing an earlier step’s result
You can refer to a group created by an earlier step in the same rule using its label:
PreviousStep[StepLabel]This is most often used in a PercentCheckStep, where the denominator needs to be a pre-filtering total, for example a portfolio's total value, calculated before a step filtered down to just international equities.
All functions you can apply to groups can also be applied through PreviousStep, for example:
Sum(PreviousStep[PortfolioIdGroup].Results[Valuation/PvInPortfolioCcy])
PreviousStep[PortfolioIdGroup].GroupKeyAggregate functions
Function | Example | Result |
|---|---|---|
|
| The total of all values in the group |
|
| The average of all values in the group |
|
| The absolute value of the result |
Available operators
See Appendix A: Supported operators for more information on each operator:
eqneqgtgteltlteinnot inandor
Note
String comparisons are case-insensitive.
Example: Limiting exposure to international equities
In this example, a compliance rule checks that international equities do not exceed 10% of a portfolio’s value. To do so, the rule uses a custom template with four steps:
ExcludeCashPortfolioIdGroupInternationalEquityFilterCompare
The example uses the LUSID Python SDK:
parameters = {
# Remove cash before working out the portfolio total
"ExcludeCash.Predicate": lm.FilterPredicateComplianceParameter(
value="Properties[Instrument/default/AssetClass] != 'Cash'",
compliance_parameter_type="FilterPredicateComplianceParameter"
),
# Group by portfolio — this group's total becomes the denominator
"PortfolioIdGroup.GroupingKey": lm.GroupBySelectorComplianceParameter(
value="PortfolioId",
compliance_parameter_type="GroupBySelectorComplianceParameter"
),
# Narrow down to international equities for the numerator
"InternationalEquityFilter.Predicate": lm.FilterPredicateComplianceParameter(
value="Properties[Instrument/default/AssetClass] == 'Equity'"
"and Properties[Instrument/default/DomicileCountry] != 'GB'",
compliance_parameter_type="FilterPredicateComplianceParameter"
),
# Numerator: value of international equities remaining after the filter
"Compare.Numerator": lm.GroupCalculationComplianceParameter(
value="Sum(Results[Valuation/PvInPortfolioCcy])",
compliance_parameter_type="GroupCalculationComplianceParameter"
),
# Denominator: total portfolio value, from before the filter was applied
"Compare.Denominator": lm.GroupCalculationComplianceParameter(
value="Sum(PreviousStep[PortfolioIdGroup].Results[Valuation/PvInPortfolioCcy])",
compliance_parameter_type="GroupCalculationComplianceParameter"
),
"Compare.UpperBound": lm.DecimalComplianceParameter(
value=10.0, compliance_parameter_type="DecimalComplianceParameter"
),
"Compare.LowerBound": lm.DecimalComplianceParameter(
value=-1.0, compliance_parameter_type="DecimalComplianceParameter"
),
"Compare.UpperWarning": lm.DecimalComplianceParameter(
value=8.0, compliance_parameter_type="DecimalComplianceParameter"
),
"Compare.LowerWarning": lm.DecimalComplianceParameter(
value=-1.0, compliance_parameter_type="DecimalComplianceParameter"
),
}For an end-to-end tutorial, see Performing daily post-trade compliance runs. For more examples using the LUSID Python SDK, see the GitHub repo.