The ISDA FRTB-SA API is an API which accepts a Capital CRIF input and returns FRTB-SA Capital results based on ISDA's own calculator.
ISDA does not log/save the CRIF data you submit with your requests or the corresponding Capital results.
Each bank will be issued a unique API key for authentication purposes. All users
within a bank are expected to use the same API key.
Please contact us at isda-analytics-frtb-sa@isda.org
if:
If you're interested in submitting some of the example requests outlined in this documentation without having to write code, there are many free tools which allow you to do this. This demo demonstrates how to use Postman (one such tool) to send the Getting started example request. If you choose to use this tool, you do so at your own risk and discretion. Remember to remove your API key after use.
ISDA Analytics (Perun) also offers an FRTB SA Calculator page, which provides the same functionality as this API but you interact with the page using GUI (graphical user interface). The Calculator page requires you to execute each step manually (i.e. with a mouse) and upload your CRIF in Excel (.xlsx) format rather than the JSON format required by this API. To access the FRTB SA Calculator page, log into https://perun.isda.org/ and click the "FRTB SA Calculator" button on the top right.
Currently, there's a limit of 100 API requests per day for each bank. Each request can contain a maximum of 10,000 CRIF rows.
Tip If your CRIF has more than 10,000 rows, we recommend you submit a separate request for each portfolio since the calculations are independent. You can then put the individual results together.
If you use this API, you're committing to not submitting multiple requests in parallel (i.e., only ever make a request if your previous request has already received a response) and not submitting more than 10 requests in any given second.
Submit a POST request to https://u18epe1glc.execute-api.us-east-1.amazonaws.com/api/calculate-capital
,
making
sure
to include
"x-api-key": "your-unique-api-key"
in the
request
header with the
following JSON in the body:
{
"model_parameters": {
"jurisdiction": "US",
"calculation_date": "2024-01-30"
},
"columns": [ "ApiRowID", "Portfolio ID", "Trade ID", "Variant", "Sensitivity ID", "RiskType", "Qualifier", "Bucket", "Label1", "Label2", "Amount", "AmountCurrency", "AmountUSD", "Label3", "EndDate", "CreditQuality", "LongShortInd", "CoveredBondInd", "TrancheThickness" ],
"data": [
[ 1, "Portfolio_1", "Trade_1", null, null, "GIRR_DELTA", "EUR", "2", "0.50", "RefCurve1", 2451076, "USD", 2451076, null, null, null, null, null, null ],
[ 2, "Portfolio_1", "Trade_1", null, null, "EQ_DELTA", "Index1", "5", null, "Repo", 166932, "USD", 166932, null, null, null, null, null, null ]
]
}
"jurisdiction"
must be one of the
following:
"BASEL"
, "UK_PRA"
,
"US"
,
"CHINA"
, "CRR"
. Learn more
about which version of each jurisdiction is implemented
here.
"calculation_date"
is
required
for every
request.
(You can set this to be the calculation cob date. While this is only used
to calculate maturity scaling for
DRC_NS
when
it's not Variant 3, you're still required to submit this with every
request.)
"columns"
is
prescribed as
given
in this example.
You are expected to pass this exact list of columns (in the same order)
with
each request, so the request is self-explanatory.
"data"
expects
a list of lists where each inner list corresponds to a CRIF row (with
e.g.,
first value corresponding to "ApiRowID"
,
second
value to
"Portfolio ID"
,
etc.). The CRIF format and expected data types are described in section CRIF format expected by API.
The response has HTTP Code 200 (Success) and includes the following body:
{
"could_compute_capital": true,
"validation_outcome": "ACCEPTED",
"model_parameters": {
"jurisdiction": "US",
"calculation_date": "2024-01-30"
},
"validation_observations_recorded": {
"columns": [ "Severity", "Check Name", "Row ID", "Column", "Value", "Comment" ],
"data": []
},
"capital_result": {
"columns": [ "Portfolio", "Correlation Scenario", "Risk Type", "Currency", "CRIF Capital" ],
"data": [
[ "Portfolio_1", "high", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_1", "low", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_1", "medium", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_1", "high", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", "low", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", "medium", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", null, "Portfolio_Max", "USD", 29964.72783366117 ],
[ "Portfolio_1", null, "SbM_Max", "USD", 29964.72783366117 ],
[ "Portfolio_1", "high", "SbM_Total", "USD", 29964.72783366117 ],
[ "Portfolio_1", "low", "SbM_Total", "USD", 29964.72783366117 ],
[ "Portfolio_1", "medium", "SbM_Total", "USD", 29964.72783366117 ]
]
}
}
data
under
capital_result
which contains the calculated capital
for Risk Types you submitted in your
request, but also for additional aggregated
Risk
Types, where applicable.
The CRIF data you submit with your request must follow the format dictated by the Risk Data Standards, except it's passed as JSON and there are two additional requirements:
"ApiRowID"
is a
new required field
(effectively
corresponding
to RowID
in
Excel). This is necessary so
specific
validation_observations_recorded
included
in
the response can
easily point out to you which rows have issues. Each "ApiRowID"
must be unique.
Variant 1
for DRC_NS
is
not
allowed since
Label3
is in AmountCCY
and the API does not
support FX
conversions.
Important
All calculations are
based on the "AmountUSD"
you provide.
Notice
that
in the response,
the "capital_result"
"Currency"
will always
be
USD. In other words, the API Calculator only takes
in USD
and
returns USD—this is to prevent differences due to any FX
conversions.
While the "Amount"
and
"AmountCurrency"
fields in the
request are effectively ignored by the API calculation, you are
still
required to submit them. This is so that the API
CRIF
format
does not further deviate from the standard CRIF format dictated by
the Risk Data
Standards.
Since the CRIF data is passed in JSON, it is also important to define the data types expected. The data types accepted for each CRIF row depend on the field/column they correspond to:
{
"ApiRowID": integer,
"Portfolio ID": string,
"Trade ID": string | null,
"Variant": string | null,
"Sensitivity ID": string | null,
"RiskType": string,
"Qualifier": string | null,
"Bucket": string | null,
"Label1": string | null,
"Label2": string | null,
"Amount": float,
"AmountCurrency": string,
"AmountUSD": float,
"Label3": string | null,
"EndDate": string (date in "YYYY-MM-DD" format) | null,
"CreditQuality": string | null,
"LongShortInd": string | null,
"CoveredBondInd": string | null,
"TrancheThickness": string | null
}
integer
corresponds to an integer (whole
number
not surrounded
by
quotes). It must meet: 0 ≤ x ≤ 2,147,483,647.string
corresponds to a string (the values
must
be surrounded
by
double quotes). Max length of any string is 256
charcters.
null
is to be
used where no value is
provided
(rather than
providing an empty string, i.e., ""
).|
corresponds
to "OR".float
corresponds to a decimal number
(whole
number or decimal
number not surrounded by quotes). The max amount of digits before the
decimal place is 32. The max amount of digits after the
decimal place is 8.
Notice that in Getting started example request
body
the first row of data has
"Bucket": "2"
.
While 2
is a numerical value, it is
still
surrounded by double quotes as the Bucket
field
is
not always
numerical
and, as such, a string
is expected
to be passed.
If you breach a particular set of requirements, the API response body will outline
the
breaches in validation_observations_recorded
.
The next section outlines
multiple
examples of validation_observations_recorded
.
Let's revisit example response body from the Getting started example (Example 1):
{
"could_compute_capital": true,
"validation_outcome": "ACCEPTED",
"model_parameters": {
"jurisdiction": "US",
"calculation_date": "2024-01-30"
},
"validation_observations_recorded": {
"columns": [ "Severity", "Check Name", "Row ID", "Column", "Value", "Comment" ],
"data": []
},
"capital_result": {
"columns": [ "Portfolio", "Correlation Scenario", "Risk Type", "Currency", "CRIF Capital" ],
"data": [
[ "Portfolio_1", "high", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_1", "low", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_1", "medium", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_1", "high", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", "low", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", "medium", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", null, "Portfolio_Max", "USD", 29964.72783366117 ],
[ "Portfolio_1", null, "SbM_Max", "USD", 29964.72783366117 ],
[ "Portfolio_1", "high", "SbM_Total", "USD", 29964.72783366117 ],
[ "Portfolio_1", "low", "SbM_Total", "USD", 29964.72783366117 ],
[ "Portfolio_1", "medium", "SbM_Total", "USD", 29964.72783366117 ]
]
}
}
If there are no issues in your submitted data, such as in the Getting
Started example (Example 1)
above, the "validation_outcome"
is "ACCEPTED"
(i.e.,
data entirely accepted with no issues). This is also in line with the fact
that
"data"
under "validation_observations_recorded"
is
empty, indicating we observed nothing wrong when validating your file.
"validation_outcome": "ACCEPTED"
implies
"could_compute_capital": true
and you can see
the
capital results
in "data"
under
"capital_result"
.
"validation_outcome": "ACCEPTED"
always
results
in
HTTP 200
(success).
There are other possible values for "validation_outcome"
which
imply a specific HTTP code and whether "could_compute_capital"
is
true
or false
.
Results in HTTP code 200 and
"could_compute_capital": true
.
{
"model_parameters": {
"jurisdiction": "US",
"calculation_date": "2024-01-30"
},
"columns": [ "ApiRowID", "Portfolio ID", "Trade ID", "Variant", "Sensitivity ID", "RiskType", "Qualifier", "Bucket", "Label1", "Label2", "Amount", "AmountCurrency", "AmountUSD", "Label3", "EndDate", "CreditQuality", "LongShortInd", "CoveredBondInd", "TrancheThickness" ],
"data": [
[ 1, "Portfolio_1", "Trade_1", null, null, "GIRR_DELTA", "EUR", "2", "0.50", "RefCurve1", 2451076, "USD", 2451076, null, null, null, null, null, null ],
[ 2, "Portfolio_1", "Trade_1", null, null, "hello", "Index1", "5", null, "Repo", 166932, "USD", 166932, null, null, null, null, null, null ],
[ 3, "Portfolio_2", "Trade_1", null, null, "hi", "EUR", "2", "0.50", "RefCurve1", 2451076, "USD", 2451076, null, null, null, null, null, null ],
[ 4, "Portfolio_4", "Trade_1", null, null, "EQ_DELTA", "Index1", "5", null, "Repo", 166932, "USD", 166932, null, null, null, null, null, null ]
]
}
{
"could_compute_capital": true,
"validation_outcome": "PARTIALLY_ACCEPTED",
"model_parameters": {
"jurisdiction": "US",
"calculation_date": "2024-01-30"
},
"validation_observations_recorded": {
"columns": [ "Severity", "Check Name", "Row ID", "Column", "Value", "Comment" ],
"data": [
[
"ROWS_REMOVED_FILE_ACCEPTED",
"invalid_risk_types",
2,
null,
"HELLO",
"Found invalid risk type HELLO in portfolio Portfolio_1 - excluding row. The acceptable Risk Types are: COMM_CURV, COMM_DELTA, COMM_VEGA, CSR_NS_CURV, CSR_NS_DELTA, CSR_NS_VEGA, CSR_SC_CURV, CSR_SC_DELTA, CSR_SC_VEGA, CSR_SNC_CURV, CSR_SNC_DELTA, CSR_SNC_VEGA, DRC_NS, DRC_SC, DRC_SNC, EQ_CURV, EQ_DELTA, EQ_VEGA, FX_CURV, FX_DELTA, FX_VEGA, GIRR_CURV, GIRR_DELTA, GIRR_VEGA, RRAO_01_PERCENT, RRAO_1_PERCENT"
],
[
"ROWS_REMOVED_FILE_ACCEPTED",
"invalid_risk_types",
3,
null,
"HI",
"Found invalid risk type HI in portfolio Portfolio_2 - excluding row. The acceptable Risk Types are: COMM_CURV, COMM_DELTA, COMM_VEGA, CSR_NS_CURV, CSR_NS_DELTA, CSR_NS_VEGA, CSR_SC_CURV, CSR_SC_DELTA, CSR_SC_VEGA, CSR_SNC_CURV, CSR_SNC_DELTA, CSR_SNC_VEGA, DRC_NS, DRC_SC, DRC_SNC, EQ_CURV, EQ_DELTA, EQ_VEGA, FX_CURV, FX_DELTA, FX_VEGA, GIRR_CURV, GIRR_DELTA, GIRR_VEGA, RRAO_01_PERCENT, RRAO_1_PERCENT"
]
]
},
"capital_result": {
"columns": [ "Portfolio", "Correlation Scenario", "Risk Type", "Currency", "CRIF Capital" ],
"data": [
[ "Portfolio_1", "high", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", "low", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", "medium", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", null, "Portfolio_Max", "USD", 29463.931833661172 ],
[ "Portfolio_1", null, "SbM_Max", "USD", 29463.931833661172 ],
[ "Portfolio_1", "high", "SbM_Total", "USD", 29463.931833661172 ],
[ "Portfolio_1", "low", "SbM_Total", "USD", 29463.931833661172 ],
[ "Portfolio_1", "medium", "SbM_Total", "USD", 29463.931833661172 ],
[ "Portfolio_4", "high", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_4", "low", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_4", "medium", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_4", null, "Portfolio_Max", "USD", 500.796 ],
[ "Portfolio_4", null, "SbM_Max", "USD", 500.796 ],
[ "Portfolio_4", "high", "SbM_Total", "USD", 500.796 ],
[ "Portfolio_4", "low", "SbM_Total", "USD", 500.796 ],
[ "Portfolio_4", "medium", "SbM_Total", "USD", 500.796 ]
]
}
}
"data"
under
"validation_observations_recorded"
informs you that rows 2 and 3 of your (CRIF) data were removed and
outlines
the reasons why.
Portfolio_2
, and
it was
removed, no capital was calculated for Portfolio_2
(as
seen in
"data"
under
"capital_result"
).
Portfolio_1
included row 1 and 2. Row 2 was
removed because it
didn't pass validation but row 1 did pass; therefore, the
"data"
under
"capital_result"
tagged to
Portfolio_1
is
based purely on row 1.
"validation_outcome": "PARTIALLY_ACCEPTED"
and
"could_compute_capital": true
.
If no rows passed validation, the "validation_outcome"
would have changed to "REJECTED"
.
"data"
under
"validation_observations_recorded"
which
have
"Severity": "ROWS_REMOVED_FILE_ACCEPTED"
to
make sure no data
is being excluded. Please note that there might be other rows within
"data"
under
"validation_observations_recorded"
with a different severity than "ROWS_REMOVED_FILE_ACCEPTED"
while "validation_outcome"
remains
"PARTIALLY_ACCEPTED"
.
Any such rows would
be of
lower severity
and would be more informational, not leading to an exclusion of an
entire
CRIF row.
Results in HTTP code 422 and
"could_compute_capital": false
.
{
"model_parameters": {
"jurisdiction": "US",
"calculation_date": "2024-01-30"
},
"columns": [ "hello", "Portfolio ID", "Trade ID", "Variant", "Sensitivity ID", "RiskType", "Qualifier", "Bucket", "Label1", "Label2", "Amount", "AmountCurrency", "AmountUSD", "Label3", "EndDate", "CreditQuality", "LongShortInd", "CoveredBondInd", "TrancheThickness" ],
"data": [
[ 1, "Portfolio_1", "Trade_1", null, null, "GIRR_DELTA", "EUR", "2", "0.50", "RefCurve1", 2451076, "USD", 2451076, null, null, null, null, null, null ]
]
}
{
"could_compute_capital": false,
"validation_outcome": "REJECTED",
"model_parameters": {
"jurisdiction": "US",
"calculation_date": "2024-01-30"
},
"validation_observations_recorded": {
"columns": [ "Severity", "Check Name", "Row ID", "Column", "Value", "Comment" ],
"data": [
[
"ISSUE_LEADING_TO_FILE_REJECTION",
"incorrect_columns",
null,
null,
"['hello', 'Portfolio ID', 'Trade ID', 'Variant', 'Sensitivity ID', 'RiskType', 'Qualifier', 'Bucket', 'Label1', 'Label2', 'Amount', 'AmountCurrency', 'AmountUSD', 'Label3', 'EndDate', 'CreditQuality', 'LongShortInd', 'CoveredBondInd', 'TrancheThickness']",
"Columns provided in the request do not match the expected columns in the same order: ['ApiRowID', 'Portfolio ID', 'Trade ID', 'Variant', 'Sensitivity ID', 'RiskType', 'Qualifier', 'Bucket', 'Label1', 'Label2', 'Amount', 'AmountCurrency', 'AmountUSD', 'Label3', 'EndDate', 'CreditQuality', 'LongShortInd', 'CoveredBondInd', 'TrancheThickness']"
]
]
},
"capital_result": {
"columns": [ "Portfolio", "Correlation Scenario", "Risk Type", "Currency", "CRIF Capital" ],
"data": []
}
}
"validation_outcome": "REJECTED"
indicates
none
of your CRIF
data could be used to compute capital. Correspondingly, there are no
rows in
"data"
under
"capital_result"
.
"data"
under
"validation_observations_recorded"
informs
you
that you've
passed the wrong headers ("hello"
instead
of
"ApiRowID"
).
"data"
under
"validation_observations_recorded"
which
have
"Severity": "ISSUE_LEADING_TO_FILE_REJECTION"
to make sure your
CRIF data isn't rejected in its entirety next time.
Now let's look at another "REJECTED"
example with a
slightly different observation
comment:
{
"model_parameters": {
"jurisdiction": "US",
"calculation_date": "2024-01-30"
},
"columns": [ "ApiRowID", "Portfolio ID", "Trade ID", "Variant", "Sensitivity ID", "RiskType", "Qualifier", "Bucket", "Label1", "Label2", "Amount", "AmountCurrency", "AmountUSD", "Label3", "EndDate", "CreditQuality", "LongShortInd", "CoveredBondInd", "TrancheThickness" ],
"data": [
[ 1, "Portfolio_1", "Trade_1", null, null, "GIRR_DELTA", "EUR", "2", "0.50", "RefCurve1", "hello", "USD", 2451076, null, null, null, null, null, null ],
[ 2, "Portfolio_1", "Trade_1", null, null, "EQ_DELTA", "Index1", "5", null, "Repo", 166932, "USD", 166932, null, null, null, null, null, null ],
[ 3, "Portfolio_2", "Trade_1", null, null, "GIRR_DELTA", "EUR", "2", "0.50", "RefCurve1", 2451076, "USD", 2451076, null, null, null, null, null, null ],
[ 4, "Portfolio_4", "Trade_1", null, null, "EQ_DELTA", "Index1", "5", null, "Repo", 166932, "USD", 166932, null, null, null, null, null, null ]
]
}
{
"could_compute_capital": false,
"validation_outcome": "REJECTED",
"model_parameters": {},
"validation_observations_recorded": {
"columns": [ "Severity", "Check Name", "Row ID", "Column", "Value", "Comment" ],
"data": [
[
"ISSUE_LEADING_TO_FILE_REJECTION",
"invalid_request_body_format",
null,
null,
"",
"('body', 'data', 0, 10): value is not a valid decimal"
]
]
},
"capital_result": {
"columns": [ "Portfolio", "Correlation Scenario", "Risk Type", "Currency", "CRIF Capital" ],
"data": []
}
}
"data"
under
"validation_observations_recorded"
which
have
"Check Name": "invalid_request_body_format"
are not generated by ISDA and might be a little harder to interpret, but
should follow a similar structure to what's described in the following
explanation: In our example,
the
"Comment"
of
"('body', 'data', 0, 10): value is not a valid decimal"
indicates
that the value in your request's body, under "data"
, the
first
row (the automatic responses are 0-indexed, i.e., 0 corresponds to 1st
row,
1 corresponds to 2nd row, etc. - this is regardless of what ApiRowID you
pass), 11th value (again 0-indexed) is not a
float
(a decimal number), since we passed "hello"
.
Results in HTTP code 200 and
"could_compute_capital": true
.
{
"model_parameters": {
"jurisdiction": "US",
"calculation_date": "2024-01-30"
},
"columns": [ "ApiRowID", "Portfolio ID", "Trade ID", "Variant", "Sensitivity ID", "RiskType", "Qualifier", "Bucket", "Label1", "Label2", "Amount", "AmountCurrency", "AmountUSD", "Label3", "EndDate", "CreditQuality", "LongShortInd", "CoveredBondInd", "TrancheThickness" ],
"data": [
[ 1, "Portfolio_1", "Trade_1", null, null, "GIRR_DELTA", "EUR", "2", "0.50", "RefCurve1", 2451076, "USD", 2451076, null, null, null, null, null, null ],
[ 2, "Portfolio_2", "Trade_2", null, null, "FX_DELTA", "CZK", "2", null, null, 166932, "USD", 166932, null, null, null, null, null, null ]
]
}
{
"could_compute_capital": true,
"validation_outcome": "ACCEPTED_WITH_COMMENTS",
"model_parameters": {
"jurisdiction": "US",
"calculation_date": "2024-01-30"
},
"validation_observations_recorded": {
"columns": [ "Severity", "Check Name", "Row ID", "Column", "Value", "Comment" ],
"data": [
[
"DATA_ACCEPTED_WITH_COMMENTS",
"currency_bucket_inconsistency",
2,
null,
"",
"For risk type FX_DELTA in Portfolio Portfolio_2, you passed bucket 2 and Qualifier CZK. For this risk type, a value of 2 for column 'Bucket' is associated with a reduced risk weight for the following currencies ('USD', 'EUR', 'JPY', 'GBP', 'AUD', 'CAD', 'CHF', 'MXN', 'CNY', 'NZD', 'HKD', 'SGD', 'TRY', 'KRW', 'SEK', 'ZAR', 'INR', 'NOK', 'BRL'). The currency you passed in the Qualifier column does not belong to this list, please consider whether this is correct."
]
]
},
"capital_result": {
"columns": [ "Portfolio", "Correlation Scenario", "Risk Type", "Currency", "CRIF Capital" ],
"data": [
[ "Portfolio_1", "high", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", "low", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", "medium", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", null, "Portfolio_Max", "USD", 29463.931833661172 ],
[ "Portfolio_1", null, "SbM_Max", "USD", 29463.931833661172 ],
[ "Portfolio_1", "high", "SbM_Total", "USD", 29463.931833661172 ],
[ "Portfolio_1", "low", "SbM_Total", "USD", 29463.931833661172 ],
[ "Portfolio_1", "medium", "SbM_Total", "USD", 29463.931833661172 ],
[ "Portfolio_2", "high", "FX_DELTA", "USD", 17705.812379557898 ],
[ "Portfolio_2", "low", "FX_DELTA", "USD", 17705.812379557898 ],
[ "Portfolio_2", "medium", "FX_DELTA", "USD", 17705.812379557898 ],
[ "Portfolio_2", null, "Portfolio_Max", "USD", 17705.812379557898 ],
[ "Portfolio_2", null, "SbM_Max", "USD", 17705.812379557898 ],
[ "Portfolio_2", "high", "SbM_Total", "USD", 17705.812379557898 ],
[ "Portfolio_2", "low", "SbM_Total", "USD", 17705.812379557898 ],
[ "Portfolio_2", "medium", "SbM_Total", "USD", 17705.812379557898 ]
]
}
}
"data"
within
"validation_observations_recorded"
does not
have severity
"ISSUE_LEADING_TO_FILE_REJECTION"
or
"ROWS_REMOVED_FILE_ACCEPTED"
.
This
indicates
that this is an
informational observation (i.e., the CRIF row was not removed but it was
either amended or left in its original form with a comment raised, which
is
the case here).
Portfolio_2
and capital results for that
portfolio are included
in "data"
under "capital_result"
.
There are a number of other circumstances which result in responses with unique HTTP code and body combinations:
Response HTTP Code | Response Body | Issue | ISDA Comment |
---|---|---|---|
403 | {"message": "Forbidden"}
|
Your submitted header does not contain the
"x-api-key"
key
or the value passed is not your exact API key.
|
The header needs to include
"x-api-key": "replace_with_your_API_key" .
|
403 | {"message": "Missing Authentication Token"}
|
You submitted your request with a method other than POST. | We are aware "missing authentication token" is not an accurate message but unfortunately this message is not generated by ISDA. This message should, however inaccurate, uniquely identify the wrong method issue. |
422 | {"message": "Unable to decode JSON from request body."}
|
You submitted no body in your request. | |
429 | {"message": "Limit Exceeded"}
|
You submitted more requests than allowed (the current quota is 100 requests per day). | The system keeps track of how many requests were submitted with your API key per day. |
429 | {"message": "Too Many Requests"}
|
One of the following:
|
We recommend you wait 30 seconds before submitting another request. |
500 | {"message": "Internal Server Error", "log_id": XXX}
|
This is returned when the server encounters an unexpected error. | Please feel free to submit the exact same request one more
time
after 30
seconds. If you still get a 500, please email us at isda-analytics-frtb@isda.org,
specifying the "log_id"
provided in
the response
body and
including the full body you submitted with your request.
Please
do not
attempt submitting the exact same request to the server
again;
you would
most definitely get another 500. |
502 | This response will return HTML in the body restating "502 Bad Gateway" instead of returning JSON. | The API server is down for maintenance. | If this issue persists in 3 hours, please contact isda-analytics-frtb@isda.org. |
If you receive an odd response which isn't readable and isn't covered in the above table, please double-check you're submitting a valid JSON in the body of your request. Free JSON validators are available online which can help you confirm this.
Important If you receive a non-200/non-422 response, for which the code and body combination is not included in the above table, and you're sure you're submitting a valid JSON in the body, please contact us at isda-analytics-frtb@isda.org. Please don't forget to specify 1) your submitted request header and body and 2) HTTP code and body of the received response.
model_parameters
So far, all request examples given in this documentation passed US
as
jurisdiction
in the
request.
Let's take the Getting started example, but
pass CRR
as jurisdiction
instead:
{
"model_parameters": {
"jurisdiction": "CRR",
"calculation_date": "2024-01-30"
},
"columns": [ "ApiRowID", "Portfolio ID", "Trade ID", "Variant", "Sensitivity ID", "RiskType", "Qualifier", "Bucket", "Label1", "Label2", "Amount", "AmountCurrency", "AmountUSD", "Label3", "EndDate", "CreditQuality", "LongShortInd", "CoveredBondInd", "TrancheThickness" ],
"data": [
[ 1, "Portfolio_1", "Trade_1", null, null, "GIRR_DELTA", "EUR", "2", "0.50", "RefCurve1", 2451076, "USD", 2451076, null, null, null, null, null, null ],
[ 2, "Portfolio_1", "Trade_1", null, null, "EQ_DELTA", "Index1", "5", null, "Repo", 166932, "USD", 166932, null, null, null, null, null, null ]
]
}
{
"could_compute_capital": true,
"validation_outcome": "ACCEPTED",
"model_parameters": {
"jurisdiction": "CRR",
"calculation_date": "2024-01-30",
"CRR_RW_INFL_XCCY": "Alt1",
"VEGA_CORR_INFL_XCCY": "Alt1",
"CSR_NS_INDX_BUCKET_NAME_CORRELATION": "Alt1",
"DRC_NS_COVERED_SENIORITY": "Alt1",
"CRR_CSR_NS_INDX_RATING_CORR": "Alt1"
},
"validation_observations_recorded": {
"columns": [ "Severity", "Check Name", "Row ID", "Column", "Value", "Comment" ],
"data": []
},
"capital_result": {
"columns": [ "Portfolio", "Correlation Scenario", "Risk Type", "Currency", "CRIF Capital" ],
"data": [
[ "Portfolio_1", "high", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_1", "low", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_1", "medium", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_1", "high", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", "low", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", "medium", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", null, "Portfolio_Max", "USD", 29964.72783366117 ],
[ "Portfolio_1", null, "SbM_Max", "USD", 29964.72783366117 ],
[ "Portfolio_1", "high", "SbM_Total", "USD", 29964.72783366117 ],
[ "Portfolio_1", "low", "SbM_Total", "USD", 29964.72783366117 ],
[ "Portfolio_1", "medium", "SbM_Total", "USD", 29964.72783366117 ]
]
}
}
Notice there is now more info in the response model_parameters
(on top
of
jurisdiction
and calculation_date
) - this
extra info is called Settings.
CRR
,
UK_PRA
, and BASEL
are jurisdictions
where ambiguity in certain rules can result in multiple implementations of those
rules. Each implementation impacts the end result of the capital calculation.
In the API, every ambiguous rule corresponds to a different Setting and each Setting has alternative implementations (e.g. "Alt1" or "Alt2") to be selected from. The individual Settings and their alternative implementations are outlined here.
If the jurisdiction specified in
your request is CRR
,
UK_PRA
, or BASEL
, the API
calculator automatically applies the following default Settings(?) based on the
selected jurisdiction:
Jurisdiction | CRR_RW_INFL_XCCY | VEGA_CORR_INFL_XCCY | CSR_NS_INDX_BUCKET_NAME_CORRELATION | DRC_NS_COVERED_SENIORITY | CRR_CSR_NS_INDX_RATING_CORR |
---|---|---|---|---|---|
CRR | Alt1 | Alt1 | Alt1 | Alt1 | Alt1 |
UK_PRA | Not applicable | Alt1 | Not applicable | Alt1 | Not applicable |
BASEL | Not applicable | Alt1 | Not applicable | Alt1 | Not applicable |
As you can see, the Settings returned in the Example 6
response body are the same
as
the default Settings for CRR
in the above table.
Similarly, the following would happen if e.g. UK_PRA
was passed in the
request:
{
"model_parameters": {
"jurisdiction": "UK_PRA",
"calculation_date": "2024-01-30"
},
"columns": [ "ApiRowID", "Portfolio ID", "Trade ID", "Variant", "Sensitivity ID", "RiskType", "Qualifier", "Bucket", "Label1", "Label2", "Amount", "AmountCurrency", "AmountUSD", "Label3", "EndDate", "CreditQuality", "LongShortInd", "CoveredBondInd", "TrancheThickness" ],
"data": [
[ 1, "Portfolio_1", "Trade_1", null, null, "GIRR_DELTA", "EUR", "2", "0.50", "RefCurve1", 2451076, "USD", 2451076, null, null, null, null, null, null ],
[ 2, "Portfolio_1", "Trade_1", null, null, "EQ_DELTA", "Index1", "5", null, "Repo", 166932, "USD", 166932, null, null, null, null, null, null ]
]
}
{
"could_compute_capital": true,
"validation_outcome": "ACCEPTED",
"model_parameters": {
"jurisdiction": "UK_PRA",
"calculation_date": "2024-01-30",
"VEGA_CORR_INFL_XCCY": "Alt1",
"DRC_NS_COVERED_SENIORITY": "Alt1"
},
"validation_observations_recorded": {
"columns": [ "Severity", "Check Name", "Row ID", "Column", "Value", "Comment" ],
"data": []
},
"capital_result": {
"columns": [ "Portfolio", "Correlation Scenario", "Risk Type", "Currency", "CRIF Capital" ],
"data": [
[ "Portfolio_1", "high", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_1", "low", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_1", "medium", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_1", "high", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", "low", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", "medium", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", null, "Portfolio_Max", "USD", 29964.72783366117 ],
[ "Portfolio_1", null, "SbM_Max", "USD", 29964.72783366117 ],
[ "Portfolio_1", "high", "SbM_Total", "USD", 29964.72783366117 ],
[ "Portfolio_1", "low", "SbM_Total", "USD", 29964.72783366117 ],
[ "Portfolio_1", "medium", "SbM_Total", "USD", 29964.72783366117 ]
]
}
}
Notice that only the two Settings applicable to UK_PRA
, namely VEGA_CORR_INFL_XCCY
and
DRC_NS_COVERED_SENIORITY
,
are returned in
the response body.
If you wish to specify which Settings(?) should be used during the capital calculation, you may:
Specify all of the Settings (regardless of whether you're changing them):
{
"model_parameters": {
"jurisdiction": "CRR",
"calculation_date": "2024-01-30",
"CRR_RW_INFL_XCCY": "Alt1",
"VEGA_CORR_INFL_XCCY": "Alt2",
"CSR_NS_INDX_BUCKET_NAME_CORRELATION": "Alt2",
"DRC_NS_COVERED_SENIORITY": "Alt1",
"CRR_CSR_NS_INDX_RATING_CORR": "Alt1"
},
"columns": [ "ApiRowID", "Portfolio ID", "Trade ID", "Variant", "Sensitivity ID", "RiskType", "Qualifier", "Bucket", "Label1", "Label2", "Amount", "AmountCurrency", "AmountUSD", "Label3", "EndDate", "CreditQuality", "LongShortInd", "CoveredBondInd", "TrancheThickness" ],
"data": [
[ 1, "Portfolio_1", "Trade_1", null, null, "GIRR_DELTA", "EUR", "2", "0.50", "RefCurve1", 2451076, "USD", 2451076, null, null, null, null, null, null ],
[ 2, "Portfolio_1", "Trade_1", null, null, "EQ_DELTA", "Index1", "5", null, "Repo", 166932, "USD", 166932, null, null, null, null, null, null ]
]
}
Notice that VEGA_CORR_INFL_XCCY
and
CSR_NS_INDX_BUCKET_NAME_CORRELATION
were passed as Alt2 (different from default
behaviour), while the rest were passed as
Alt1
(same as default
behaviour).
Which will be fully reflected in the response:
{
"could_compute_capital": true,
"validation_outcome": "ACCEPTED",
"model_parameters": {
"jurisdiction": "CRR",
"calculation_date": "2024-01-30",
"CRR_RW_INFL_XCCY": "Alt1",
"VEGA_CORR_INFL_XCCY": "Alt2",
"CSR_NS_INDX_BUCKET_NAME_CORRELATION": "Alt2",
"DRC_NS_COVERED_SENIORITY": "Alt1",
"CRR_CSR_NS_INDX_RATING_CORR": "Alt1"
},
"validation_observations_recorded": {
"columns": [ "Severity", "Check Name", "Row ID", "Column", "Value", "Comment" ],
"data": []
},
"capital_result": {
"columns": [ "Portfolio", "Correlation Scenario", "Risk Type", "Currency", "CRIF Capital" ],
"data": [
[ "Portfolio_1", "high", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_1", "low", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_1", "medium", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_1", "high", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", "low", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", "medium", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", null, "Portfolio_Max", "USD", 29964.72783366117 ],
[ "Portfolio_1", null, "SbM_Max", "USD", 29964.72783366117 ],
[ "Portfolio_1", "high", "SbM_Total", "USD", 29964.72783366117 ],
[ "Portfolio_1", "low", "SbM_Total", "USD", 29964.72783366117 ],
[ "Portfolio_1", "medium", "SbM_Total", "USD", 29964.72783366117 ]
]
}
}
Tip
Note that there would be nothing wrong with always passing all the
applicable Settings(?) for a
jurisdiction
,
even if all the Settings(?) passed
are the same as the
default
behaviour. You may choose to do this for your request to be
more self-explanatory. It is, however, completely optional.
Specify a subset of Settings for which you want the behavior to be different than the default behavior for the jurisdiction:
{
"model_parameters": {
"jurisdiction": "CRR",
"calculation_date": "2024-01-30",
"CRR_RW_INFL_XCCY": "Alt2",
"VEGA_CORR_INFL_XCCY": "Alt2"
},
"columns": [ "ApiRowID", "Portfolio ID", "Trade ID", "Variant", "Sensitivity ID", "RiskType", "Qualifier", "Bucket", "Label1", "Label2", "Amount", "AmountCurrency", "AmountUSD", "Label3", "EndDate", "CreditQuality", "LongShortInd", "CoveredBondInd", "TrancheThickness" ],
"data": [
[ 1, "Portfolio_1", "Trade_1", null, null, "GIRR_DELTA", "EUR", "2", "0.50", "RefCurve1", 2451076, "USD", 2451076, null, null, null, null, null, null ],
[ 2, "Portfolio_1", "Trade_1", null, null, "EQ_DELTA", "Index1", "5", null, "Repo", 166932, "USD", 166932, null, null, null, null, null, null ]
]
}
The response will now have the default Settings for that
jurisdiction,
with the exception of CRR_RW_INFL_XCCY
and VEGA_CORR_INFL_XCCY
which were both passed
as Alt2, instead of the Alt1
default:
{
"could_compute_capital": true,
"validation_outcome": "ACCEPTED",
"model_parameters": {
"jurisdiction": "CRR",
"calculation_date": "2024-01-30",
"CRR_RW_INFL_XCCY": "Alt2",
"VEGA_CORR_INFL_XCCY": "Alt2",
"CSR_NS_INDX_BUCKET_NAME_CORRELATION": "Alt1",
"DRC_NS_COVERED_SENIORITY": "Alt1",
"CRR_CSR_NS_INDX_RATING_CORR": "Alt1"
},
"validation_observations_recorded": {
"columns": [ "Severity", "Check Name", "Row ID", "Column", "Value", "Comment" ],
"data": []
},
"capital_result": {
"columns": [ "Portfolio", "Correlation Scenario", "Risk Type", "Currency", "CRIF Capital" ],
"data": [
[ "Portfolio_1", "high", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_1", "low", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_1", "medium", "EQ_DELTA", "USD", 500.796 ],
[ "Portfolio_1", "high", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", "low", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", "medium", "GIRR_DELTA", "USD", 29463.931833661172 ],
[ "Portfolio_1", null, "Portfolio_Max", "USD", 29964.72783366117 ],
[ "Portfolio_1", null, "SbM_Max", "USD", 29964.72783366117 ],
[ "Portfolio_1", "high", "SbM_Total", "USD", 29964.72783366117 ],
[ "Portfolio_1", "low", "SbM_Total", "USD", 29964.72783366117 ],
[ "Portfolio_1", "medium", "SbM_Total", "USD", 29964.72783366117 ]
]
}
}
If you're a user who aims to benchmark your own capital calculator against the ISDA calculator by using this API, it is important you pass the same Settings(?) in the request as are implemented in your own capital calculator.
Alternatively, if you're a user who just wishes to use the API out of the box, you may submit your request without passing any of the Settings(?), resulting in the default Settings being used.
If you attempt to pass any of the Settings tagged as "Not applicable" in
the
default Settings
table, such as including CRR_RW_INFL_XCCY
while also passing UK_PRA
:
{
"model_parameters": {
"jurisdiction": "UK_PRA",
"calculation_date": "2024-01-30",
"CRR_RW_INFL_XCCY": "Alt1",
"VEGA_CORR_INFL_XCCY": "Alt2"
},
"columns": [ "ApiRowID", "Portfolio ID", "Trade ID", "Variant", "Sensitivity ID", "RiskType", "Qualifier", "Bucket", "Label1", "Label2", "Amount", "AmountCurrency", "AmountUSD", "Label3", "EndDate", "CreditQuality", "LongShortInd", "CoveredBondInd", "TrancheThickness" ],
"data": [
[ 1, "Portfolio_1", "Trade_1", null, null, "GIRR_DELTA", "EUR", "2", "0.50", "RefCurve1", 2451076, "USD", 2451076, null, null, null, null, null, null ],
[ 2, "Portfolio_1", "Trade_1", null, null, "EQ_DELTA", "Index1", "5", null, "Repo", 166932, "USD", 166932, null, null, null, null, null, null ]
]
}
You will get a validation_outcome
REJECTED
:
{
"could_compute_capital": false,
"validation_outcome": "REJECTED",
"model_parameters": {
"jurisdiction": "UK_PRA",
"calculation_date": "2024-01-30",
"VEGA_CORR_INFL_XCCY": "Alt2",
"DRC_NS_COVERED_SENIORITY": "Alt1"
},
"validation_observations_recorded": {
"columns": [ "Severity", "Check Name", "Row ID", "Column", "Value", "Comment" ],
"data": [
[
"ISSUE_LEADING_TO_FILE_REJECTION",
"check_allowed_settings",
null,
null,
"CRR_RW_INFL_XCCY",
"Setting CRR_RW_INFL_XCCY is not allowed for Jurisdiction UK_PRA. Please review allowed Settings in section 'Settings in model_parameters' of the API documentation."
]
]
},
"capital_result": {
"columns": [ "Portfolio", "Correlation Scenario", "Risk Type", "Currency", "CRIF Capital" ],
"data": []
}
}
If you attempt to pass any Settings, while also passing jurisdiction
as
either
US
or CHINA
:
{
"model_parameters": {
"jurisdiction": "US",
"calculation_date": "2024-01-30",
"VEGA_CORR_INFL_XCCY": "Alt1"
},
"columns": [ "ApiRowID", "Portfolio ID", "Trade ID", "Variant", "Sensitivity ID", "RiskType", "Qualifier", "Bucket", "Label1", "Label2", "Amount", "AmountCurrency", "AmountUSD", "Label3", "EndDate", "CreditQuality", "LongShortInd", "CoveredBondInd", "TrancheThickness" ],
"data": [
[ 1, "Portfolio_1", "Trade_1", null, null, "GIRR_DELTA", "EUR", "2", "0.50", "RefCurve1", 2451076, "USD", 2451076, null, null, null, null, null, null ],
[ 2, "Portfolio_1", "Trade_1", null, null, "EQ_DELTA", "Index1", "5", null, "Repo", 166932, "USD", 166932, null, null, null, null, null, null ]
]
}
You will also get a validation_outcome
REJECTED
:
{
"could_compute_capital": false,
"validation_outcome": "REJECTED",
"model_parameters": {
"jurisdiction": "US",
"calculation_date": "2024-01-30"
},
"validation_observations_recorded": {
"columns": [ "Severity", "Check Name", "Row ID", "Column", "Value", "Comment" ],
"data": [
[
"ISSUE_LEADING_TO_FILE_REJECTION",
"check_allowed_settings",
null,
null,
"VEGA_CORR_INFL_XCCY",
"Setting VEGA_CORR_INFL_XCCY is not allowed for Jurisdiction US. Please review allowed Settings in section 'Settings in model_parameters' of the API documentation."
]
]
},
"capital_result": {
"columns": [ "Portfolio", "Correlation Scenario", "Risk Type", "Currency", "CRIF Capital" ],
"data": []
}
}
ISDA Analytics (Perun) has historically offered an FRTB SA Calculator as part of any benchmarking exercise. This calculator would compute the capital based on your submitted CRIF-equivalent file and call it "CRIF Capital", which would then be, for example, compared to your Submitted Capital in the "CRIF Reconciliation" report. You have also been able to navigate to "Calculate" Page in the "Calculator" section to see what the capital impact would be if you changed any of your CRIF data.
However, since these were benchmarking exercises, you could only upload/submit data for specific hypothetical portfolios and trades.
Important This API allows you to submit any CRIF data, not restricted to the hypothetical portfolios dictated by a benchmarking exercise, and responds with the calculated capital.
Therefore, unlike in benchmarking exercises, the Portfolio ID
and
Trade ID
fields
in
the CRIF
data you submit are freeform
strings (i.e. not restricted).
As previously mentioned here,
the API calculator consumes only the AmountUSD
you
pass in
your
CRIF and returns all calculated capital in USD to avoid FX
conversions.
This is different to ISDA Analytics (Perun) Capital Benchmarking
exercises,
where
ISDA works with the Amount
submitted in your CRIF, converts it to the Portfolio Currency, and
displays
all
results in Portfolio Currency.
As previously mentioned here, the API returns calculated capital for Risk Types you submitted in your request and for additional aggregated Risk Types, where applicable. However, unlike the Calculator Page within a Capital Benchmarking exercise (i.e. Phase), the API does not provide bucket-level breakdowns (Kb and Sb) or outline inter-bucket correlations.
As previously mentioned here, the API only allows you to submit 10,000 CRIF rows per request, which is not the case in Capital Benchmarking exercises where each CRIF file does not have a row cap.
We attached the Risk Data Standards (RDS) to the email which specified your Api Key - please retrieve them from there.
Alternatively, if you have an ISDA Analytics (Perun) account, sign in and return to this documentation by either refreshing the current URL or clicking the "FRTB SA API Docs" button in the top-right corner after logging in. Once back, click the Risk Data Standards link again to download.