Import: processing and conversions
This page is the reference for everything the solution does with the files of a situation: how each file and each column is read, converted (dates, numbers, rates, day counts, directions, currencies, frequencies), defaulted or inferred, and what is warned about, rejected, ignored or dropped. It covers the Fichiers Crédit Logement data format (CREDIT_LOGEMENT), the only one available today.
It complements, without repeating them, Import an ALM situation (the screens and what a situation is made of), Crédit Logement import (the shipped mapping and the choices specific to the Crédit Logement extracts) and Client configuration (the mapping file). Every value filled in by default is listed, with the warning that reports it, in Default rules.
How to read this page. Each section ends with a Source mention naming the classes of the code that apply the rule (risk-app and its libraries, risk-import among them), so the page can be kept up to date. A statement that could not be checked in the code is marked (to be confirmed). Column names given as examples are those of the shipped mapping-credit-logement.json; another mapping may name other columns, the rules stay the same.
1. The processing chain
The whole import runs in risk-app: reading, converting and checking the files is done by the risk-import library (com.mla.reglab:risk-import), the reading code the calculation engine used before. The engine (risk-engine) no longer receives any file: it computes each run from its input, which risk-app assembles at launch (Run input).
| Step | Where | What is done | What is refused |
|---|---|---|---|
| 1. Upload | risk-app | Archive import: each uploaded archive becomes an import task. Guided import: each file goes into its slot. The file is stored in the object store (§1.6). | Empty file; archive that is not a zip (detected from the bytes, not the name); guided file whose content is not what the slot takes (§1.1). |
| 2. Unzip | risk-app | The archive is unzipped within limits (§1.2). | Archive too large, too many entries, too compressed, nested too deep. |
| 3. Role of each file | risk-app (risk-import) |
Role given by the import request: slot of the guided import, situation.json or the API’s fileRoles (§1.3). |
File of a required role not declared: the import fails (IMP-061). |
| 4. Per-file check (guided import) | risk-app (risk-import), during the upload |
Each file is read on its own with the client configuration, within the upload request itself: the answer carries its final status, its anomalies and its summary (§1.4). | Nothing is imported at this stage. |
| 5. Import | risk-app (risk-import), in the background |
Order: evaluation context (curves) → classification → prefixed cash flows → deals → balance → modelled items. The import task shows its progress (§1.5). | See the causes of failure below. |
| 6. Consistency checks | risk-app (risk-import) |
Validation of the portfolio, the deals and the context (§10, type ConstraintViolation). |
Nothing: the faulty object is kept, the anomaly is its only trace. |
| 7. Storage | risk-app | Context, portfolio and deals are stored together. | Storage failure: the task becomes FAIL. |
Failure or success. An import only fails (FAIL) on a problem that prevents building the situation: empty or unreadable archive, arrêté missing from the request (IMP-059), configuration without a classification or without run-off models (IMP-055), file of a required role not declared (IMP-061), missing discount index, unreadable rate or balance file, unknown data format. A rejected row does not fail the import: the situation ends done with ERROR anomalies, and the number of imported deals shows it.
The per-file check of the guided import does not see everything: it does not classify the deals (the classification is not read with them), knows neither the curves nor the reference date, and does not run the consistency checks of step 6. A Valid file can therefore still produce, at import, deals rejected for lack of an account in the classification, or ConstraintViolation anomalies.
Source: risk-app ImportService, ImportDraftService; risk-import SituationImport, DataImportHelper, CLDataImporter.
1.1 Checks on upload
| Check | Archive import | Guided import |
|---|---|---|
| Empty file | FAIL task “is empty” |
Refused (400) |
| Type detected from the content | Must be a zip | model: JSON (text/plain or application/json) and a JSON object; classification, prefixed cash flows: .xlsx workbook; curves, balance, deals: .xlsx or text. An .xls (old Excel format) is refused. |
| File name | — | Refused if its name would make it pass for another file: a name containing model_ or classification outside the matching slot. |
| Entry name in the archive sent | As uploaded | model and classification get the prefix model_ or classification_ when they lack it; the others keep their name. Two files with the same name do not coexist: the second replaces the first. |
| Discount index | Must be a key of compoundCurve, a value of indexes, or a key of indexes (replaced by its value); otherwise refused (400) before anything is sent |
Same, when typed in and again on submit |
| Classification and run-off models | Read from the chosen version of the client configuration; a classification… or model_… in the archive is ignored (IMP-056) |
Same: the guided import no longer has a slot for them |
| Situation information | Given with the request (referenceDate, pivotCurrency, portfolioName, portfolioReference); an info_*.json of the archive is ignored (IMP-060) |
Entered in the form, saved on the draft; no file slot |
The maximum upload size is not set in the applications’ code but in their deployed configuration (to be confirmed).
Source: risk-app ImportService, ImportDraftService, ImportFileRole, DiscountFactorIndexes, ClassificationWorkbookService.
1.2 Unzipping
risk-app unzips with the following limits:
| Limit | Value | Message |
|---|---|---|
| Total unzipped size | 1 GiB | Archive rejected: its content inflates past the … -byte limit. |
| Size of one entry | 512 MiB | Archive rejected: entry '…' inflates past the … -byte limit per entry. |
| Number of entries | 10,000 | Archive rejected: it holds more than … entries. |
| Compression ratio of an entry | 100 times its compressed size (beyond 1 MiB) (exact threshold to be confirmed) | Archive rejected: entry '…' inflates more than … times its compressed size. |
| Nested archives | 3 levels | Archive rejected: '…' nests archives more than … level(s) deep. |
- An archive inside the archive is unzipped in turn (its files become files of the situation), except an XBRL report package (
META-INF/reportPackage.json). An.xlsx, detected as a workbook, is not unzipped. - Directories are ignored; a file name keeps its path inside the archive.
- The type of each file is detected from its content (Tika library), not from its extension.
- Dropped: files whose name contains
~,.ds_storeor_macos(case-insensitive), i.e. Office temporary files and macOS metadata.
Source: utils-library FileUtils, UnzipLimits; risk-import DataImportHelper.
1.3 Role of each file
| Role | Guided import | Archive dropped on the screen | Archive sent through the API |
|---|---|---|---|
| Situation information | Form | Form (after the drop); situation.json for a complete archive |
Request; situation.json for a complete archive |
| Run-off model | — | Ignored: comes from the client configuration (IMP-056) | Same |
| Classification | — | Ignored: comes from the client configuration (IMP-056) | Same |
| Curves, balance, prefixed cash flows | Slot | Slot, after the drop; files of situation.json for a complete archive |
fileRoles of the request (exact entry name); files of situation.json for a complete archive |
| Deals | Slot | All other files | fileRoles.TRANSACTIONS, and any file not listed |
In an archive, any file that is not recognised is read as a deals file: a ReadMe.txt or an extra export yields reading anomalies on that file. File names no longer say anything of their role, apart from model_ and classification: the balance, the prefixed cash flows and the curves must be declared.
Source: risk-import DataImportHelper.buildDataModel.
1.4 Checking a file on upload
Uploading a guided-import file (POST /api/v1/import/tasks/{id}/files?role=…) checks it within the request itself: risk-app reads it on its own with the draft’s client configuration and answers with its final status, VALID or INVALID (Valide or n anomalie(s) on screen), its anomalies, the summary of its content and the time of the check. There is no wait any more: the outcome is known when the upload ends. Only a file uploaded before this version can still carry the PENDING status (Vérification…): it is checked in turn when the draft is reopened and when the import is launched.
Loading a classification workbook into the client configuration is checked the same way: the answer to the upload carries the outcome of the reading (status PARSED, EMPTY or UNREADABLE, message, anomalies), and saving it into the configuration remains a second step, possible for 2 hours after the reading.
Source: risk-app ImportDraftService, ClassificationWorkbookService; risk-import FileCheck, ClassificationParse.
1.5 The import task
Launching the import (the guided import’s Lancer l'import button, POST /api/v1/import/tasks/{id}/submit, or uploading an archive) answers at once: the task becomes IN_PROGRESS (en cours). The import then runs in the background in risk-app; the task ends DONE (terminé) or FAIL (échec) with its anomalies, and a notification announces it. Leaving the screen does not stop the import. Several imports can run at the same time (3 at once, the next ones wait their turn).
A restart of the application during an import leaves it en cours without resuming it. If a task stays en cours abnormally long, report it to support.
The screen follows the task by reading its status every 3 seconds until DONE or FAIL (GET /api/v1/import/tasks/{id}?detailed=false: status, number of errors, failure message). A tool that calls the API does the same.
Source: risk-app ImportService.
1.6 Storage of uploaded files
The archive and the guided-import files are stored in the tenant’s object store (S3), under alm/<tenant>/imports/<import task>/<object>/<file name>, next to the runs (alm/<tenant>/runs/<run>/, see Run input). They are read back from there for the import, for downloading the complete situation archive, and deleted with the import task or by the purge of drafts. Each upload creates its own object (the <object> segment): a file replaced by another of the same name, or an archive rebuilt when a reopened draft is submitted again, never reuses the previous object. Files uploaded before this version stay in the database and are read the same way.
Source: risk-app ImportFileStore.
1.7 Classification at import and at run launch
The classification (§5) is applied twice:
- at import: each deal gets its account and its class (§5.4), with the resulting
CLSanomalies; this is what the situation’s portfolio and anomaly log show; - at run launch: risk-app classifies every deal of the portfolio again, with the same
risk-importclassifier, when it assembles the run input, with the client configuration that input carries, with the same rules as at import (product family, second leg, hedge role). A deal added or edited in the situation since the import is thus classified as if it had been imported. A deal with neither anInstrument Typenor ahistoline keeps the classification it already has.
Source: risk-app CashFlowGenerationService.runInputOf, DealReclassification; risk-import CLClassificationEngine.
2. Common rules
2.1 Excel workbooks
- Only the
.xlsxformat (Office Open XML) is read. The workbook is streamed rather than loaded in memory; if that read fails, it is read again in memory. - A numeric cell formatted as a date is read as a date; another numeric cell as a number; a text cell as text; a boolean as a boolean.
- A formula gives its computed value, but a formula producing a date arrives as a number (the Excel serial number): the deals convert it (§2.3), the other files do not.
- A fully blank row is skipped everywhere, without an anomaly.
- Sheet selection: see each file. When several sheets qualify, they are ranked by the alphabetical order of their names, never by their position in the workbook.
Source: poi-library ExcelStreamingReader; risk-import CLDataImporter, CLCurveImporter.
2.2 Numbers
Amounts, nominals and rates of the deals, and the amounts of the balance, are read as follows (curves and prefixed cash flows have their own rule, see their sections):
| Written as | Value | Note |
|---|---|---|
| Excel numeric cell | as is | |
1500.25, 1500,25 |
1,500.25 | a single separator is the decimal separator |
1 234,56, 1 234.56 |
1,234.56 | thousands grouped by spaces, non-breaking ones included (U+00A0, U+202F, U+2009) |
1.234,56, 1,234.56 |
1,234.56 | both separators: the right-most is decimal |
1.234 or 1,234 |
1.234 | a single separator followed by three digits stays decimal |
1.234.567, 1,234,567 |
1,234,567 | repeated thousands separators, no decimals |
4.5621405013E8, 4,56E8 |
456,214,050.13… | scientific notation |
-12,5, +12,5 |
signed | leading sign only; (12,5) or 12,5- are not numbers |
| blank | absent | never read as 0 (see each column) |
anything else (1 234,5,6, n/a) |
rejected | '…' is not a number |
Source: risk-import BaseImporter.parseDouble, TransactionParser.parseDouble.
2.3 Dates
Each file has its own rule:
| File | Excel date cell | Accepted text | Unreadable date |
|---|---|---|---|
| Deals | yes; also a number (serial, 1900 system) | yyyy-MM-dd, dd/MM/yyyy, MM/dd/yyyy, dd-MM-yyyy, MM-dd-yyyy, yyyyMMdd, dd.MM.yyyy, yyyy/MM/dd, dd/MM/yy, MM/dd/yy, dd-MM-yy, MM-dd-yy, dd.MM.yy, tried in that order |
deal rejected (Cannot parse '<key>' with value '…') |
| Balance | yes (before 31/12/1910: absent) | ddMMyyyy only (30062025) |
row dropped |
| Curves (CSV) | — | dd/MM/yyyy HH:mm only |
row ignored, warning |
| Curves (Excel) | yes, required | — | the import fails (§6) |
| Prefixed cash flows | yes | yyyy-MM-dd only |
row dropped, error |
| Reference date of the situation | — | yyyy-MM-dd (form or request) |
refused before the import |
Rules specific to the deals:
01/02/2025is 1 February:dd/MMis tried beforeMM/dd, which only applies when the day exceeds 12.- A two-digit year is read between 2000 and 2099: a 20th-century date must be written with four digits.
- A text or serial date before 01/01/1950 is read as absent (the case of an empty formula,
1899-12-30); a real date cell before that is kept. - An absent date on a required column does not stop the deal from being imported, but yields a
ConstraintViolationanomaly (§10).
Excel date cells are converted in the server’s time zone, the one Excel built them in: the day read is the day shown.
Source: risk-import TransactionParser.parseDate, BaseImporter.parseDate, CLCurveImporter, CLDataImporter.buildCashFlows.
2.4 Rates and percentages
Every rate in the files is a percentage (2,40 for 2.40 %) and is divided by 100 when read:
| File | Columns (mapping keys) |
|---|---|
| Deals | interestRate, interestMargin, liquidityMargin, commercialMargin (loans, term deposits); couponRate, couponMarginRate (securities); interestRate, rateLeg1 (repos); payBaseRate, recBaseRate, payMargin, recMargin (swaps) |
| Curves | offer |
| Prefixed cash flows | 7th column (rate) |
Not percentages: the rates of the run-off model (model_*.json), already decimal (0.015 for 1.5 %).
Source: risk-import LoanParser, TermDepositParser, SecurityTransactionParser, RepoParser, SwapParser, CLCurveImporter, CLDataImporter.
2.5 Frequencies and tenors
| Value read | Payment and review frequencies (deals) |
|---|---|
MONTHLY |
month |
QUARTERLY |
quarter |
SEMI ANNUAL |
half-year |
ANNUAL |
year |
AT MATURITY, NONE |
at maturity |
| anything else | payment: deal rejected (Cannot parse 'Frequency' …); review: left unset, INFO message |
Values are compared exactly (upper case, one space); the frequency and rateType sections of the mapping are not read (Client configuration). A blank payment frequency means one year on a loan or term deposit, and stays unset on a security or a swap leg (which yields a ConstraintViolation anomaly).
Index tenors (columns mapped under payIndexTenor, rateBasisTenor, payRateBasisTenor, recRateBasisTenor) are normalised before being compared: O/N, ON, OVERNIGHT, OVER NIGHT → 1D; <n> D|DAY(S)|W|WEEK(S)|M|MONTH(S)|Y|YEAR(S) (at most three digits, dots and dashes ignored) → nD, nW, nM, a year being 12 months (1Y = 12M = 1 YEAR). Any other value is not a tenor: the key without tenor applies (§7.7).
The frequencies of the prefixed cash flows and the maturities of the curves have their own spelling (see §6 and §8).
Source: risk-import TransactionParser.parseFrequency, TransactionParser.normaliseTenor.
2.6 Day counts
| Product | Column | Rule |
|---|---|---|
| Loan, term deposit | payConvention |
value looked up as is in rateBase; blank → rateBase.default; not in the table → rejected (Cannot parse 'RateBase' …) |
| Security | dayConvention |
same |
| Repo | interestConvention |
same |
| Swap leg | payDaysConvention / recDaysConvention (optional) |
1. a rateBase value (except default); 2. a standard spelling; 3. the market convention; never rejected (§7.6) |
The rateBase value must be an engine basis: EXACT_EXACT, EXACT_365, EXACT_360, ABB_30_360 (Calculation framework, §1.6).
Source: risk-import TransactionParser.parseBase, SwapParser.resolveDayCount.
2.7 Directions and signs
The import books every deal BUY or SELL; that direction, with the product, gives the sign of the flows (Calculation framework, §1.10).
| Product | BUY means |
Source of the direction |
|---|---|---|
| Loan | loan granted (asset) | nature: INVESTMENT → BUY, BORROWING → SELL; otherwise inferred from the instrument type |
| Term deposit | deposit taken (liability) | nature: INVESTMENT → SELL, BORROWING → BUY; otherwise inferred |
| Security | security bought | nature: INVESTMENT → BUY, BORROWING → SELL; otherwise inferred from the instrument type |
| Repo | reverse repo (cash lent) | nature: INVESTMENT → BUY, BORROWING → SELL; otherwise inferred from the instrument type |
| Swap | — | always BUY; the side of each leg comes from its prefix (pay paid, rec received) |
| Modelled balance item | — | always BUY; the sign is the sign of the balance amount |
The comparison ignores case; the inference from the instrument type, specific to each product, is described in Crédit Logement import. A value that is neither INVESTMENT nor BORROWING, or a blank cell on an instrument type that does not tell the direction, gives BUY with a warning (TRX-024 to TRX-027); a deal is never rejected for its direction.
Source: risk-import TransactionParser.parseDirection, TransactionParser.parseTransactionType, SwapParser, CLDataImporter.buildModelTransactions.
2.8 Currencies
| Object | Currency |
|---|---|
| Loan, term deposit, security, swap | The column named currency (case ignored, so Currency too), trimmed; EUR when the column is missing or the cell blank. A value that is not an ISO 4217 code rejects the deal (Currency '…' is not an ISO-4217 code). |
| Repo | always EUR (the column is checked but not used) |
| Modelled balance item | always EUR |
| Curve of the rate file | currency column of the file |
| Compound curve, liquidity spread curve | EUR |
Situation (pivotCurrency) |
value entered on the screen or given by the request, at most 3 characters |
For the column to be used, the mapping must map the currency key to currency (the shipped mapping does): the import stores the currency it settled on under that name before reading the deal.
Source: risk-import CLDataImporter.currencyOf, CLDataImporter.checkCurrency, RepoParser, CLCurveImporter.
2.9 References, counterparties, tags
- Reference:
<prefix>_<deal number>, withLO(loan),TD(term deposit),SE(security),RE(repo),SW(swap). A number read from a numeric cell loses its decimal part (6443.0→6443). Uniqueness is not checked: two rows with the same number give two deals with the same reference. - Modelled items:
<PRODUCT>_<strategy reference>_<account>, e.g.ACCOUNTING_291200**_29120005. - Counterparty: the column value; blank →
DEFAULT_NAME. It is created with typeRETAIL, ratedA. Modelled items have the counterpartyDEFAULT, of typeCORPORATE. - Tags (
tags): for each listed column (name compared case-insensitively), its value is copied. A blank cell in a workbook rejects the row (Tag column '<column>' is blank., Crédit Logement import). - Raw data: the row read is kept as is with the deal (
Transaction Datatab of the situation), unmapped columns included.
Source: risk-import TransactionParser.getReference, TransactionParser.findOrCreateCounterparty, CLDataImporter.parseTransaction, CLDataImporter.buildModelTransactions.
3. Situation information
The arrêté no longer comes from an info_*.json: it is entered on the import screen, read from the situation.json of a complete archive, or given in the API request. risk-app saves it on the task and hands it to the import.
| Field | Reading | When missing or blank |
|---|---|---|
| client | the client configuration’s; no longer entered | — |
portfolioName |
text, at most 100 characters | warning; name default_name (IMP-030) |
portfolioReference |
text, at most 100 characters, and fewer depending on the client (see below) | warning; reference default_reference (IMP-029) |
referenceDate |
date yyyy-MM-dd; arrêté and evaluation date |
the import fails (IMP-059) |
discountFactorIndex |
a key of compoundCurve or a value of indexes; a key of indexes becomes its value |
the import fails (IMP-059) |
pivotCurrency |
text, at most 3 characters | the import fails (IMP-059) |
- Lengths are checked on receipt: the form or the request is refused (400 error on the field), for example “portfolioName is 101 characters long, at most 100 are allowed.”.
- The context reference,
[<client> - <referenceDate>] Context <portfolioReference>, holds 100 characters: the configuration’s client andportfolioReferencetogether therefore have at most 76 (61 for the reference with the clientcredit logement). An archive sent through the API that exceeds it gives aFAILtask (IMP-007). - Through the API, an archive without
situation.jsonalso gives the role of its files:"fileRoles": {"RATE_CURVES": ["RT_indices.txt"], "ACCOUNTING": ["COMPTA.xlsx"], "CASHFLOWS": ["cashflows.xlsx"]}, by exact entry name; a file not listed is a deals file. - The discount index used must name a curve of the context (case-insensitive); otherwise an
ERRORanomalyMissingCurve(CRV-018) reports it: no other index replaces it, and at calculation every flow after the reference date is left without a discount factor.
Source: risk-app ImportService, ImportDraftService, ImportInfoLimits; risk-import DataImportHelper, ImportDataModel, CLDataImporter.buildContextModel.
4. Run-off model (model_*.json)
| Key | Content |
|---|---|
outflowStrategies[] |
List of strategies. @type: LinearOutflowStrategy, BucketOutflowStrategy or ScriptOutflowStrategy; any other type makes the file unreadable. |
…productName |
Product of the strategy; upper-cased for the item’s reference (accounting → ACCOUNTING). |
…reference |
Account prefix followed by stars (291200**); the stars are removed for the comparison. |
…rate |
Rate of the item, decimal: type (FIXED/FLOATING), value, spread, index, base, interestMode (SIMPLE/COMPOUND). |
…frequency, …timeHorizon |
Linear law: frequency (MONTH, QUARTER, SEMESTER, YEAR, AT_MATURITY) and horizon (6Y). |
…curve |
Bucket law: maturity → share. |
…language, …scriptName, …function |
Script law. |
…strategyType |
Origins (contractual, behavioural view) the law applies to. |
balanceSheetEvolutionStrategy |
Optional: ConstantBalanceSheetStrategy (rollHorizon), GrowthBalanceSheetStrategy (rollHorizon, annualGrowthPct), RunOffBalanceSheetStrategy. |
What these laws mean is described in Constant and behavioural balance sheet.
4.1 Assigning balance lines
- Each balance line is assigned to one strategy only: the one whose prefix (reference without stars) is the longest prefix of its account. A line several prefixes match gets a warning naming the strategy kept.
- Two strategies with the same prefix: the first listed applies, the others are ignored, with a warning.
- A line no prefix matches is not modelled, without an anomaly.
- Each assigned line becomes a deal: “accounting balance” product, amount of the line (sign included) in EUR, account label trimmed, law and rate of the strategy, transaction and settlement date = reference date, direction
BUY. - Its classification account is the strategy’s prefix, not the line’s account (Crédit Logement import); if it is not exactly once in
mapping_compta, the line is dropped with an error.
Source: risk-model OutflowStrategyModel; risk-import CLDataImporter.assignOutflowStrategies, CLDataImporter.buildModelTransactions, CLClassificationEngine.
5. Classification (classification*.xlsx)
This workbook is loaded into the Classification section of the client configuration, which exports one in the same layout; the import reads the classification from the configuration. The rules below are those of its reading.
Three sheets, looked up by their exact name. mapping_compta and mapping_compta_irrbb are required (otherwise: an error naming the sheets present, and no deal is classified); histo is optional.
5.1 mapping_compta sheet: accounts
Two header rows; data starts on the third row. Columns are read by position.
| Col. | Header (generated workbook) | Reading | On a problem |
|---|---|---|---|
| A | Poste Comptable |
numeric cell, integer part; or text made of letters then digits (H96…), as is |
other text (a number formatted as Text) → row dropped (ERROR, ClassCastException, CLS-009) |
| B | Bilan |
side: Actif, A, Asset → asset; Passif, P, L, Liability → liability; HB, Hors bilan → off-balance (case ignored, no extra space) |
blank → row skipped (WARNING); other value → row dropped (ERROR) |
| C | Contrepartie |
text | blank → row skipped (WARNING) |
| D | Map |
not read | |
| E | Operation Financiere |
boolean | |
| F | Actif Modelise |
boolean | |
| G | Gross Carrying Amount |
boolean | |
| H | Nominal |
boolean | |
| I | EVE |
boolean | |
| J | MNI |
boolean | |
| K | Sensible Taux |
boolean | |
| L | Signe |
integer; blank → 0 | non-numeric text → row dropped |
| M | MV |
boolean |
Booleans: blank, false, 0, no, n, non → false; true, 1, yes, y, oui, o, x → true (case ignored); a number is true when positive; any other text drops the row with an error.
The category of an account is the string <Bilan> <Contrepartie>, built from the cells as written; that is what is looked up in mapping_compta_irrbb.
5.2 mapping_compta_irrbb sheet: categories
One header row; data from the second row.
| Col. | Header | Reading | On a problem |
|---|---|---|---|
| A | Map |
category <Bilan> <Contrepartie>, text, compared exactly with that of mapping_compta |
|
| B | FINREP |
name of an engine FINREP row (A_LOANS_AND_ADVANCES…), case-sensitive |
unknown → WARNING, the category has no FINREP code |
| C | Row Code (optional, found by its header) |
J 02.00 row number (270, 270.0, "0270") |
differs from the chosen FINREP code → the row is rejected (ERROR) |
| D | Hedge Role (optional) |
MACRO, MICRO, INDEX, NONE, UNSPECIFIED (case ignored) |
other → WARNING, role unspecified |
Side check: an asset category (Bilan Actif…) mapped to a liability FINREP row (L_…), or the reverse, is rejected with an error; its deals have no FINREP code and leave the whole reporting. Off-balance categories and FINREP rows without a side (OFF_BS_…, OTHER_DERIVATIVES) are not compared.
A mapping_compta category with no row here gets one warning, with its number of accounts; its deals will be excluded from the whole reporting, J 01.00 totals included (MissingClassification warning).
The hedge role is only applied to deals classified on a derivatives row (A_DERIVATIVE_HEDGING…, L_DERIVATIVE_HEDGING…, OTHER_DERIVATIVES): UNSPECIFIED when the category says nothing; every other deal has role NONE.
5.3 histo sheet: account of each deal
One header row (N° histo, Poste comptable, Instrument / Line ID).
| Col. | Reading | On a problem |
|---|---|---|
| A | deal number, numeric cell | not numeric → row dropped (ERROR) |
| B | account, numeric cell | not numeric → row dropped (ERROR); account not in mapping_compta → row skipped (WARNING) |
| C | label, for reference | not read |
A deal listed twice on the same account: warning. On two different accounts: error, and the deal takes the account of the instrumentAccounts mapping.
5.4 Account and classification of a deal
| Object | Account used |
|---|---|
| Modelled balance item | prefix of its strategy |
Deal present in histo |
account in histo (deal number = reference without its prefix) |
| Other deal | instrumentAccounts rule of the configuration (Accounting account of the deals): instrument type (Instrument Type, compared ignoring case and surrounding spaces), then sub-family, then family (value of the products mapping, security for the securities file) |
| Deal no rule covers | no account: imported unclassified |
An exact account must appear exactly once in mapping_compta; a starred account (9431**) must cover at least one account, and all those it covers must share a FINREP row. Otherwise a modelled balance line is rejected (Mapping for 'Classification' 'account' and reference '…' is missing); a deal is imported unclassified. Each deals file reports, in a Classification / Account warning, its deals without an account (by instrument type) and those whose account cannot be classified (with the reason).
Source: risk-import CLDataImporter.buildClassification, CLDataImporter.buildHistoAccounts, CLDataImporter.hedgeRoleOf, CLClassificationEngine, DataMapper; risk-app ClassificationAccountSheet, ClassificationCategorySheet, ClassificationHistoSheet.
6. Rate curves
The file is accepted as an Excel workbook or as text (.csv, .txt). The format of each column is given in Import an ALM situation; here is how it is read.
| Text file | Excel workbook | |
|---|---|---|
| Separator, encoding | ; only; UTF-8, BOM tolerated |
— |
| Header | first line | first row with at least 8 filled cells of the sheet used |
| Sheet | — | the one whose header carries the five columns; several → the first in alphabetical order (warning); none → the first sheet in alphabetical order |
| Rows read | all | only those with at least 8 filled cells; the others are ignored without an anomaly |
| Column names | offer, ratedate, currency, ratename, timeband, lower case, exact |
same; a missing column → error, no curve read |
offer |
number, decimal comma or point, no thousands separator; ÷ 100 | numeric cell ÷ 100, or text as in CSV |
ratedate |
dd/MM/yyyy HH:mm; the time is ignored |
date cell required |
timeband |
see below | same |
| Invalid row | ignored, warning Unable to parse index… |
missing cell or invalid value: ignored, warning |
timeband: ACTUAL → 0 days (spot point); OVERNIGHT → 1 day; <n> WEEK(S), <n> MONTH(S), <n> YEAR(S) (case ignored, one space) → n weeks, months, years. Anything else → row ignored.
6.1 Building the curves
- One curve per (
ratename, quote date): a file covering a month of quotes yields as many curves per index as days. Two points of the same maturity in one curve: the last one read wins, without an anomaly. - Each point is tagged swap if the index name contains
SWAP(case ignored), money market otherwise; the quotation (ZEROorPAR) comes fromcurveQuotations(Client configuration). - The refixing period of an index is read from its name:
ESTR,EONIAorO/N→ 1 day;12M/1Y→ 12 months;6M,3M,1M→ 6, 3, 1 months; otherwise none (the engine will assume 3 months, with a warning at calculation time). - A curve dated more than 50 days from the reference date, before or after, gets a warning.
- A zero liquidity spread curve (
LIQUIDITY_SPREAD, EUR, points 1 day, 1 month, 10 years) is always added. - Mapping check: every value of
indexesand every leaf curve ofcompoundCurvemust exist in the file (case and extra spaces ignored); otherwise an error on the rate file names the labels concerned.
An unexpected error while reading (unrecognised file type, text ratedate in a workbook…) fails the import: Unable to build the evaluation context from '<file>'.
6.2 Compound curves
For each compoundCurve entry ("DISCOUNT_EUR": {"1d": "ESTR", "1Y": "EURIBOR", "100y": "ESTR SWAP"}):
- the thresholds (
1d,1Y,100y…) are sorted from shortest to longest; - for each threshold, the leaf curve used is the one whose quote date is nearest the reference date (the most recent one when a file is checked on its own);
- it contributes its points with a maturity less than or equal to the threshold; a point of the same maturity contributed by a longer threshold replaces the earlier one;
- the compound curve takes the entry’s name, the EUR currency and the reference date;
- if a leaf curve is missing, the compound curve is not built (the error is carried by the mapping check);
- a faulty threshold leaves the compound curve out with a
CompoundCurveerror, its object being the curve’s name:Compound curve '<name>' is not built: its threshold '<key>' is not a tenor such as 3m or 10y.,… its threshold '<key>' names no index., or… its thresholds '<key>' and '<key>' are the same tenor.(1yand1Y). Any other failure readsCompound curve '<name>' is not built: <cause>.
Source: risk-import CLCurveImporter, RateCurveHelper.determineFixingPeriod.
7. Deals
7.1 Reading the files
Text file (.csv, .txt) |
Excel workbook | |
|---|---|---|
| Separator, encoding | ; only; UTF-8, BOM tolerated; CSV-standard quotes |
— |
| Header | first line; exact names, spaces included | in each sheet, the first row with more than 5 filled cells; the rows above are skipped |
| Sheets read | — | those whose header carries Instrument Type; the others are ignored (warning if the sheet has a header, information otherwise); no such sheet → error |
| End of reading | a malformed line stops reading the file, the rows already read are kept, an error says where | |
| Summary | Imported n lines from m per file (INFO), or …: k line(s) rejected (ERROR) |
same, per sheet |
A column named by a required mapping key must exist in the file, even empty; otherwise every row is rejected (Record does not contain field '…'). An optional key may be missing from the mapping as well as from the file. A rejected row yields two anomalies: the cause, on the deal’s reference when it is known, and Cannot import the transaction at row <n> of sheet '<sheet>' of '<file>' (or line <n>) with the raw row.
7.2 Choosing the product
- The value of the
Instrument Typecolumn is looked up exactly in theproductssection of the mapping. - A file whose name contains
securities(case ignored) is read as securities, whatever the value: the column carries the ISIN there. - The product must be
loan,term_deposit,security,repoorswap.nantissementhas no reader: the row is rejected. A value missing fromproductsrejects the row (Cannot parse 'ProductMapping' with value '…'). A value ofproductsthat is none of the engine’s products rejects it too:Instrument type '<type>' is mapped to product '<value>', which is not a product of the engine (expected one of […]).A blankInstrument Typerejects it with'Instrument Type' is blank, so the deal cannot be matched to a product.Since the product, hence the prefix, is not known yet, these two anomalies are located on<file> / Deal Number <number>. - Order of the checks on a row: product, reading of the columns, currency, tags, then (at import only) classification.
In the tables below, Req. marks a required mapping key; “blank” means a blank or missing cell. A blank cell on a required column is not a rejection in itself: depending on the column it gives a default, a rejection, or a ConstraintViolation anomaly on a deal that is kept.
7.3 Loans and term deposits (loan, term_deposit)
| Key | CL column | Req. | Reading | Blank / invalid |
|---|---|---|---|---|
reference |
Deal Number |
yes | reference LO_… / TD_… |
|
instrumentType |
Instrument Type |
yes | contains Capitalise (case ignored) → compound interest; on a term deposit, a single coupon at maturity |
blank → rejected (Instrument type (column '…') is blank, so whether its interest is capitalised cannot be read.) |
counterparty |
Counterparty |
yes | §2.9 | DEFAULT_NAME |
currency |
currency |
yes | §2.8 | EUR |
dealDate |
Deal Date |
yes | transaction date | ConstraintViolation |
settlementDate |
Settlement Date |
yes | start date | ConstraintViolation (loan) |
maturityDate |
Effective Maturity Date |
yes | maturity | ConstraintViolation |
callDate |
DateCall |
yes | call date | no call |
nominal |
Original Face Value |
yes | number | ConstraintViolation; not numeric → rejected |
remainingNominal |
Remaining Face Value |
no | outstanding used instead of the nominal, 0 included; a gap above 0.005 → warning | original nominal |
rateType |
Fixed or Floating |
yes | FIXED / FLOATING, case ignored |
other → rejected (Rate type '…' (column '…') is neither 'Fixed' nor 'Floating'.); blank → rejected (Rate type (column '…') is blank; it must be 'Fixed' or 'Floating'.) |
interestRate |
Interest Rate |
yes | % ÷ 100; on a floating rate, 0 = unknown fixing (rate read on the curve) | blank: no rate |
interestMargin |
Interest Rate Margin |
yes | % ÷ 100 → spread | no spread |
payIndex |
Basis |
yes | rate label → index (§7.7) | rate without index |
payIndexTenor |
Basis Rate Frequency Time Band |
no | tenor (§2.5) | key without tenor |
payConvention |
Days Convention |
yes | day count (§2.6) | rateBase.default; unknown → rejected |
paymentFrequency |
Payment Frequency |
yes | §2.5 | year; unknown → rejected |
reviewFrequency |
Review Frequency |
no | floating rate only; stored, not used yet | unknown → unset, INFO |
nature |
(not in the IRRBB_MM view) |
no | direction (§2.7) | inferred from the instrument type |
liquidityMargin, commercialMargin |
— | no | loan only; % ÷ 100 | liquidity spread of the context |
liquidityCurveIndex |
— | no | loan only; resolved like a rate label | none |
Source: risk-import LoanParser, TermDepositParser, TransactionParser.
7.4 Securities (security)
| Key | CL column | Req. | Reading | Blank / invalid |
|---|---|---|---|---|
reference |
Deal Number |
yes | reference SE_… |
|
isin |
Instrument Type |
yes | ISIN | |
nature |
Borrow or Invest |
yes | INVESTMENT → BUY, BORROWING → SELL |
inferred from the instrument type, otherwise BUY (§2.7) |
counterparty |
Counterparty Name |
yes | DEFAULT_NAME |
|
currency |
currency |
yes | §2.8 | EUR |
dealDate |
Deal Date |
yes | transaction date | ConstraintViolation |
settlementDate |
Settlement Date |
yes | settlement and start date | ConstraintViolation |
maturityDate |
Effective Maturity Date |
yes | maturity | ConstraintViolation |
callDate, issuerCallDate |
DateCall, DtCallEmet |
no | the first one filled; both and different → the earlier, with a warning | no call |
nominal |
Original Face Value |
yes | number | ConstraintViolation |
remainingNominal |
Remaining Face Value |
no | outstanding used, with a warning on a gap | original nominal |
rateType |
Fixed or Floating |
yes | FIXED / FLOATING, case ignored |
other or blank → rejected |
couponRate |
Coupon Rate |
yes | % ÷ 100 → rate of a fixed security | 0 %, warning if the security is fixed |
couponMarginRate |
Coupon Margin Rate |
yes | % ÷ 100 → margin of a floating security | 0 %, warning if the security is floating |
rateBasis |
Basis |
yes | rate label → index | rate without index |
rateBasisTenor |
Basis Rate Frequency Time Band |
no | tenor | key without tenor |
dayConvention |
Convention de calcul |
yes | day count | rateBase.default; unknown → rejected |
frequency |
Coupon Frequency |
yes | §2.5 | ConstraintViolation; unknown → rejected |
reviewFrequency |
Review Frequency |
no | as for loans | |
rate, marginRate, issuer, entity, product |
various | no | not read (kept in the raw data) |
For couponRate and couponMarginRate, a non-numeric value is 0 % like a blank cell, instead of rejecting the security; a column missing from the file, on the other hand, rejects every row.
Source: risk-import SecurityTransactionParser, TransactionParser.
7.5 Repos (repo)
| Key | CL column | Req. | Reading | Blank / invalid |
|---|---|---|---|---|
reference |
Deal Number |
yes | reference RE_… |
|
instrumentType |
Instrument Type |
yes | kept on the product | ConstraintViolation |
nature |
Borrowing Investing (two spaces) |
yes | INVESTMENT → BUY (reverse repo), BORROWING → SELL |
inferred from the instrument type, otherwise BUY (§2.7) |
counterparty |
Counterparty |
yes | DEFAULT_NAME |
|
panier |
Panier |
yes | ISIN of the basket | |
dealDate, settlementDate, maturityDate |
Deal Date, Settlement Date, Effective Maturity Date |
yes | dates | ConstraintViolation |
callDate |
DateCall |
no | unwinding date in the behavioural view | no call |
interestRate |
Interest Rate |
yes | % ÷ 100, fixed rate, simple interest, spread 0 | no rate |
rateLeg1 |
Interest Rate Leg 1 |
yes | % ÷ 100, same basis | no rate |
interestConvention |
Interest Days Convention |
yes | day count of both rates | rateBase.default; unknown → rejected |
originalFaceValue |
Original Face Value |
yes | nominal | blank amount |
leg2FaceValue |
Leg Two Original Face Value |
yes | nominal of leg 2 | blank amount |
interestAmount |
Interest Amount |
yes | interest amount | blank amount |
Every amount of a repo is in EUR.
Source: risk-import RepoParser, TransactionParser.
7.6 Swaps (swap)
A paid leg (prefix pay) and a received leg (prefix rec), read with the same rules; the table names the pay… keys.
| Key | CL column | Req. | Reading | Blank / invalid |
|---|---|---|---|---|
reference |
Deal Number |
yes | reference SW_… |
|
counterparty |
Counterparty |
yes | DEFAULT_NAME |
|
currency |
currency |
yes | currency of both legs | EUR |
nominal |
Original Face Value |
yes | nominal of both legs; the outstanding is not read | ConstraintViolation |
settlementDate, maturityDate |
Settlement Date, Effective Maturity Date |
yes | start and maturity | ConstraintViolation |
dealDate |
Deal Date |
no | transaction date | settlement date |
callDate |
DateCall |
no | no call | |
payBaseRate |
Pay base rate |
yes | % ÷ 100; fixed rate, or last fixing for information | blank → rejected (The pay leg has no base rate: column '…' is blank.); not numeric → rejected (Cannot parse 'payBaseRate'…) |
payMargin |
Pay margin |
yes | % ÷ 100 → spread | no spread |
payRateBasis |
Pay Rate Basis |
yes | rate label → index | fixed leg (if no type) |
payRateBasisTenor |
Pay Rate Basis Freq Time Band |
no | tenor | key without tenor |
payRateType |
Pay Fixed/Floating |
no | FIXED / FLOATING (case ignored) decides the type |
other or blank: floating if a rate label is given, fixed otherwise |
payFrequency |
Pay Frequency |
yes | §2.5 | ConstraintViolation; unknown → rejected |
payDaysConvention |
Days Convention |
no | see below | market convention |
payReviewFrequency |
Pay Review Frequency |
no | as for loans | |
pay1stPaymentDate |
Pay 1st Payment Date |
no | check only: a gap of more than 4 days with the schedule → warning |
Leg type: flagged floating without a label → valued at its current rate, warning; flagged fixed with a label → fixed, label kept for information, warning. The schedule is rolled back from maturity, always with simple interest.
Day count of a leg, in this order (Crédit Logement import):
- a
rateBasevalue, exceptdefault, and except a business-day rule; - a standard spelling, compared after upper-casing,
ACTUAL→ACT, spaces and brackets removed:30/360,30E/360,30U/360,360/360,BONDBASIS,EUROBONDBASIS→ 30/360;ACT/360,A/360,A360→ ACT/360;ACT/365,ACT/365F,ACT/365FIXED,A/365,A365→ ACT/365;ACT/ACT,ACT/ACTISDA,ACT/ACTICMA,A/A→ ACT/ACT; - otherwise the market convention: fixed EUR leg → 30/360; floating EUR leg whose label names EURIBOR, €STR (
ESTR,ESTER,IESTR,IESTER,€STR,EURO SHORT-TERM RATE) or EONIA (EURO OVERNIGHT INDEX AVERAGE) → ACT/360; other →rateBase.default.
A business-day rule is any value containing FOLLOWING, PRECEDING or BUSINESS DAY, or equal to ACTUAL DATE, UNADJUSTED or NO ADJUSTMENT. Each file says once how many legs took the market convention, and why.
Source: risk-import SwapParser, TransactionParser, CLDataImporter.reportDayCountFallbacks.
7.7 Resolving rate labels
For a rate label (Basis, Pay Rate Basis…):
- with a recognised tenor, a
label|tenorkey ofindexes(exact label, normalised tenor); - otherwise the exact
labelkey; - otherwise the label is not mapped: the deal is kept with a warning, and:
- fixed rate: nothing changes;
- floating rate whose label is the name of a curve of the file (case ignored): that curve;
- otherwise: no index, the deal is valued at its current rate and does not react to the shocks.
When a file is checked on its own the curves are unknown: only the warning is issued. The original label is always kept on the rate.
Source: risk-import TransactionParser.lookupIndex.
8. Prefixed cash flows
| Rule | |
|---|---|
| Format | .xlsx workbook only |
| Sheet | the one holding a Deal No or action_dt cell (case ignored); several → the first in alphabetical order, warning; none → the first sheet, warning, data read from the 3rd row |
| Data | from the row after the header; columns read by position |
| Invalid row | dropped, error naming the row |
| Unreadable file | error; the import goes on without prefixing, with a Missing anomaly per deals file |
| Col. | Content | Reading |
|---|---|---|
| 1 | deal number | numeric cell → integer part; text as is |
| 2 | instrument | text |
| 3 | basis (index) | text |
| 4 | frequency of the basis rate | <n> <unit>, unit containing year, month, week or day (3 months); empty text accepted (no frequency); other → row dropped |
| 5 | component | text |
| 6 | fixing date | date cell, or yyyy-MM-dd text |
| 7 | rate | % ÷ 100; number with a decimal point |
A missing cell (blank in the workbook) in any of the seven columns drops the row (inferred from the code).
At calculation time a line applies to the deal whose reference, split at the first _, has this number as its second part; it only applies until fixing date + frequency — without a frequency it never applies. Several lines for one deal: error, none is used (§4.5 of the methodology).
Source: risk-import CLDataImporter.buildCashFlows, RateCurveHelper, PrefixingLines.
9. Accounting balance
| Excel workbook | Text file (.txt, .csv) |
|
|---|---|---|
| Where | i1-balance sheet (missing → the import fails); row 1 = header |
no header: the first line is an account line |
| Separator | — | the most frequent of ;, tab, ,, \| on the first line (on a tie, in that order) |
| Encoding | — | UTF-8 |
| Columns | A date, B account, C label, D amount | 1 account, 2 label, 3 amount, 4 date; the following ones are ignored; a shorter line is padded with blank cells |
| Account | numeric cell → integer; text (H96…) as is; blank → row dropped |
as is |
| Label | text; blank → row dropped | text, trimmed when modelled |
| Amount | §2.2; blank → row dropped | same |
| Date | date cell, blank, or ddMMyyyy text; other → row dropped |
ddMMyyyy text required; blank or other → row dropped |
| Other extension | the import fails |
A dropped row is reported with its number and raw content. Balance lines only become deals when a strategy of the run-off model covers them (§4.1).
A text file saved as “UTF-8 with BOM” keeps the BOM in front of the first account, which then no longer starts with a strategy prefix and is not modelled, without an anomaly (inferred from the code). Save the balance as UTF-8 without BOM.
Source: risk-import CLDataImporter.parseAccountingData, DataImportHelper.readTxtFile, DataImportHelper.detectSeparator, BaseImporter.
10. Anomalies raised at import
The type is the one of the Code or type filter of the anomaly log. Each anomaly also carries a code, described in the Anomaly reference: domains IMP, VAL, CRV, TRX, CLS and BAL for the import, raised by risk-app, most of them by the risk-import library (Emitting service).
| Type | Level | Raised when |
|---|---|---|
Upload |
ERROR |
archive empty, not a zip, or refused (risk-app) |
BadContent |
ERROR |
unreadable archive or JSON file, unzip limit exceeded |
MissingInput |
ERROR |
required file not found, blank declared name |
UnknownDataFormat |
ERROR |
no reader for the configuration’s format |
Missing |
ERROR |
essential data missing (client, pivotCurrency, unreadable prefixed cash flows…), repeated for each deals file |
Index |
WARNING / ERROR |
curve more than 50 days from the reference date (WARNING); mapped index missing from the rate file, discount index not mapped (ERROR) |
RateCurveParsing |
WARNING / ERROR |
curve row ignored, several curve sheets (WARNING); missing curve column (ERROR) |
CompoundCurve |
ERROR |
compound curve cannot be built |
MissingCurve |
ERROR |
the discount index names no curve of the context |
EvaluationContext, Accounting |
ERROR |
unreadable rate or balance file: the import fails |
Accounting / AccountType |
WARNING |
ledger accounts neither the classification nor accountingMapping types, by class (count, balance) |
Classification |
WARNING / ERROR |
classification row or sheet (§5), deals without an account (§5.4) |
CashFlows |
WARNING / ERROR |
prefixed cash flows (§8) |
Parsing |
WARNING / ERROR |
unreadable value (Cannot parse '…' with value '…'), blank security coupon, two call dates |
Mapping |
INFO / WARNING / ERROR |
unmapped rate label, default direction, different outstanding, missing classification account |
Import |
INFO / WARNING / ERROR |
unreadable deals file, sheet ignored, reading interrupted |
ImportTransaction |
ERROR |
rejected deal row, with the raw row |
ImportSynthesis |
INFO / ERROR |
Imported n lines from m summary of each file or sheet |
Direction, DayCount |
WARNING |
inferred directions, default day counts, once per file |
ConstraintViolation |
ERROR |
required value missing on a deal, the portfolio or the context; the object is kept |
UnexpectedError |
ERROR |
unexpected error; the import fails |
Persistence |
ERROR |
risk-app could not store the result |
Every deal rejected for a cause the importer can name ends its message with The deal is not imported., on the deal’s reference. A deal rejected by an unforeseen error keeps the generic Cannot parse a transaction of '<file>': …, on the file.
Source: risk-import SituationImport, DataImportHelper, CLDataImporter, CLCurveImporter, TransactionParser; risk-app ImportService.
11. Known limits
- One format only:
CREDIT_LOGEMENT. TheIRRBB_MM,Swaps_IRRBB,Securities_IRRBBandREPOviews are the only ones read; pledges (NANT-…) are rejected. - Deal numbers: a number read from a numeric cell is converted to a 32-bit integer; beyond 2,147,483,647 it is wrong, and its decimals are lost (same rule in the
histosheet). Duplicates are not detected. A number containing_cannot be matched with a prefixed cash flow. - Curves in Excel: a row with fewer than 8 filled cells is ignored without an anomaly; a workbook carrying only the five required columns yields no curve. The text file has no such limit.
- Currency of repos and modelled items: always EUR.
- Review frequency: stored but not used; a floating rate is reset on every payment date.
frequencyandrateTypesections of the mapping: not read.- Balance date: required and in
ddMMyyyyformat in a text file, although it is not used in the calculation (to be confirmed). - Per-file check: without classification, curves, reference date or consistency checks (§1).
- Production mapping: the real extracts and their production mapping are not in the repository; this page describes the rules of the code, valid whatever the mapping, and the columns of the shipped mapping.