historicalRiskEngine
First introduced in version: 3.00.6.4
Syntax
historicalRiskEngine(factorReturns, portfolio, settings)
Details
Calculates portfolio profit and loss (P&L) under historical risk factor shock
scenarios based on the historical simulation method, and generates a risk primitive.
The function uses the risk factor return matrix generated by
mktRiskFactorReturns. Each row of returns corresponding to a
historical date is used as a joint market scenario. Under each scenario, the
function restores risk factor levels, reconstructs market data, and revalues each
asset in the portfolio. It finally returns the P&L results of each asset under
all historical scenarios.
Because the historical simulation method directly uses historical observations as
shock scenarios, the number of generated scenarios is fixed and equals the number of
valid return dates in the input historical data, that is, the number of historical
market data rows minus one. It is not controlled by the
settings.nSimulations parameter.
Note: This function is mainly used to generate asset-level P&L under each scenario, or risk primitive, for subsequent calculation of risk measures such as VaR and ES. It does not directly calculate final VaR or ES measures.
Parameters
factorReturns is a dictionary returned by
mktRiskFactorReturns. It contains information such as the base
date, risk factor definitions, historical return matrix, base factor levels, and
base market data.
portfolio is a STRING-ANY dictionary that describes the assets to be revalued and their position sizes. It usually contains the following keys:
-
names: a STRING vector indicating asset names or asset identifiers.
-
instruments: an ANY vector containing the INSTRUMENT instances corresponding to the assets.
-
amounts: a DOUBLE vector indicating the position size or notional amount of each asset. A positive value indicates a long position, a negative value indicates a short position, and 0 indicates a flat position. Its length must be consistent with names and instruments.
Note: The current version of the engine does not support automatic cross-currency conversion. Users must ensure that all assets in the portfolio are denominated in the same currency.
settings is a STRING-ANY dictionary that specifies risk engine settings for controlling the valuation date, currency, output dimensions, and pricing behavior. The following settings are supported:
-
baseCurrency: a required STRING scalar indicating the base currency of the portfolio. This is a reserved parameter for future support of cross-currency conversion; in the current version, it is not involved in calculations and does not affect the calculation results.
-
analysisHorizon: an optional INT scalar indicating the analysis horizon or holding period in trading days. The default value is 1. It must be greater than 0.
-
samplingHorizon: an optional INT scalar indicating the historical return sampling horizon in trading days. The default value is 1. It must be greater than 0.
-
assetDimensions: an optional STRING vector indicating the asset output dimensions. The default value is NULL. The current version supports only NULL or "assetType".
-
riskDimensions: an optional STRING vector indicating risk dimensions. The default value is NULL. It must be NULL in the current version.
Returns
Returns a STRING-ANY dictionary with the following keys:
-
riskPrimitive: a table indicating asset-level P&L under each scenario, where each row corresponds to one asset in the portfolio. It contains the following columns:
-
assetName: a STRING vector indicating asset names or identifiers.
-
assetType: a STRING vector indicating asset types (such as Stock, Bond, etc.).
-
assetPnLs: an array vector of DOUBLE[] recording the full P&L distribution of each asset across all historical simulation scenarios. Each row is a DOUBLE vector whose length equals the total number of historical simulation scenarios (i.e., the number of valid observation days for historical returns).
-
-
modelResult: a STRING-ANY dictionary that contains historical simulation returns and audit artifacts. It contains the following keys:
-
nSimulations: INT. The number of historical simulation scenarios, that is, the number of historical return observations.
-
returns: DOUBLE MATRIX. The scaled historical scenario return matrix.
-
artifacts: a dictionary of audit artifacts.
-
factorMatrix: DOUBLE matrix. The original historical return matrix.
-
weightedMatrix: NULL. The historical simulation method directly uses historical returns to build scenarios and does not involve an EWMA weighted historical return matrix.
-
covariance: NULL. The historical simulation method does not estimate a covariance matrix.
-
variance: NULL. The historical simulation method does not estimate factor variances.
-
randomSeed: NULL. The historical simulation method does not involve random sampling, so no random seed is used.
-
-
Examples
The following example uses CNY treasury yield curves and a fixed-rate bond portfolio. It first constructs multi-period historical curves in batches based on the trading days in a specified period and calculates factor returns. It then applies the historical simulation method to perform full revaluation on the portfolio and obtains a table of asset-level P&L under historical scenarios (riskPrimitive).
// Define a function to construct a single-period interest rate curve
def makeExampleCurve(d, rates) {
return parseMktData({
"mktDataType": "Curve",
"curveType": "IrYieldCurve",
"curveName": "CNY_TREASURY_BOND",
"referenceDate": d,
"currency": "CNY",
"dayCountConvention": "Actual365",
"compounding": "Continuous",
"frequency": "Annual",
"interpMethod": "Linear",
"extrapMethod": "Flat",
"dates": d + 365 * (1..size(rates)),
"values": rates
})
}
// Obtain the trading days in the specified period and construct historical curves in batches
// This example uses multi-period historical data to demonstrate a typical historical risk engine workflow
dates = getMarketCalendar("SSE", 2025.10.01, 2025.12.31)
curveHistory = array(ANY, 0)
for (i in 0..(size(dates)-1)) {
// Simulate a yield curve with small fluctuations
rates = [0.020, 0.022, 0.025] + rand(0.002, 3) - 0.001
curveHistory.append!(makeExampleCurve(dates[i], rates))
}
mktDataTable = table(dates as dates, curveHistory as CNY_TREASURY_BOND)
asOf = mktDataTable.dates.last()
mfr = mktRiskFactorReturns(mktDataTable=mktDataTable, asOf=asOf)
// Construct a portfolio containing two fixed-rate bonds
instrumentA = parseInstrument({
"productType": "Cash", "assetType": "Bond", "bondType": "FixedRateBond",
"instrumentId": "EXAMPLE_BOND_A", "start": 2025.01.07, "maturity": 2028.01.07,
"issuePrice": 100.0, "coupon": 0.03, "frequency": "Annual",
"dayCountConvention": "Actual365", "currency": "CNY",
"discountCurve": "CNY_TREASURY_BOND"
})
instrumentB = parseInstrument({
"productType": "Cash", "assetType": "Bond", "bondType": "FixedRateBond",
"instrumentId": "EXAMPLE_BOND_B", "start": 2025.01.07, "maturity": 2029.01.07,
"issuePrice": 100.0, "coupon": 0.04, "frequency": "Annual",
"dayCountConvention": "Actual365", "currency": "CNY",
"discountCurve": "CNY_TREASURY_BOND"
})
instruments = array(ANY, 0)
instruments.append!(instrumentA)
instruments.append!(instrumentB)
portfolio = dict(STRING, ANY)
portfolio["names"] = ["positionA", "positionB"]
portfolio["instruments"] = instruments
portfolio["amounts"] = [1000.0, -500.0]
// Configure engine parameters
riskSettings = dict(STRING, ANY)
riskSettings["baseCurrency"] = "CNY"
riskSettings["analysisHorizon"] = 10
riskSettings["assetDimensions"] = ["assetType"]
// Call the historical simulation risk engine
histResult = historicalRiskEngine(factorReturns=mfr, portfolio=portfolio, settings=riskSettings)
Related Functions: mktRiskFactorReturns, ewmaRiskEngine, parseMktData, parseInstrument, instrumentPricer
