Story: Populate the ACME books with a realistic trade population — the remaining work
Table of Contents
This page documents a story in Sprint 29, carried unfinished from Sprint 28 at close. It captures the goal, current status, acceptance criteria, and the tasks that compose it.
1. Goal
ACME's books hold a realistic trade population: every asset class the platform can price, in the proportions a dealing institution holds, dated relative to the day the tenant is provisioned, and referencing the parties, books, counterparties and staff the tenant already holds.
The synthetic trade generation machinery produces it. That machinery is scoped by tenant and by party and is driven by a trade generation config, so ACME is the first tenant it serves and Northwind is the next. No task in this story may name a tenant, a party, a book or a counterparty. Those arrive from the config row. The only place that names ACME is the ACME seed data.
The investigation this story commissioned is Investigation: Populating ACME with a trade population. It is the record of what was measured and which mechanism was chosen. It is a snapshot, not a description of the system.
2. Status
| Field | Value |
|---|---|
| State | DONE |
| Parent sprint | Sprint 29 |
| Now | Nothing. |
| Waiting on | Nothing. |
| Next | Nothing. |
| Last touched | 2026-11-08 |
3. Acceptance
The story closes on the tasks it finished:
- A generated date is a real date.
- A security is named by its product.
- Charter a book and a config for the commodity population.
- Construct every bond product by name.
- Draw every bond code and state its facts.
- Expose the population's size and mix in the provisioning UI.
- Factor out the shared planner loop.
- Give the system a legal entity.
- Make the trade population plan family-neutral.
- Name a bond security by its issuer.
- Populate the commodity family.
- Populate the credit family.
- Populate the equity family.
- Populate the FX family.
- Populate the inflation family.
- Populate the interest rates family.
- Populate the scripted family.
- Publish the commodity catalogue.
- Record where a trade came from.
- Trade Population Weights states a trade-count mix: interest ….
- Seed a commodity catalogue.
- Seed an inflation curve the tenant holds.
- The bond population books one product of ten.
- The population never draws the products past its slot count.
4. Tasks
| Task | State | Start | End | Description |
|---|---|---|---|---|
| Make the trade population plan family-neutral | DONE | 2026-10-24 | 2026-10-25 | Give the plan a per-family payload, put one planner per asset class behind one interface, keep one writer, and move the population size into the config. The bond population runs through it. |
| Seed a commodity catalogue | DONE | 2026-10-25 | 2026-10-25 | Give the platform a commodity vocabulary it can validate: an entity for the commodities a population draws from, seeded with the exchange-prefixed indices the engine resolves, each with its unit and quotation currency. |
| Populate the commodity family | DONE | 2026-10-25 | 2026-10-25 | Book the twenty-five commodity trade types the catalogue routes, in the 5% share the weights page sets. Waits on the commodity catalogue. |
| Record where a trade came from | DONE | 2026-10-25 | 2026-10-25 | Every trade states an immutable origin from a lookup and an origin reference, so reports and rollbacks can separate manual, API, ORE import and synthetic trades. |
| Populate the interest rates family | DONE | 2026-10-25 | 2026-10-25 | Book the ten interest rate trade types the catalogue routes to rate_instrument, in the 42% share the weights page sets. |
| Populate the FX family | DONE | 2026-10-25 | 2026-10-26 | Book the sixteen FX trade types the catalogue routes, in the 25% share the weights page sets. |
| Populate the equity family | DONE | 2026-10-26 | 2026-10-28 | Book the nineteen equity trade types the catalogue routes, in the 12% share the weights page sets. |
| Populate the inflation family | DONE | 2026-10-31 | 2026-10-31 | Book the inflation-linked trade types, in the 3% share the weights page sets. The refdata asset class has one catalogue code and it routes to rate_instrument. |
| Populate the scripted family | DONE | 2026-10-31 | 2026-10-31 | Book the four routed scripted trade types, in the 3% share the weights page sets. The refdata catalogue has no scripted asset class, so the mapping must be declared. |
| Extend the generator across the instruments | ABANDONED | Replaced by one task per asset class, because a family cannot land as a single verifiable unit. | ||
| Factor out the shared planner loop | DONE | 2026-10-25 | The bond, commodity and interest rate planners each carry a verbatim copy of the slot loop: the book, counterparty and trader lookups, the identifiers, the trade date and the netting set scan. A fourth family would copy it again. Extract the envelope every family shares, so a planner states only what its family adds. | |
| Publish the commodity catalogue | DONE | 2026-10-28 | 2026-10-28 | The commodity catalogue is seeded and never published: it has no artefact type, no publish operation and no bundle membership, so a tenant that draws a commodity holds none. The equity catalogue had the same three gaps and is now fixed; this is the same shape for the commodity vocabulary. |
| The bond population books one product of ten | DONE | 2026-10-30 | Ten trade types route to the bond instrument table. The planner draws exactly one of them, a plain Bond, so every one of the twenty-four bond trades in a provisioned tenant is a Bond and the other nine codes never appear. The family's own fact rows – the option, the repo, the future, the total return swap, the ASCOT, the callable's call dates, the convertible's conversion targets – are all empty, because the writer fills only the instrument header. A tenant therefore cannot see a bond option, a repo or a convertible, and nothing says so. | |
| Charter a book and a config for the commodity population | DONE | 2026-10-28 | 2026-10-28 | No ACME book trades commodities, so the family cannot be booked and its constructors are never reached by a run. Charter a commodity book for the UK entity and a generate_trades config that reaches every routed code, so the family books and its constructor can be proved. |
| Populate the credit family | DONE | 2026-10-29 | Credit has a routed table, catalogue rows and four seeded books, and nothing that writes it: no credit trade planner and no writer arm. Draw its five products, resolve reference entities from the DQ lei_entity dataset, and prove the family books. | |
| Give the system a legal entity | DONE | 2026-10-30 | A credit trade must reference a legal entity by LEI, and the system has nowhere to put one: the 38,213 LEI rows sit in a DQ artefact under the system tenant, a party session cannot read them, and the publication that does exist turns them into counterparties, which carry a name and no LEI. Model the legal entity where a party can reference it. | |
| The population never draws the products past its slot count | DONE | 2026-10-30 | 2026-10-30 | The rate planner cycles nine routed types and each seeded rate config states eight slots, so slot 0 to 7 selects the first eight types and the ninth is never reached: a provisioned tenant books 24 rate trades over eight types and holds no knock-out swap at all. The fx planner cycles sixteen types against the same eight slots, so its variance swap and its accumulator never appear either. Either the config states a slot per type, or the type is drawn by name rather than by position, so a population of any length states every type it routes. |
| Construct every bond product by name | DONE | 2026-10-30 | 2026-10-30 | Ten codes route to the bond instrument table and only one of them, a plain Bond, has a constructor. The other nine have their own fact tables and nothing that states them, so the family cannot draw them and their tables are empty in every tenant. Give each code a constructor that states its own facts and cannot fill a column its product does not have. |
| Draw every bond code and state its facts | DONE | 2026-10-30 | 2026-10-30 | The bond planner draws one code of the eleven the catalogue routes to the bond instrument table, so a tenant holds only plain bonds and every other bond fact table is empty. Draw all eleven, construct each through its named constructor, persist the facts the plan carries, and prove it with a provisioning run. |
| Seed an inflation curve the tenant holds | DONE | 2026-10-31 | The inflation family cannot book: the catalogue routes one code, InflationSwap, to the rate instrument table, but the trade must name an inflation index and the tenant holds no inflation curve at all. Measured on a fresh ACME tenant: zero inflation curve configs and zero seasonality factors, against 110 inflation swap conventions and 45 zero inflation index conventions. Declare the index the trades name, seed its curve and the fixings the engine reads, so an inflation swap can be priced and a planner has something to point at. | |
| A generated date is a real date | DONE | 2026-10-31 | 2026-10-31 | The population draws dates that do not exist and the wire turns each one into the absent date. Adding months to the 31st of a month keeps day 31, so an anchor of 2026-10-31 draws 2026-09-31 for the slot one month back, and an anchor of today puts two such slots in every family. The reflector writes any not-ok date as the empty string, which reads back as the absent date, so the store holds the sentinel the absent date becomes, 0002-11-30 BC. The fx variance swap refuses it because its two ends are equal, and every other family stored it in silence. |
| A security is named by its product | DONE | 2026-10-31 | 2026-10-31 | Ten bond codes route to the bond instrument table and they share a security name, because the name states the currency, the anchor and the term and leaves the product out. A callable bond states the dates its issuer may call it and a plain bond of the same term states none, so the second product of a term is written against the first one's issue and the store refuses it: Bond issue … is stored with other terms. The population therefore books one product of every term and the run stops in the bond family. |
| Name a bond security by its issuer | DONE | 2026-10-31 | 2026-10-31 | Two bond configs of one tenant name the same security id and mean two issues, because the security's name states the currency, the anchor, the term and the product but not the issuer whose bond it is. The second config's issuer differs, so the store refuses its issue as stored with other terms and the population stops. |
| Let the ACME inflation curve state the type the schema holds | ABANDONED | The ACME curve configuration seeds state ZeroInflation for inflation_type, which is the ORE market data model name, while the curveconfig schema enumerates ZC and YY. The refdata trigger refuses the bundle, so provisioning stops before the population and no tenant is created. | ||
| Trade Population Weights states a trade-count mix: interest … | DONE | 2026-10-31 | 2026-10-31 | Trade Population Weights states a trade-count mix: interest rates 42%, fx 25%, equity 12%, credit 6%, commodity 5%, bonds 4%, inflation and scripted 3% each. The seeded configs were never sized to it. On a fresh tenant the mix is rates 27 of 162 (17%), fx 64 (40%), equity 17 (10%), credit 5 (3%), commodity 25 (15%), bonds 24 (15%); inflation and scripted book nothing at all. Each class books one trade per routed code, which is what coverage needs, and a weighted population needs a different rule: the weights set the counts, and the codes are drawn within those counts. Doing that changes the seeded configs for every class at once and needs the weights page's tolerance stated, so it is its own task. |
| Expose the population's size and mix in the provisioning UI | DONE | 2026-10-31 | Task for: Populate the ACME books with a realistic trade population — the remaining work |
5. Decisions
- One config row per tenant, party and asset class. The config already
carries
asset_class_codefrom the refdata catalogue:interest_rates,fx,equity,credit,commodity,inflationandbond. Coverage is therefore a row per family, and not a branch in the code. - The plan is the seam, and not the writer. Today
trade_population_planandtrade_population_slotare bond-shaped, holdingsecurity_id,issue_id,issuer_id,tenor_years,calendarandreference_curve_id, andplan_populationrefuses every asset class butbond. The plan must carry a payload that belongs to its family, each class must sit behind one planner interface, and one writer must execute any plan. - The population size is an input.
trades_per_bookis a compile-time constant of 8 today. Move it into the config, so a tenant sizes its own population. - The order follows Trade Population Weights: interest rates 42%, FX 25%, equity 12%, credit 6%, commodity 5%, inflation 3% and scripted 3%. Bonds are 4% and are already delivered. Commodity is the exception to the order. It lands inside the seam task, because it is the only class every declared type of which routes, so it is the only one that tests the plan alone and not also the routing work.
- Unrouted trade types are in scope per class. 30 of the 121 catalogue types route nowhere: equity 13, FX 10, interest rates 3, credit 2, bond 1 and scripted 1. The task for a class either routes its holes or names them out of scope.
- Each class states the market data it prices on. A class whose curves or surfaces are absent still books and exports, and its task says which pricing it cannot prove yet.
- A trade that must export states a header, one product fact row and its children. The store rebuilds an instrument from the header and one fact row per product, so a trade with children and no fact row books, reports and exports as its type alone — the engine has nothing to price. The interest rate family found this with an exporter test, and every later family states its fact row.
- A type ORE models as its own instrument and the store holds no fact row for is out of scope, with the reason named. Routing it to a shared table is not enough on its own: RateDigitalOption, SwaptionStraddle and ForwardVolatilityAgreement each have an ORE element and no fact row here, so each needs a table, an array, a writer and an export mapping before it can book.
- The class share is a check for the whole story, not for one task. A class's share of the population is a property of every family at once, so a family task reports the share it measured and does not inflate its own config to reach the weight.
- A generated date is a calendar date, and the day it was drawn from holds. Adding a month to the 31st states the last day of a month that has no 31st rather than spilling into the next one, because a window that ends a day after the terms the product means is a silent change of terms. The year arithmetic does the same for the 29th of February.
- The wire states absent dates one way and refuses everything else. The empty string is the absent date and reads back as the default value; a date that is neither absent nor real is refused where it is written, because a reader has no way to tell an invented date from an absent one, and a run that lost a date quietly is worse than one that stops.
- The seed states what the vocabulary states and invents none of it. An
inflation curve names a
<INDEX>_INFLATIONSWAPconvention the tenant already holds, and states no extrapolation, because thecurve.flagvalue set arrives empty and the guard refuses every value: a curve that states none takes the engine's default, which is a known state, where a guessed word is a refusal. - A class's fixings are the class's own market data, and this seed is not where they come from. The curve is what a trade names; the fixing series and the seasonality factors are what the engine prices from, and the family's task states that it books without them. Recorded as the capture The seeded inflation curve states its index, its conventions and no fixings.
- A family that routes to another family's table is planned by its own planner
and states that family's header. Inflation is the case: the catalogue sends
InflationSwapto the rates table, so the trade is a rates header, and the asset class is still the key the registry answers a planner by, because the population a class asks for is a fact about the class and not about the table it lands in. - A trade names an index the tenant resolves, and the resolution is the curve's
own name. The population draws the ids of the tenant's
InflationCurvesdefinitions rather than a list of its own, so a trade can only name a curve that exists and a tenant that holds none books none. - The product's index is not the leg's index. The leg column references the benchmark catalogue, so an inflation index there is refused; the product's own fact row states it, and the export reads it from the fact.
- A payoff the taxonomy has no class for gets one, in the catalogue, and not a class that stands for something else. The taxonomy is the list a config may name and the store's validator is generated from it, so a family that files itself under another class both lies about the trade and puts two planners on one class.
- A family books the codes its export can carry, and names the rest out of scope. The scripted family books three of its four routed codes because the projection writes no element for the autocallable's data; booking it would produce a trade that reports as its type and exports as nothing.
- A generated row's parameters are the document's own members. The projection writes an unrecognised key as an element the schema does not hold, so the population states the document's names and a round-trip case holds it to them.
- The population's total is not a free choice: it is the smallest number where every class can be its weight and keep one trade per routed code. A class's count cannot fall below its code count, and its share cannot fall below that floor, so the class with the worst floor-to-weight ratio sets the total. At a thousand trades every class states its weight exactly; at a hundred and ninety commodity was twice its weight and rates a third of it.
- The population's size and mix are profile parameters, not a screen's own form. The provisioning form renders every parameter a profile declares, so a knob the profile declares costs no screen code and the arithmetic has one home on the server. A run that states no size keeps the seeded counts; one that states a size and no mix keeps the seeded mix.
- Closed on 2026-11-08 at sprint 29 close with its done tasks. The open tasks and the original acceptance moved to Populate the ACME books with a realistic trade population — the remaining work.
6. Result
ACME's books hold a realistic population, and an operator can size it.
Every class the refdata taxonomy states has a planner, and a fresh tenant holds a thousand trades: interest rates 420, FX 250, equity 120, credit 60, commodity 50, bonds 40, inflation 30 and scripted 30 — the weights page's own mix, exactly, with every routed code appearing between two and sixteen times. The population exports as the ORE portfolio, and each family's round trip is proved in the ORE suite.
Four things the arc settled, and one it exposed:
- A class's count cannot fall below the codes its planner cycles, and its share cannot fall below that floor, so the total is the smallest number where every class fits both. At 190 commodity was twice its weight; at 1000 every class is its weight exactly.
- A payoff the taxonomy cannot classify gets a class in the taxonomy, not a class that stands for something else.
- A family books the codes its export can carry and names the rest out of scope.
- The population's size and mix are profile parameters, so the provisioning form states them and one place computes what they mean.
What it exposed and did not fix here: the seeded inflation curve states no fixings, so an inflation swap books and exports and cannot price. That is the capture The seeded inflation curve states its index, its conventions and no fixings, and it belongs to the market-data surface rather than to this story.
7. Out of scope
- Intraday reports. They belong to the report inputs story.
- Draft reasons, structure holds and structure completion. They belong to the Trade Blotter.
8. History
- Split from Populate the ACME books with a realistic trade population on 2026-10-24 at sprint 28 close. The done tasks of that story are recorded there.