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.

Note

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.

Warning

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_store or _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
Warning

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).

Warning

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 CLS anomalies; 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-import classifier, 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 an Instrument Type nor a histo line keeps the classification it already has.

Source: risk-app CashFlowGenerationService.runInputOf, DealReclassification; risk-import CLClassificationEngine.

2. Common rules

2.1 Excel workbooks

  • Only the .xlsx format (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/2025 is 1 February: dd/MM is tried before MM/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 ConstraintViolation anomaly (§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>, with LO (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 type RETAIL, rated A. Modelled items have the counterparty DEFAULT, of type CORPORATE.
  • 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 Data tab 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 and portfolioReference together therefore have at most 76 (61 for the reference with the client credit logement). An archive sent through the API that exceeds it gives a FAIL task (IMP-007).
  • Through the API, an archive without situation.json also 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 ERROR anomaly MissingCurve (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

  1. 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.
  2. Two strategies with the same prefix: the first listed applies, the others are ignored, with a warning.
  3. A line no prefix matches is not modelled, without an anomaly.
  4. 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.
  5. 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).

Warning

An unreadable classification (corrupt workbook, missing sheet: CLS-003, CLS-004) rejects no deal: the deals and the modelled balance lines are imported without a FINREP row, and their cash flows are computed (CLS-002, CLS-018). Fix the workbook and import again to classify them.

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

  1. 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.
  2. Each point is tagged swap if the index name contains SWAP (case ignored), money market otherwise; the quotation (ZERO or PAR) comes from curveQuotations (Client configuration).
  3. The refixing period of an index is read from its name: ESTR, EONIA or O/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).
  4. A curve dated more than 50 days from the reference date, before or after, gets a warning.
  5. A zero liquidity spread curve (LIQUIDITY_SPREAD, EUR, points 1 day, 1 month, 10 years) is always added.
  6. Mapping check: every value of indexes and every leaf curve of compoundCurve must 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"}):

  1. the thresholds (1d, 1Y, 100y…) are sorted from shortest to longest;
  2. 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);
  3. 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;
  4. the compound curve takes the entry’s name, the EUR currency and the reference date;
  5. if a leaf curve is missing, the compound curve is not built (the error is carried by the mapping check);
  6. a faulty threshold leaves the compound curve out with a CompoundCurve error, 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. (1y and 1Y). Any other failure reads Compound 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

  1. The value of the Instrument Type column is looked up exactly in the products section of the mapping.
  2. A file whose name contains securities (case ignored) is read as securities, whatever the value: the column carries the ISIN there.
  3. The product must be loan, term_deposit, security, repo or swap. nantissement has no reader: the row is rejected. A value missing from products rejects the row (Cannot parse 'ProductMapping' with value '…'). A value of products that 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 blank Instrument Type rejects 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>.
  4. 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):

  1. a rateBase value, except default, and except a business-day rule;
  2. 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;
  3. 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…):

  1. with a recognised tenor, a label|tenor key of indexes (exact label, normalised tenor);
  2. otherwise the exact label key;
  3. 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).

Warning

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. The IRRBB_MM, Swaps_IRRBB, Securities_IRRBB and REPO views 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 histo sheet). 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.
  • frequency and rateType sections of the mapping: not read.
  • Balance date: required and in ddMMyyyy format 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.