Your mapping spec is the implementation.

Your analysts already keep a spreadsheet that says what every field in your regulatory and surveillance feeds should contain. Today someone else turns it into code. expressionmap runs the spreadsheet itself: point it at your trade data, and it writes the feed with every field checked and every value explained.

Runs on your batch schedule Any table you provide JSON and CSV out
One row in the mapping workbook
Target fieldExpressionValidation
Economics.Amount quantity * (buySell == 'Sell' ? -1 : 1) Amount == 0 ? 'zero quantity' : ''
What the consumer receives"Economics": {
  "Amount": -1000.0,
  "Price": "81.82"
}
Why each field holds that value"Economics": {
  "Amount": "quantity=1000.0, buySell=Sell",
  "Price": "tradePrice=81.82"
}

The problem

The mapping already exists. It just doesn't run.

In most trading firms the business owns a mapping spreadsheet and engineering owns a transformation layer that is supposed to match it. The two drift. Every fix waits for a release, and nobody outside engineering can see what actually runs.

Today

Trade data→Mapping spreadsheet→Transformation code→Feed
  • Every field change is a ticket. A new venue code or a changed rounding rule is a build and a release. The analyst who knows the answer waits for someone else to type it.
  • Nobody outside engineering can read the logic. The person who knows what a field should contain cannot see how it is computed.
  • One bad field fails the record. The error names a stack frame, not the value that was wrong.
  • "Why does this field say that?" is a multi-layer trace. Audit asks; engineering walks back through staging layers that flattened the data on the way.

With expressionmap

Trade data→Mapping workbook→Feed
  • A field change is a workbook edit and a review. There is no generated code and nothing to compile, so nothing to release.
  • The file the business reviews is the file that runs. One expression per field, in a syntax an analyst can read.
  • The failing field is named, in words. The rest of the record still maps. Nothing fails silently.
  • Every field carries its own explanation. The path that was read and the value it held, written beside the feed on every run.

How it works

From your table to a validated feed in four steps. None of them is a release.

Step 1 · engineering, once

Declare the source

Name the table, the row filter and the workbook in one schema file. The source tree and every field type are read from your data, nested as it already is.

Step 2 · generated

Generate the workbook

The first version of the mapping is produced from the schema, not typed. The target tree is written by indentation: nesting in the sheet is nesting in the output.

Step 3 · analysts

Fill in one expression per field

A plain path for the common case, a real expression when needed. Format and validation rules sit beside the value in the same row. Lookups and reference calls are rows too.

Step 4 · the engine, every batch

Validate, then transform

Every expression is checked against the declared types before a single row is read. Then the batch runs and writes the feed, with its evidence beside it.

For the business

The people who know the data own the mapping.

The workbook your analysts review is the workbook the engine runs. A missing lookup value is fixed by adding a row. A changed rule is an edit and a review. Onboarding a new product is measured in analyst days, not sprints.

  • One expression per target field, readable by the person who owns it
  • Validation rules live beside the value they govern
  • Reference data and lookups are sheets, not services to deploy

Expressions from a real workbook

Exchange
getExchange(instrument.exchange) ?: instrument.exchange
Counterparty
counterparty?.legalEntityId ?: counterparty?.partyId
Year code
'' + instrument.lastTradeableDate.substring(0, 4)
Extract date
LocalDate.now()

For operations

Mistakes surface before the data moves, and name the field when they don't.

When the workbook loads, every expression is checked against the declared source types. A typo is refused with a row number before a single row is read. At run time, one bad field does not sink the record: the rest maps, and the failure names the field and the reason in words an analyst can act on.

  • Every expression type-checked at load time
  • Validation runs as the record is produced, not after the fact
  • Every record lands in exactly one place: valid, invalid or error

One run, three files

valid.jsonMapped and passed every rule
invalid.jsonWhich field failed which rule
error.jsonWhich field threw, and why
Refused when the workbook loadsline=7 · The property [trade.tradeId2] is undeclared
Reported per field, per record"Exchange": "should be mapped to XNYM"

For audit and support

Every document carries its own explanation.

Beside every output file, the engine writes a source file in the same shape. For each field it records the path that was read and the value it held at the moment the field was produced. The feed says what was sent. The source file says why, for every field, for every record, on every run. An analyst lines them up side by side.

  • Same tree as the output, field for field
  • Every input named, including lookup and reference results
  • Produced on every run, not reconstructed on request

Today: one question, four hops

  1. Feed value
  2. Final staging layer
  3. Cleaned and joined layer
  4. Raw copy
  5. Source system

With expressionmap: one hop

  1. Feed value
  2. Source path and value, on the same field

For engineering

One processor for every feed. Transformation code stops multiplying.

The engine is a library that follows the workbook. It is the same binary for every feed, every table and every output shape, so the code footprint for a new feed is the workbook: in most cases zero lines of custom code.

A closed, typed expression language

Java-like expressions over ten source types, with safe navigation, elvis and ternaries. No statements, no assignment, no loops. Only a short list of classes and methods can be named; anything else is refused by the validator. Money math is exact by default.

Workbooks are test fixtures

A workbook, a sample record and an expected output run as a unit test on every build. A bad workbook never reaches production: it fails to load, with the row number, before any data flows.

Fits the batch you already run

Four commands: schema, mapping, validate, transform. Source is any table you expose. Reference data arrives over REST. Output is nested JSON or flat CSV from the same workbook, written where your consumer already reads.

0lines of custom transformation code for a typical feed
1file to review: the workbook is the implementation
3outcomes per record, with the field named
100%of fields explained on every run

A pilot feed, run beside your current output.

Pick one feed. We map it from the table you already expose, run it on your batch schedule for one cycle, and compare the two outputs field by field. You keep the workbook either way.

Request a pilot See how it works hello@expressionmap.com