Entity register data model
Sixty-three concrete tables and three abstract bases: fifteen for the entity register and its base, six for the trial balances, four for the parties, twelve for the investor register, eleven for assets, eight for borrowings and six for cash (holdings, operations and positions), one for fees. Every fund structure, however deep, is expressed with two tables only: Entity for the nodes and EntityRelationship for the typed edges. The other tables hold the stable identity of entities, identifiers, configuration and NAVs.
Entity-relationship diagram
on_delete=PROTECT
Identity and versions
An entity has one identity (EntityIdentity, whose id is the uid of its versions) and versions (Entity): name, legal form, LEI… at each date. Every reference to an entity — edges, external codes, rounding policies, NAVs, trial balances — points at the identity, never at a version. Renaming an entity creates a version; nothing is repointed and nothing is lost: the version valid at the requested date provides the attributes. The type of an entity is that of its identity and never changes.
A fact is changed through supersede(). With an effective date (default: now), the former state remains true until that date and stays readable at a past date. With the start date of the version, it is a correction: only the knowledge time changes. end_validity() ends a fact without erasing anything.
Quality status
A received fact (NAV, trial balance) arrives in Bronze. Its status changes through events (NavQualityEvent, BalanceQualityEvent, abstract base core.QualityEventBase), never by changing the fact, which stays immutable. An event targets a version: the status of a version is that of its latest event, Bronze without any. A correction or a restatement creates a version without events, which therefore starts again in Bronze; the former version keeps the quality it had.
Transitions (core.quality.record_quality_event): promotion one step at a time, Bronze → Silver → Gold; downgrade with a mandatory reason; only the current version receives an event. Each event carries its author (decided_by, e.g. Trail), its date and, where relevant, the reference of the control. Events are never changed nor deleted.
Relationship categories
| Category | Types | Traversed by positions and look-through | Quantity carried | Example parent → child |
|---|---|---|---|---|
| OWNERSHIP assets | OWNS | Yes, the only category traversed | ownership_pct, or units_held when the held entity is a SHARE_CLASS | HOLDCO → SPV |
| STRUCTURAL liabilities | COMPARTMENT_OF SHARE_CLASS_OF | No, never | None. A class weight comes from the NAVs. | UMBRELLA → SUB_FUND SUB_FUND → SHARE_CLASS |
| SERVICE service provider | MANAGES · INVESTMENT_MANAGER_OF SUB_INVESTMENT_MANAGER_OF · INVESTMENT_ADVISOR_OF DEPOSITARY_OF · CUSTODIAN_OF · ADMINISTRATOR_OF TRANSFER_AGENT_OF · AUDITOR_OF · DOMICILIARY_AGENT_OF PAYING_AGENT_OF · DISTRIBUTOR_OF · VALUER_OF PROPERTY_MANAGER_OF · LEGAL_ADVISER_OF | No | None | MANCO → UMBRELLA LEGAL_PERSON → SUB_FUND |
| COUNTERPARTY financial counterparty | LENDER_TO · ACCOUNT_BANK_OF · DERIVATIVE_COUNTERPARTY_OF PRIME_BROKER_OF · BROKER_OF | No | None | LEGAL_PERSON → SPV |
| GOVERNANCE | GP_OF · DIRECTOR_OF CONDUCTING_OFFICER_OF · KEY_MANAGEMENT_OF | No | None | GP → UMBRELLA NATURAL_PERSON → MANCO |
| RELATED_PARTY | FEEDS_INTO · BENEFICIAL_OWNER_OF RELATED_PARTY_SAME_GROUP · RELATED_PARTY_SIGNIF_INFLUENCE RELATED_PARTY_KEY_MANAGEMENT · RELATED_PARTY_OTHER | No | None | feeder → master |
Database constraints
| Table | Constraint |
|---|---|
| EntityIdentity | immutable: never changed nor deleted by the application; entity_type set at creation |
| Entity | isin set only on a SHARE_CLASS; currency only on a fund, a HoldCo or an SPV (reference currency) or a share class (denomination currency) — NAV import, commitments and transactions check it when set; internal_code unique among current versions; short_code (short display code, e.g. CLC) only on a SHARE_CLASS; one current version per identity; uid = identity |
| EntityRelationship | parent ≠ child; a quantity if and only if the type is OWNS; units_held > 0; ownership_pct between 0 and 100; (parent, type, child) unique among current versions |
| EntityExternalCode | a code is unique within its source; one code per (entity, source) pair |
| FundNavPolicy | one current policy per fund |
| ShareClassNav | one current row per (class, nav_date, nav_type); units > 0; amounts ≥ 0; rate > 0 |
| RelationshipRule | (parent_type, relationship_type, child_type) unique |
| NavImport | Import log, accepted or rejected: a CSV file (FILE) or the NAVs of an API batch (API, SHARE_CLASS_NAV). sha256 unique among accepted files: the same file is never imported twice, a rejected file may be resubmitted. file_ref = original file at the sender (e.g. AlfaWay), optional |
| NavImportRow | One line received, as received (raw), with its outcome and rejection reason; source_raw = the complete original line at the sender (all its columns, never interpreted): Acta keeps its own record of what it received, independently of the sender |
| NavQualityEvent | PROTECT foreign key to a NAV version; append-only log (application guard) |
Application safeguards
| Rule | Where |
|---|---|
(parent_type, type, child_type) allowed by RelationshipRule | services.py |
| Quantity according to the category and the type of the held entity | validate_quantities |
| No cycle on write (OWNERSHIP and STRUCTURAL traversal) | services.py |
No cycle on read: path array in every CTE | graph.py |
Every change through supersede() (API, admin), never UPDATE; deletion = end of validity | core/models.py |
| The type of an entity does not change from one version to the next | Entity.clean |
| Rounding resolved by currency, overridable per fund | rounding_for |
Trial balances
Balances received already checked by AlfaWay and Trail (debit / credit balance included) and stored as received, in Bronze on arrival; their quality status then changes through BalanceQualityEvent. A balance belongs to any node of the graph: fund, sub-fund, share class, SPV… Account, counterparty, instrument and share class codes on the lines are strings from the source, with no foreign key to the register.
on_delete=PROTECT
Balance constraints
| Table | Constraint |
|---|---|
| ChartOfAccounts | code unique among current versions; an inactive chart accepts no new balance |
| AccountClassification | (chart, code) unique among current versions; parent in the same chart and the same financial statement, never itself (CHECK), no cycle; PCN classes 1 to 7 seeded |
| BalanceSheet | outside PROVISIONAL, one current balance per (entity, date, chart, currency, nature); PROVISIONAL, one per (…, sequence); sequence = 1 outside PROVISIONAL |
| BalanceCategoryMapping | (chart, prefix) unique, prefix not empty; configuration of the INV-05 control, editable in the admin; LU_PCN proposal seeded (22, 51, 19), to be validated |
| BalanceLine | amounts ≥ 0; fx_rate NULL or > 0, never recalculated; instrument code and its type set together; one line per (balance, account, currency, counterparty, instrument, share class) |
Writing and display
| Rule | Where |
|---|---|
Written only by record_balance (all or nothing) and restate_balance | balances/services.py |
Immutability: save() of an existing row, delete() and update() refused, except the closing done by supersede() | balances/models.py |
| Quality status: latest event of the version, computed (never stored on the balance) | core/quality.py |
| Account in the entity currency: equal amounts in both currencies | BalanceLine.clean |
| Latest per (chart, currency, nature): most recent reference date, then highest sequence | selectors.py |
| A PROVISIONAL is replaced, at the same date, by the OFFICIAL, otherwise by the highest sequence; CLOSING and AUDITED replace nothing | selectors.py |
Entity page: latest not replaced, the rest as history; API: ?latest_only=true | views_web.py · views.py |
Parties
A party — investor, counterparty, related party — is an entity of the register: a natural person (NATURAL_PERSON), a legal person (LEGAL_PERSON) or a fund (fund of funds), with no Party table. A role is never a type: INVESTOR is deprecated. A natural person is registered under a pseudonym (investor code); their name, date of birth, address and tax identifier live in PartyPersonalData, isolated and erasable. A tax identifier or an identity document number never goes into the external codes.
Reading personal data requires the parties.pii_read permission (group acta.pii.read) and every read is logged (PersonalDataAccessLog); otherwise the admin masks it, and it always masks it in lists. Erasure deletes every version once the retention period has expired — 5 years after the end of the relationship, configurable — and logs who, when and why, without the content (PersonalDataErasure). The pseudonym, the profile, the codes and the whole business history stay intact. The KYC status of the profile is the one published by TrustLink.
on_delete=PROTECT
| Rule | Where |
|---|---|
Natural person: pseudonymous name (upper case, digits, . _ / -), no legal form, jurisdiction, LEI, RCS or ISIN | Entity.save / clean |
Category by type: INDIVIDUAL for a natural person and only for them; INVESTMENT_FUND for a fund | PartyProfile.clean |
| One current profile per party; KYC status always dated; residence for natural persons only | PartyProfile |
| Personal data for natural persons only; never deleted directly | PartyPersonalData |
Registry number (COMPANY_REGISTRY_NUMBER) for legal persons only; one code per (entity, source, type) | EntityExternalCode |
| Erasure refused while a relationship is open, when no end is known, or before the deadline | erase_personal_data |
Roles: service providers, counterparties, governance
Who plays which role for a fund, a sub-fund, an SPV, a holding company or a ManCo is a typed edge, never a flag on the entity. Direction: provider → served entity, like MANAGES. A role carries neither a percentage nor units and is never traversed by ownership. Allowed combinations come from RelationshipRule: a legal person for every role, a natural person also for governance and investment advice. Each role has its own served entities: a sub-fund has neither registered office nor board (it inherits the domiciliary agent and directors from the umbrella), a property manager serves an SPV or a HoldCo, a share class is never served. A ManCo is never a provider: when it manages the portfolio itself, that is MANAGES; INVESTMENT_MANAGER_OF means delegated management.
counterparties_of(entity, as_of, roles, inherit) returns the roles held towards an entity. A role set on the umbrella applies to its sub-funds (inherited), unless the sub-fund carries the same role type itself: its own then applies (direct). roles_of(party, as_of) returns every role of a party with the served entity. Both are read at a date (validity and knowledge): a depositary change on 1 July shows the old one before and the new one after.
Investor register
The investor register: accounts, commitments, transactions and their reference tables. Account, commitment and transaction each have a stable identity that every reference targets, like entities. OperationType (subscription, redemption, capital call…: the EQUITY domain of the single reference table, next section) and TransactionComponentType (components of a call, a distribution, a shareholder loan, deductions) are configuration, not bitemporal: a new waterfall component is a row, not a migration. A code is never deleted, it is deactivated (is_active). Their labels are data, in French and English; the other interface languages get English.
| Rule | Where |
|---|---|
| A paired operation (switch, transfer) increases or decreases units, never “optional” or “none” | OperationType (CHECK) |
| Only a payment from the investor to the fund reduces the unfunded commitment; only a distribution can be recallable; a deduction has the “deduction” direction | TransactionComponentType (CHECK) |
Liquidity profile (OPEN_ENDED, SEMI_OPEN, CLOSED_ENDED) of a sub-fund or a fund without sub-funds, and financial year end (day and month, both or neither), dated; an umbrella holds a profile for its financial year end only, inherited by the sub-funds that declare none; expected NAV frequency (nav_frequency) and highlighted change threshold (nav_change_alert_pct) of the NAV screen, inherited from the umbrella field by field; missing = not set, never a default | FundProfile |
| Source ranking per domain: rank 1 = the source of truth (TrustLink for the KYC status); an unranked or inactive source comes after all others | SourcePriority · core.sources |
Account: stable identity (InvestorAccountIdentity, target of every FK) and versions; kept by a sub-fund or a fund without sub-funds; the transfer agent and the distributor hold their role towards the fund on the opening date (umbrella inheritance included); number unique per transfer agent | InvestorAccount |
| On a direct account, the final investor is the registered holder or is not set; a nominee or omnibus account is in the name of a legal person; a closed account has a closing date, not before the opening | InvestorAccount (CHECK + clean) |
Commitment: closed-ended or semi-open fund (liquidity profile set, never OPEN_ENDED), open account, class of the account's fund at the date; amount > 0; one agreement reference per account and class | InvestorCommitment |
Immutable commitment: written by record_commitment, changed by amend_commitment (new version, correction or dated change, back to Bronze); account, class, date and closing never change | investors.services |
| Closing a party's accounts sets the end of relationship used for the retention of its personal data | account_relationship_end |
| Eligibility: an open-ended fund accepts LIQUID and BOTH operations, a closed-ended fund ALTERNATIVE and BOTH, a semi-open fund all; the liquidity profile must be set | InvestorTransaction |
| Units signed by the effect of the operation (opposite sign for a reversal), required once executed; NAV, NAV date and pricing basis required for an executed NAV-based operation; commitment required for a call, a distribution, an equalisation, a shareholder loan | InvestorTransaction |
| Pairs: a switch stays on the same account (or two accounts of the same holder) between two classes; a transfer stays on the same class between two accounts; transfer fields on a transfer only; a reversal repeats account, class and operation, once | InvestorTransaction |
| Statuses: PENDING → DEALT → SETTLED, any status → CANCELLED (final); every change is a version that reissues its components and goes back to Bronze | change_status · correct_transaction |
| Components: one per type and version, amount ≥ 0 (direction given by the type), category compatible with the operation, recallable part ≤ amount and dated, only on a recallable type | InvestorTransactionComponent |
Reading. transactions returns the transactions of an account, a class or a fund over a period of trade dates, as known at a knowledge date. cash_flows sums the flows of an account by family and direction, in the class currency (amount × rate), on the effective date: the components, and the principal (family PRINCIPAL) according to the direction declared by the operation type — the gross amount paid by the investor for a subscription, the net amount received for a redemption or a cash dividend. Deductions are already included in it: they are informative lines. A cancelled transaction does not count; a reversal counts negatively.
Unfunded commitment — provisional convention, to be validated against the LPA (it will be configurable per structure): committed amount of the version valid at the date, minus the unfunded-reducing components of the commitment's non-cancelled transactions up to the date (notice date), plus the recallable amounts still recallable at the date. A commitment transferred by a sale is not taken into account as such: a sale is recorded in the commitments — the seller's is amended at the sale date (reduced amount, TRANSFERRED if the sale is full), the buyer gets a new commitment on the same class with the original closing number. transferred_commitment_amount remains the trace received on the transaction; its consistency with the commitments is checked (C4).
Positions. A position is received as is (units, NAV, value, and for a closed-ended fund committed, contributed, unfunded, distributed, recallable), one per account, class, date, basis (trade or settlement date) and source. The register (register) and a party's portfolio (portfolio) keep, when several sources deliver the same position, the one from the best-ranked source (SourcePriority); a register never mixes two dates for a class. The register carries a computed “related party” column (IAS 24) towards the fund and its management company.
| Control | Rule (non-blocking: a finding, never a rejection) |
|---|---|
| C1 | Position units = previous position units + units of the period's executed transactions, on the position's basis |
| C2 | Sum of a class's register units = units outstanding of the official NAV at the date |
| C3 | Value = units × NAV per share; NAV per share = official NAV at its date (not checked when the class currency is not set) |
| C4 | Received unfunded commitment = derived computation; sale: the transferred commitment shows as a decrease for the seller and an increase for the buyer |
| C5 | Fund of funds: units of the investing fund in the register = units of its OWNS edge towards the class |
| C6 | No non-zero position after the account's closing; no movement on a blocked account |
Trail. Every stored commitment, transaction or position publishes an event (DomainEvent) in the same transaction. Trail reads these events at its own pace, in order; Acta never calls it.
Ingestion. Register data arrives in batches (Standard Data File v1, JSON schemas in docs/sdf/v1/): parties, personal data, accounts, commitments, transactions and positions. Each record is processed on its own, in order: a rejection with its reason does not stop the others, and nothing rejected is stored. The same record sent again changes nothing; a different value creates a new version through the fact's write service. References (parties, funds, classes, accounts) are natural keys resolved at ingestion; no party is ever created implicitly.
Demonstration. The seed_investor_demo data set (fictitious data, prefix DEMOREG-) covers an open-ended UCITS fund with two classes, a closed-ended real estate fund (two closings, calls with equalisation, recallable distribution, carried interest, secondary sale), a fund of funds, the management company's group and its related parties, and the service providers (change of depositary during the year). Controls C1 to C6 find no discrepancy on it.
Holdings, operations and positions
What each entity holds (assets), has in cash and owes (borrowings), how it moves and what it is worth at a date. Funds, holdings and SPVs remain entities of the graph; an asset is what is held at the end of the chain (building, infrastructure, land, receivable, target fund unknown to Acta). Decisions: docs/positions_model_mapping.md.
Single reference table of operation types. OperationType lives in the base (core) and serves the four balance-sheet categories: domain = ASSET, CASH, BORROWING or EQUITY (the twelve types of the investor register). direction gives the cash flow seen from the holder: the fund for EQUITY (a subscription is an inflow), the asset holder, the borrower (a drawdown is an inflow), the account holder. MIXED (equalisation, shareholder loan): the direction comes from the components. Register-specific fields (units, NAV, commitment, pairs, principal) stay neutral outside EQUITY, and an investor transaction only takes an EQUITY type.
Equity. The EQUITY domain is the investor register (previous section), aligned without renaming: the prompt's InvestorOperation is InvestorTransaction, and its call and distribution columns (called_*, distributed_*, withholding_tax, fees) are computed from the components by breakdown; a component without a column stays readable in other. Its cash leg is a CashOperation. Full mapping: docs/positions_model_mapping.md, § 7.
Assets. An asset (Asset) has a stable identity and versions, like an entity; its real estate or debt record is a separate bitemporal table, one current version per asset. Who holds it, and how much, is never on the graph: those are its dated positions, per direct holder (SPV, HoldCo or fund). The ASSET entity type is deprecated. An indivisible asset (building, land, infrastructure) is held in quantity 1 and a percentage; a divisible asset (receivable, units, shares) in quantity. Operations, valuations (at 100 %) and positions are received facts, immutable: a status change, a finalised valuation or a correction is a new version with the same valid_from; a restated position goes back to Bronze.
| Rule | Where |
|---|---|
| Outside EQUITY: no NAV, commitment, pair or principal; effect on quantity for ASSET (purchase +, sale −, swap with the received sign) and BORROWING (drawn amount) only; MIXED reserved to EQUITY | OperationType (CHECK) |
| An investor transaction takes a type of the EQUITY domain | InvestorTransaction |
| Asset type: asset class and additional record carried (real estate, debt, none); configuration, a type is deactivated, never deleted | AssetType |
Account bank: ACCOUNT_BANK_OF role (counterparty) of a legal person towards a fund, a sub-fund, an SPV or a HoldCo | RelationshipRule |
| HoldCos and SPVs carry a reference currency, like a fund | Entity (CHECK + clean) |
| Asset: code unique among current versions; active type on creation; real estate or debt record only when the type carries it; fixed rate given, or an index for a floating rate | Asset · AssetRealEstate · AssetDebt |
| A new ASSET entity is refused; no rule leads to an ASSET entity any more | Entity.clean · RelationshipRule |
| Operation: ASSET domain type; holder = SPV, HoldCo or fund existing on the date; asset existing on the date; percentage (indivisible) or quantity (divisible), never both, signed by the type's effect (inverted for a reversal), required once executed; rate 1 in the holder's currency; parties = persons or funds | AssetOperation |
| Valuation at 100 %, external = named valuer; one current per (asset, date, valuer, source); DRAFT → FINAL only once | AssetValuation · finalise_valuation |
| Position: one current per (holder, asset, date, nature, number, source); indivisible = quantity 1 and a percentage; in the asset's currency; in the holder's currency, rate 1 and equal amounts; valuation of the same asset on the date | AssetPosition |
Borrowings. A borrowing (Borrowing) has a borrower (SPV, HoldCo or fund) and exactly one lender: an entity of the group for an intra-group loan, otherwise a party (bank, investor, vendor, lessor). An intra-group loan is recorded once: borrowings_of returns it as a liability of the borrower and a receivable of the lender. A bank, a lessor or a fund financer must hold the LENDER_TO role towards the borrower at signing. Tranches, operations (positive amount, effect on the drawn amount given by the type: drawdown and capitalised interest +, repayments and waiver −) and positions (drawn, undrawn, accrued interest, actual covenants, as received) follow the same principle as assets.
| Rule | Where |
|---|---|
Exactly one lender (INV-03); never the borrower itself; intra-group loan ⇔ lender is an entity of the group (SPV, HoldCo, fund); bank, finance lease, fund financing: LENDER_TO role at signing | Borrowing (CHECK + clean) |
| Code unique among current versions; committed amount > 0; fixed rate given, or an index for a floating rate; maturity after signing; hedge notional and maturity only with an instrument | Borrowing (CHECK) |
| Tranche: code unique per borrowing; operation and position on a tranche of the borrowing, in the currency of the tranche, else of the borrowing | BorrowingTranche · BorrowingOperation · BorrowingPosition |
| Operation: BORROWING domain type, amount > 0; a reversal on the same borrowing, tranche and type, only once | BorrowingOperation |
| Position: one current per (borrowing, tranche, date, nature, number, source); in the borrower's currency, rate 1 and equal amounts | BorrowingPosition |
Cash. An account (CashAccount) belongs to an SPV, a HoldCo or a fund, in a bank holding the ACCOUNT_BANK_OF role towards it; its reference is masked, never a full IBAN. A DSRA or pledged account names the borrowing it secures. A cash operation is a statement line with a signed amount (+ inflow, − outflow, per the direction of its type); its leg is at most one asset, borrowing or investor operation of the holder. A line loaded from a statement stays unmatched until a new version gives it its leg.
| Rule | Where |
|---|---|
Account: unique code; one reference per bank; never a full IBAN (a valid mod-97 key is refused); restricted ⇔ named restriction; linked borrowing only for a DSRA or pledged account, a borrowing of the holder; bank with the ACCOUNT_BANK_OF role at opening | CashAccount (CHECK + clean) |
| Operation: CASH domain type; account open on the value date, in its currency; non-zero amount, signed per the type's direction (inverted for a reversal) | CashOperation |
| Leg: at most one (INV-03); unmatched ⇔ no leg; the asset operation is the holder's, the borrowing has the holder as borrower or lender, the investor transaction is in the register of the holding fund | CashOperation (CHECK + clean) |
| Position: signed balance, one current per (account, date, nature, number, source); in the holder's currency, rate 1 and equal amounts | CashPosition |
Controls INV-01 to INV-06. Non-blocking Python services (holdings/controls.py), read by Trail: they return findings (code, keys, expected, actual, difference, tolerance) and neither refuse nor correct anything. INV-01 roll-forward (quantity or % of an asset, balance of an account, drawn amount of a borrowing, units of the register); INV-02 cash leg of every settled operation that moves money, and list of unmatched lines; INV-03 one lender, one leg (database CHECKs, re-read); INV-04 Σ % of an asset ≤ 100; INV-05 cross-check with the trial balance per category, through the BalanceCategoryMapping table (account prefix → fixed assets, cash, financial debt, intragroup loans apart); INV-06 received rate for every position in a foreign currency, consistent per currency (no rate table). For one object and one date, a single position is read: the best-ranked source, then the most final nature. API: /api/v1/controls/holdings/. Assets, borrowings, cash and operation types are readable through the API (/api/v1/assets/, borrowings/, cash-accounts/, operation-types/…), read only.
API and ingestion. Everything is readable through the API, read only: /api/v1/assets/, asset-operations/, asset-valuations/, asset-positions/, borrowings/, borrowing-tranches/, borrowing-operations/, borrowing-positions/, entities/{uid}/borrowings/, cash-accounts/, cash-operations/, cash-positions/, operation-types/ — masters at as_of / known_at, facts at known_at. Everything comes in through the Standard Data File v1 (POST /api/v1/ingest/): masters identified by their code, facts by (source, source_record_id), written by the services above.
Fees
Work in progress (fees prompt): the fees of a fund, from the reference table of fee types to the amounts received with the NAV. Acta does not compute the NAV: it stores the fees received from the administrator and checks them against the contractual terms. Decisions: docs/fees_model_mapping.md.
Fee types. FeeType is a coded configuration table, like OperationType: adding a fee type is a row. Each type has a family (service provider, performance, tax, other), a basis (% of NAV, fixed amount, % of commitments, % of invested capital) and, for a service provider, the role it holds towards the fund (DEPOSITARY_OF, ADMINISTRATOR_OF…), used to check the provider of a fee term. A tax (subscription tax) has no provider. Thirteen types seeded.
Contractual terms. FeeSchedule (bitemporal) holds the terms of a fee type on a share class or on a fund — umbrella, sub-fund or standalone fund —, exactly one of the two (CHECK), one current schedule per scope and fee type. Annual rate in % for a percentage basis (or tiers), annual fixed amount otherwise; annual minimum and maximum, frequency, day count convention (ACT/365 by default). The provider must hold the role of the fee type towards the fund (umbrella inheritance included) on the validity date; a service provider fee names one, a tax never. Terms applying to a class: those of the class, else of its fund, else of the umbrella (resolve_fee_schedule). Tiers (FeeScheduleTier) belong to one version: contiguous, from 0 to infinity, copied onto every new version; the schedule says how they apply (tier_method: each band at its rate, or the rate of the tier reached on the whole basis). A change creates a version (correction, or change at a date); scope and fee type never change.
Fees received with the NAV. FeeAccrual is an immutable dated fact, as received from the administrator (same mechanism as positions): for a share class — or for a sub-fund or standalone fund when the fee is not broken down by class —, a NAV date and type, a fee type and a source, the accrual of the period (negative for a reversal) and the year-to-date amount (empty when not received, never recomputed), in the currency of the class. valid_from = NAV date; a correction is a new version at the same valid_from, back to Bronze (quality status by FeeAccrualQualityEvent). Several sources coexist (SourcePriority, domain FEE_ACCRUAL). Fees arrive through the Standard Data File (FEE_ACCRUAL type); their actual payment is a FUND_FEE_PAYMENT cash operation. Only the fees of an official NAV will be checked (FEE-01 to FEE-04).
Fee payments. FeePayment (immutable fact, as received from the fee report) records what was paid: fee type, scope (class or fund), payment date, period covered, amount (negative for a refund), provider paid — who must hold the role of the fee type towards the fund on that date. It is linked, once known, to the FUND_FEE_PAYMENT cash operation that settled it, on an account of the fund; one operation may settle several fees, and a line so linked no longer appears among unmatched operations. Accrued versus paid: controls of lot 4.
Controls. Non-blocking, they read only the fees of an official NAV, one source per date (SourcePriority). FEE-01: the accrual of the period equals the annual amount of the applicable schedule (basis × rate, tiers, fixed amount, bounded by the minimum and the maximum) × the year fraction since the previous accrual, per the day count convention; the basis is the official NAV of the class, or the sum of those of the classes of the fund. FEE-02: the year-to-date amount equals the previous one plus the accrual, and restarts from the accrual after the financial year end (the fund's, else its umbrella's). FEE-03: at the date of a trial balance, the sum of the year-to-date amounts received (fees of the fund and of its classes, converted into the fund currency at the ratio of the NAV amounts) equals the charges of the accounts mapped to the fee type (FeeAccountMapping: account prefix → type, the longest wins, configuration without seed). FEE-05: the provider of a schedule still holds its role on the date. FEE-06: the fee payments linked to a FUND_FEE_PAYMENT operation cover its amount. Missing data gives “not available”, never a default.
Computed on demand, never stored. FEE-04, ongoing charges: sum of the accruals of the period (performance fee excluded) over the average NAV of the period — simple average of the NAV dates or weighted by the days each NAV applies, as chosen —, and this ratio annualised; for a class, the fees of the fund are allocated at its weight on each NAV date. Fee report: by scope and type, accrued and paid over the period, accrued, paid and outstanding at the end date.
Enumeration values
EntityType
- UMBRELLA
- STANDALONE_FUND
- SUB_FUND
- SHARE_CLASS
- HOLDCO
- SPV
- GP
- MANCO
- INVESTOR
- NATURAL_PERSON
- LEGAL_PERSON
- ASSET
- OTHER
RelationshipType
- COMPARTMENT_OF
- SHARE_CLASS_OF
- OWNS
- MANAGES
- GP_OF
- FEEDS_INTO
- BENEFICIAL_OWNER_OF
- INVESTMENT_MANAGER_OF
- SUB_INVESTMENT_MANAGER_OF
- INVESTMENT_ADVISOR_OF
- DEPOSITARY_OF
- CUSTODIAN_OF
- ADMINISTRATOR_OF
- TRANSFER_AGENT_OF
- AUDITOR_OF
- DOMICILIARY_AGENT_OF
- PAYING_AGENT_OF
- DISTRIBUTOR_OF
- VALUER_OF
- PROPERTY_MANAGER_OF
- LEGAL_ADVISER_OF
- LENDER_TO
- ACCOUNT_BANK_OF
- DERIVATIVE_COUNTERPARTY_OF
- PRIME_BROKER_OF
- BROKER_OF
- DIRECTOR_OF
- CONDUCTING_OFFICER_OF
- KEY_MANAGEMENT_OF
- RELATED_PARTY_SAME_GROUP
- RELATED_PARTY_SIGNIF_INFLUENCE
- RELATED_PARTY_KEY_MANAGEMENT
- RELATED_PARTY_OTHER
LegalForm
- SICAV
- SICAF
- FCP
- SCSp
- SCS
- SA
- SARL
- RAIF
- OTHER
NavType
- OFFICIAL
- ESTIMATED
- TECHNICAL
FxMethod
- MULTIPLY
- DIVIDE
RoundingMode
- HALF_UP
- HALF_EVEN
- DOWN
- UP
AccountingFramework
- LUX_GAAP
- IT_GAAP
- IFRS
- OTHER
FinancialStatement
- BALANCE_SHEET
- PROFIT_AND_LOSS
- OFF_BALANCE
BalanceNature
- PROVISIONAL
- OFFICIAL
- CLOSING
- AUDITED
InstrumentCodeType
- ISIN
- INTERNAL
- OTHER
ExternalCodeType
- SOURCE_CODE
- TA_INVESTOR_CODE
- COMPANY_REGISTRY_NUMBER
PartyCategory
- INDIVIDUAL
- BANK
- INSURANCE
- PENSION_FUND
- INVESTMENT_FUND
- ASSET_MANAGER
- SOVEREIGN
- PUBLIC_BODY
- FAMILY_OFFICE
- CORPORATE
- NON_PROFIT
- OTHER
KycStatus
- VALIDATED
- PENDING
- EXPIRED
- REJECTED
QualityStatus
- BRONZE
- SILVER
- GOLD
LiquidityProfile
- OPEN_ENDED
- SEMI_OPEN
- CLOSED_ENDED
NavFrequency
- DAILY
- WEEKLY
- MONTHLY
- QUARTERLY
- SEMI_ANNUAL
- ANNUAL
SourceDomain
- PARTY_KYC
- PARTY_PROFILE
- INVESTOR_REGISTER
- ASSET_POSITION
- BORROWING_POSITION
- CASH_POSITION
- FEE_ACCRUAL
OperationDomain
- ASSET
- CASH
- BORROWING
- EQUITY
CashFlowDirection
- INFLOW
- OUTFLOW
- NEUTRAL
- MIXED
FundCategory
- LIQUID
- ALTERNATIVE
- BOTH
UnitsEffect
- INCREASE
- DECREASE
- NONE
- OPTIONAL_INCREASE
- OPTIONAL_DECREASE
- EITHER
Pairing
- NONE
- SWITCH
- TRANSFER
ComponentFamily
- CALL
- DISTRIBUTION
- LOAN
- DEDUCTION
CashDirection
- INVESTOR_TO_FUND
- FUND_TO_INVESTOR
- DEDUCTION
AccountType
- DIRECT
- NOMINEE
- OMNIBUS
InvestorClassification
- RETAIL
- PROFESSIONAL
- ELIGIBLE_COUNTERPARTY
- WELL_INFORMED
AccountStatus
- ACTIVE
- BLOCKED
- CLOSED
CommitmentType
- CASH
- IN_KIND
CommitmentStatus
- ACTIVE
- TRANSFERRED
- RELEASED
- CLOSED
TransactionStatus
- PENDING
- DEALT
- SETTLED
- CANCELLED
PricingBasis
- FORWARD
- HISTORIC
TransferType
- SECONDARY_SALE
- SUCCESSION
- DONATION
- INTRA_GROUP
- OTHER
PositionBasis
- TRADE_DATE
- SETTLEMENT_DATE
AssetClass
- REAL_ESTATE
- INFRASTRUCTURE
- PRIVATE_EQUITY
- LAND
- DIRECT_LENDING
- MEZZANINE_DEBT
- DISTRESSED_DEBT
- TARGET_FUND
- OTHER
AssetExtension
- REAL_ESTATE
- DEBT
- NONE
RiskProfile
- CORE
- CORE_PLUS
- VALUE_ADD
- OPPORTUNISTIC
- DEVELOPMENT
AssetStatus
- ACTIVE
- DISPOSED
- IN_LIQUIDATION
PropertyType
- OFFICE
- RETAIL
- HOTEL
- LOGISTICS
- RESIDENTIAL
- MIXED
- OTHER
ValuationMethod
- DCF
- COMPARABLE
- INCOME_CAPITALISATION
- COST
- RESIDUAL
ValuationStatus
- DRAFT
- FINAL
InterestRateType
- FIXED
- FLOATING
Seniority
- SENIOR
- UNITRANCHE
- MEZZANINE
- JUNIOR
- SUBORDINATED
BorrowingCategory
- BANK_LOAN
- MEZZANINE_LOAN
- INTRAGROUP_LOAN
- INVESTOR_LOAN
- FUND_FINANCING
- VENDOR_LOAN
- FINANCE_LEASE
FacilityType
- TERM
- REVOLVING
- BRIDGE
- SUBSCRIPTION_LINE
- NAV_FACILITY
- OTHER
AmortisationProfile
- BULLET
- AMORTISING
- BALLOON
- OTHER
SecurityType
- MORTGAGE
- SHARE_PLEDGE
- ACCOUNT_PLEDGE
- RECEIVABLES_PLEDGE
- UNCALLED_COMMITMENTS
- GUARANTEE
- UNSECURED
- OTHER
RecourseType
- FULL_RECOURSE
- LIMITED_RECOURSE
- NON_RECOURSE
HedgeInstrument
- NONE
- INTEREST_RATE_SWAP
- CAP
- COLLAR
- OTHER
TrancheType
- ACQUISITION
- CAPEX
- OTHER
CashType
- CURRENT_ACCOUNT
- TERM_DEPOSIT
- MONEY_MARKET_FUND
- OTHER_EQUIVALENT
RestrictionType
- NONE
- DSRA
- ESCROW
- PLEDGED
- TENANT_DEPOSIT
MatchStatus
- UNMATCHED
- MATCHED
- PARTIAL
HoldingCategory
- FIXED_ASSETS
- CASH
- FINANCIAL_DEBT
- INTRAGROUP_LOANS
- EXCLUDED
FeeFamily
- PROVIDER
- PERFORMANCE
- TAX
- OTHER
CalculationBasis
- NAV_PCT
- FIXED_AMOUNT
- COMMITMENT_PCT
- INVESTED_CAPITAL_PCT
FeeFrequency
- DAILY
- MONTHLY
- QUARTERLY
- ANNUAL
DayCountConvention
- ACT_365
- ACT_360
- ACT_ACT
- 30_360
TierMethod
- MARGINAL
- WHOLE
NavAverage
- SIMPLE
- TIME_WEIGHTED
Bitemporal intervals are half-open [from, to); a NULL _to bound is open. Foreign keys to an entity point at its identity (EntityIdentity), never at a version. Source: entities/models.py, balances/models.py, parties/models.py, core/models.py, assets/models.py, borrowings/models.py, cash/models.py, fees/models.py.