๐ง Generic CSV Provider
The Generic CSV Provider (broker_generic_csv) is the fallback import plugin for BRIM. It accepts any CSV file that follows the column conventions below โ even if it does not come from a specifically supported broker.
One file per broker
Generic CSV must use one separate file per broker. Each file is assigned exactly one broker; never combine multiple brokers into one flat CSV. The wizard still allows multiple files and brokers, and multiple currencies for a single broker are valid โ this is not one file per currency. This reflects the current parser flow, where broker_id is passed per file/parse, not a new restriction on monthly files.
๐ค Tip: Use an LLM to write your conversion script
The fastest way to import data from an unsupported source is to paste this entire page into an LLM and ask it to write a Python script that transforms your data into the Generic CSV format.
Suggested prompt
Here is the LibreFolio Generic CSV format specification:
[paste this page]
I have data in this format:
[paste your file's header row and 2โ3 sample rows]
Write a Python script that reads my file and produces a valid LibreFolio Generic CSV.
The LLM will produce a working script. Import the output CSV directly via BRIM.
Watch for sign convention errors โ this is the most common mistake. See Sign Conventions below.
โญ Key Features
- Header Auto-Detection: Does not rely on fixed column names โ maintains a dictionary of common synonyms per field.
- Flexible Date Parsing: Tries
YYYY-MM-DD,DD/MM/YYYY,MM/DD/YYYY, and others automatically. - Flexible Number Parsing: Handles both US (
1,234.56) and European (1.234,56) formats. - Transaction Type Mapping: Maps keywords (
buy,acquisto,compra, โฆ) to theTransactionTypeenum. - Low Priority:
detection_priority = 0, so specific high-confidence plugins are always tried first.
๐ Column Mapping Reference
| Column | Required | Description |
|---|---|---|
date |
โ Always | Transaction date. Accepts 2023-12-31, 31/12/2023, etc. |
type |
โ Always | One of: BUY, SELL, DIVIDEND, INTEREST, DEPOSIT, WITHDRAWAL, FEE, TAX, ADJUSTMENT |
quantity |
Depends on type | Number of units. See Sign Conventions. |
amount |
Depends on type | Net cash impact. See Sign Conventions. |
currency |
Optional | ISO 4217 code (EUR, USD). Defaults to EUR. |
asset |
Depends on type | Asset identifier. See Asset Identifier. |
description |
Optional | Free text. Used as fallback for asset name resolution when no identifier is available. |
TRANSFER, FX_CONVERSION and CASH_TRANSFER are rejected
Paired-leg types (TRANSFER, FX_CONVERSION, CASH_TRANSFER) require two
transactions linked by link_uuid, which a flat CSV cannot express. The
parser raises Unknown transaction type (or an explicit pairing error) for
them. Use manual entry or a broker-specific plugin for paired movements.
๐ข Sign Conventions
This is the most common mistake when writing conversion scripts
LibreFolio uses an investor perspective for signs:
quantity: positive when you receive units, negative when you deliver unitsamount: positive when cash enters your account, negative when cash leaves your account
๐ Per-type quick reference
| Type | quantity sign |
amount sign |
Notes |
|---|---|---|---|
BUY |
+ (receive units) |
โ (pay cash) |
e.g. quantity=10, amount=-1500.00 |
SELL |
โ (deliver units) |
+ (receive cash) |
e.g. quantity=-1, amount=+62.36 |
DIVIDEND |
none (0 or empty) | + |
Cash distribution received |
INTEREST |
none | + |
Interest income received |
DEPOSIT |
none | + |
Cash entering the broker account |
WITHDRAWAL |
none | โ |
Cash leaving the broker account |
FEE |
none | โ |
Commission or fee paid |
TAX |
none | โ |
Tax or withholding paid |
ADJUSTMENT |
+ or โ |
must be empty | Quantity-only correction (splits, gifts, inheritance seeding). No cash movement. |
Inherited cost basis (WAC) is PER-UNIT
An ADJUSTMENT row that seeds an inherited or transferred position
(you owned it before, with a known purchase cost) carries a frozen cost basis. The
generic CSV has no cost_basis column, so the import wizard prompts you to fill it
("Missing inherited per-unit cost basis (WAC)"). Enter the cost per single unit
(e.g. 42.50 for a share bought at โฌ42.50), not the position's total value. The
engine multiplies it by quantity; a total entered here inflates the cost basis by a
factor of quantity. For bonds, quantity is the face value and the per-unit cost is
near 1.0.
๐ท๏ธ Asset Identifier
The asset column accepts:
- Ticker (e.g.
AAPL,VWCE) โ for exchange-listed securities - ISIN (e.g.
US0378331005) โ preferred when available; unambiguous across exchanges - Name / description (e.g.
VIA SILONE,MARINA DI SCARLINO) โ for non-listed assets such as P2P loans, real estate, or anything without a market code
First import and asset matching
CSV import does not create assets or choose a provider automatically. Create a missing asset explicitly (a provider is optional); an existing asset can be selected manually or matched automatically when its saved identifiers give a unique match. An issuance/CUM ISIN can differ from the traded ISIN, and tickers can be ambiguous. Keep the appropriate primary and alternate identifiers on the asset so later imports can recognize it.
Non-listed assets (P2P loans, crowdfunding, real estate)
Use a consistent name string as the identifier (e.g. the project name). During BRIM import review you will be asked to map it โ choose asset type OTHER since these are not exchange-traded instruments.
If the BUY transaction has no obvious identifier in a dedicated column, extract the project name from the description field in your conversion script.
๐ When to Use Each Transaction Type
๐ Multi-leg broker rows
Some broker events are one source row but several LibreFolio transactions. The correct model is to emit multiple TXCreateItems on the same date rather than hiding economics inside one row:
| Broker event | LibreFolio transactions |
|---|---|
| Securities-only cash buy | DEPOSIT for funding + BUY for the security |
| Securities-only sale/redemption | SELL for the security + WITHDRAWAL for cash swept away |
| Bond maturity above par | SELL at par principal + INTEREST for the above-par premium/FOI amount |
| Portfolio snapshot seed | DEPOSIT for cash when present + one cashless ADJUSTMENT per holding |
This mirrors shipped broker plugins such as Intesa Sanpaolo (snapshot seed) and Crรฉdit Agricole (automatic cash counter-entries and bond maturity split).
๐ค P2P lending / crowdfunding patterns
P2P platforms often issue a single report row that bundles capital repayment and interest. You need to split this into two transactions for LibreFolio:
| Platform event | LibreFolio transactions |
|---|---|
| Principal repayment only | SELL (quantity=โfraction, amount=+principal) |
| Interest only | INTEREST (amount=+interest) |
| Principal + interest on same row | Two rows: SELL at exact cost basis + INTEREST for the earnings |
| Tax on interest | TAX (amount=โtax, same date as interest) |
Example: P2P project repayment
Project "VIA SILONE": bought 1 unit at โฌ3,005. Partial repayment of โฌ300.50 capital + โฌ15.00 interest.
date,type,quantity,amount,currency,asset,description
2024-06-01,SELL,-0.100000,300.50,EUR,VIA SILONE,Rimborso parziale capitali
2024-06-01,INTEREST,,15.00,EUR,VIA SILONE,Interessi progetto VIA SILONE
The SELL quantity is โ300.50 / 3005 = โ0.100000 โ the fraction of the 1-unit position being returned.
โฉ๏ธ Storno / reversal of a broker error
When a broker incorrectly credits an amount and then reverses it, you have two options:
Option A โ Clean history (recommended when the error and reversal are close in time)
Delete both the erroneous credit and the reversal from your CSV. If they were on the same day, just net the amounts: record only the true net value as a single transaction.
This keeps your portfolio charts clean with no artificial spikes.
Option B โ Exact ledger (when the two events are weeks or months apart)
Record the reversal as the opposite transaction of the original:
- If the error was a SELL (cash in), the reversal is a WITHDRAWAL (cash out, same amount negative)
- If the error was a DEPOSIT, the reversal is a WITHDRAWAL
Do NOT use ADJUSTMENT for cash reversals
ADJUSTMENT must have an empty amount โ it is strictly for quantity-only corrections (stock splits, share gifts). Using ADJUSTMENT for a cash reversal will leave the cash balance wrong.
๐ธ Fees and taxes
FEE and TAX are cash-only transactions (no quantity, no asset required):
date,type,amount,currency,description
2024-06-01,TAX,-28.31,EUR,Ritenuta d'acconto su interessi
2024-06-01,FEE,-1.50,EUR,Commissione operativa
๐ How It Works: A Deeper Look
1๏ธโฃ Column Detection (_detect_columns)
Maps the CSV's header row to LibreFolio's standard fields using a synonym dictionary:
HEADER_MAPPINGS = {
"date": ["date", "data", "settlement_date", ...],
"type": ["type", "tipo", "operation", ...],
"asset": ["asset", "symbol", "ticker", "isin", ...],
# ...
}
Each header is trimmed and lower-cased before the lookup (csv_col.lower().strip()). Headers that
match no synonym are ignored, and when two headers map to the same field the leftmost wins.
The same map drives detection: can_parse โ through cannot_parse_reason โ accepts a .csv
only when both date and type are mapped, so the wizard offers the plugin only for such files.
If the user forces it on another file, parse_file refuses it with
Plugin 'broker_generic_csv' cannot parse file '<name>': required column 'date' not found in the CSV header
(HTTP 400), and the file moves to failed.
2๏ธโฃ Row Parsing (_parse_row)
- Extract Values via
column_map - Parse Date โ tries multiple
strptimeformats - Parse Type โ looks up lowercase string in
TYPE_MAPPINGS - Parse Numbers โ handles US and European decimal formats
- Handle Assets โ classifies identifier as ticker/ISIN/name; assigns consistent fake asset IDs for batch mapping in BRIM review
Errors. An exception raised for a row โ an empty or unreadable date, an unknown type, a
TRANSFER (refused: it needs a link_uuid pair), a currency code that fails the ISO 4217 check โ
becomes the warning Row N: <message> (the header is row 1) and the row is skipped. A row that
parses but breaks a business rule (signs, missing cash; see validate_transaction_business_rules)
is not created either: _create_transaction records it in validation_issues. An asset-required
type with an empty asset gets the placeholder identifier UNKNOWN_ROW_<n>, to be mapped in the
review. The EUR default applies only when no currency column is mapped: with the column
present, an empty cell on a row with an amount fails the ISO 4217 check, so that row is skipped.
A file that yields no transaction adds the warning No valid transactions found in file.
๐ 3. The "Gold Standard" Example
The Generic CSV Provider is the perfect starting point for a new broker plugin. Copy its structure and:
- Increase
detection_priorityto100 - Add a
can_parse()method to reliably detect your broker's file - Customize
HEADER_MAPPINGSandTYPE_MAPPINGS - Refine parsing for any broker-specific quirks
๐ Complete Example Row by Row
This example shows a P2P portfolio lifecycle on a single platform (adapted from a real Recrowd import):
date,type,quantity,amount,currency,asset,description
2022-11-03,DEPOSIT,,6015.00,EUR,,Bonifico iniziale
2022-11-03,BUY,1,-3005.00,EUR,VIA SILONE,Investimento progetto VIA SILONE
2022-11-05,BUY,1,-2005.00,EUR,MARINA DI SCARLINO,Investimento progetto MARINA DI SCARLINO
2023-08-01,SELL,-0.031102,62.36,EUR,MARINA DI SCARLINO,Rimborso parziale capitali
2023-08-01,INTEREST,,15.20,EUR,MARINA DI SCARLINO,Interessi parziali
2023-08-01,TAX,,-3.95,EUR,,Ritenuta acconto interessi
2023-12-18,SELL,-1.000000,1005.00,EUR,EX ALBERGO VELA,Restituzione capitali completi
2023-12-18,INTEREST,,108.87,EUR,EX ALBERGO VELA,Interessi finali
2023-12-18,TAX,,-28.31,EUR,,Ritenuta 26% su interessi
2024-06-30,WITHDRAWAL,,-360.87,EUR,,Prelievo verso conto personale
Key points demonstrated:
DEPOSIT: positive amount, no asset, no quantityBUY: positive quantity (receive units), negative amount (pay cash)SELL: negative quantity (deliver units), positive amount (receive cash)INTEREST: positive amount, asset optional, no quantityTAX: negative amount, no quantity, no asset requiredWITHDRAWAL: negative amount, no quantity, no asset