Skip to content

๐Ÿ”ง 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 the TransactionType enum.
  • 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 units
  • amount: 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)

  1. Extract Values via column_map
  2. Parse Date โ€” tries multiple strptime formats
  3. Parse Type โ€” looks up lowercase string in TYPE_MAPPINGS
  4. Parse Numbers โ€” handles US and European decimal formats
  5. 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:

  1. Increase detection_priority to 100
  2. Add a can_parse() method to reliably detect your broker's file
  3. Customize HEADER_MAPPINGS and TYPE_MAPPINGS
  4. 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 quantity
  • BUY: positive quantity (receive units), negative amount (pay cash)
  • SELL: negative quantity (deliver units), positive amount (receive cash)
  • INTEREST: positive amount, asset optional, no quantity
  • TAX: negative amount, no quantity, no asset required
  • WITHDRAWAL: negative amount, no quantity, no asset