Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

- Add bounded level-two order-book replay with fresh snapshots, contiguous absolute updates,
multi-level marketable depth, deterministic passive queue position, and locked-book support.
- Publish scenario/journal contract v15 and external strategy protocol v13 while preserving v14
and protocol v12 as frozen compatibility contracts.
- Add causal quote/trade replay with displayed-liquidity capacity, aggressor-qualified passive
fills, maker/taker fee attribution, and economic event timestamps.
- Publish scenario/journal contract v14 and external strategy protocol v12 while preserving v13
Expand Down
28 changes: 15 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,14 @@ scenario slices and scheduled or external intents
fee-component attribution
- Deterministic event IDs, ordered causal references, and order-creation attribution
- Contract-selected compiled execution modules with versioned model-owned configuration and
capability descriptors; v13 adds conservative bar models and v14 adds causal quote/trade replay
while freezing `completed_bar_v1`
capability descriptors; v13 adds conservative bar models, v14 adds causal quote/trade replay,
and v15 adds bounded level-two order-book replay while freezing `completed_bar_v1`
- Tick-aligned fixed-spread and participation-impact execution costs with separate reference,
spread, impact, and final-price audit attribution
- Causally ordered quotes and aggressor-classified trades with displayed-liquidity limits,
maker/taker attribution, and event-time fills
- Bounded order-book snapshots and contiguous updates with price-time queue simulation,
multi-level depth consumption, partial fills, and locked-book support
- Strict batch JSON and bounded-memory JSON Lines scenario parsing with JSON Schemas
- Versioned synchronous JSON Lines strategy processes with per-request timeouts and strict
lifecycle supervision
Expand Down Expand Up @@ -96,23 +98,23 @@ Validate the included scenario with an in-memory replay:

```sh
opam exec -- dune exec trading-engine -- \
--input contracts/v14/fixtures/demo.scenario.json \
--input contracts/v15/fixtures/demo.scenario.json \
--validate-only
```

Run it and create a journal:

```sh
opam exec -- dune exec trading-engine -- \
--input contracts/v14/fixtures/demo.scenario.json \
--input contracts/v15/fixtures/demo.scenario.json \
--journal demo.journal.jsonl
```

For larger histories, validate and replay the equivalent stream one slice at a time:

```sh
opam exec -- dune exec trading-engine -- \
--input contracts/v14/fixtures/demo.scenario.jsonl \
--input contracts/v15/fixtures/demo.scenario.jsonl \
--input-format jsonl \
--journal demo.journal.jsonl
```
Expand All @@ -121,7 +123,7 @@ Run an external strategy against an empty-schedule scenario:

```sh
opam exec -- dune exec trading-engine -- \
--input contracts/strategy/v12/fixtures/external.scenario.json \
--input contracts/strategy/v13/fixtures/external.scenario.json \
--journal external.journal.jsonl \
--strategy-executable ./my-strategy \
--strategy-arg=config.toml \
Expand Down Expand Up @@ -236,19 +238,19 @@ do not provide reducer snapshots or restart recovery.
- [Diagnostic contract](docs/diagnostics.md)
- [Scenario contract](docs/scenario.md)
- [Contract conformance corpus](contracts/conformance/README.md)
- [Current contract v14 and conformance fixtures](contracts/v14/README.md)
- [Current contract v15 and conformance fixtures](contracts/v15/README.md)
- [Frozen contract v2](contracts/v2/README.md)
- [Historical contract v1](contracts/v1/README.md)
- [Scenario JSON Schema](contracts/v14/scenario.schema.json)
- [Scenario stream record JSON Schema](contracts/v14/scenario-stream.schema.json)
- [Journal record JSON Schema](contracts/v14/journal.schema.json)
- [External strategy protocol v12](contracts/strategy/v12/README.md)
- [Scenario JSON Schema](contracts/v15/scenario.schema.json)
- [Scenario stream record JSON Schema](contracts/v15/scenario-stream.schema.json)
- [Journal record JSON Schema](contracts/v15/journal.schema.json)
- [External strategy protocol v13](contracts/strategy/v13/README.md)
- [Historical strategy protocol v3](contracts/strategy/v3/README.md)
- [Historical strategy protocol v2](contracts/strategy/v2/README.md)
- [Historical strategy protocol v1](contracts/strategy/v1/README.md)
- [Persistra compatibility](docs/persistra.md)
- [Strategy message JSON Schema](contracts/strategy/v12/message.schema.json)
- [Strategy transcript JSON Schema](contracts/strategy/v12/transcript.schema.json)
- [Strategy message JSON Schema](contracts/strategy/v13/message.schema.json)
- [Strategy transcript JSON Schema](contracts/strategy/v13/transcript.schema.json)
- [Execution model](docs/execution-model.md)
- [OCaml coverage](docs/coverage.md)
- [Continuous integration and portability matrix](docs/continuous-integration.md)
Expand Down
119 changes: 119 additions & 0 deletions contracts/conformance/cases.json
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,68 @@
"schema_expectation": "accept",
"runtime_expectation": "accept",
"rule": "structural"
},
{
"name": "scenario-v15-valid",
"artifact": "scenario-v15",
"kind": "scenario",
"source": "v15/fixtures/demo.scenario.json",
"mutations": [],
"schema_expectation": "accept",
"runtime_expectation": "accept",
"rule": "structural"
},
{
"name": "scenario-v15-order-book-valid",
"artifact": "scenario-v15",
"kind": "scenario",
"source": "v15/fixtures/order-book.scenario.json",
"mutations": [],
"schema_expectation": "accept",
"runtime_expectation": "accept",
"rule": "structural"
},
{
"name": "scenario-stream-v15-valid",
"artifact": "scenario-stream-v15",
"kind": "scenario_stream",
"source": "v15/fixtures/order-book.scenario.jsonl",
"mutations": [],
"schema_expectation": "accept",
"runtime_expectation": "accept",
"rule": "structural"
},
{
"name": "strategy-ready-valid-v13",
"artifact": "strategy-message-v13",
"kind": "strategy_response",
"source": "strategy/v13/fixtures/external.strategy.jsonl",
"record": 2,
"extract": [
"message"
],
"expected_sequence": "1",
"protocol_version": "13",
"mutations": [],
"schema_expectation": "accept",
"runtime_expectation": "accept",
"rule": "structural"
},
{
"name": "strategy-intents-valid-v13",
"artifact": "strategy-message-v13",
"kind": "strategy_response",
"source": "strategy/v13/fixtures/external.strategy.jsonl",
"record": 4,
"extract": [
"message"
],
"expected_sequence": "2",
"protocol_version": "13",
"mutations": [],
"schema_expectation": "accept",
"runtime_expectation": "accept",
"rule": "structural"
}
],
"schema_only_cases": [
Expand Down Expand Up @@ -1506,6 +1568,63 @@
},
"mutations": [],
"schema_expectation": "accept"
},
{
"name": "strategy-stopped-valid-v13",
"artifact": "strategy-message-v13",
"instance": {
"strategy_protocol_version": "13",
"strategy_sequence": "7",
"message_type": "stopped",
"payload": {}
},
"mutations": [],
"schema_expectation": "accept",
"parser_expectation": "accept",
"parser_expected": "stopped"
},
{
"name": "strategy-error-valid-v13",
"artifact": "strategy-message-v13",
"instance": {
"strategy_protocol_version": "13",
"strategy_sequence": "7",
"message_type": "error",
"payload": {
"message": "fixture failure"
}
},
"mutations": [],
"schema_expectation": "accept"
},
{
"name": "strategy-v13-rejected-response-branch",
"artifact": "strategy-transcript-v13",
"instance": {
"strategy_diagnostic_version": "1",
"transcript_sequence": "2",
"record_type": "rejected_strategy_response",
"expected_strategy_sequence": "1",
"diagnostic": {
"diagnostic_version": "1",
"code": "strategy.protocol",
"phase": "strategy",
"message": "strategy initialization: invalid strategy response JSON",
"context": {
"json_path": "$",
"sequence": "1"
},
"cause": null
},
"evidence": {
"encoding": "hex",
"prefix": "7b",
"observed_bytes": 1,
"truncated": false
}
},
"mutations": [],
"schema_expectation": "accept"
}
]
}
103 changes: 103 additions & 0 deletions contracts/conformance/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,109 @@
"format": "jsonl"
}
]
},
{
"name": "scenario-v15",
"schema": "v15/scenario.schema.json",
"version_field": "contract_version",
"version": "15",
"sources": [
{
"path": "v15/fixtures/demo.scenario.json",
"format": "json"
},
{
"path": "v15/fixtures/fill-clipped.scenario.json",
"format": "json"
},
{
"path": "v15/fixtures/quote-trade.scenario.json",
"format": "json"
},
{
"path": "v15/fixtures/order-book.scenario.json",
"format": "json"
},
{
"path": "strategy/v13/fixtures/external.scenario.json",
"format": "json"
}
]
},
{
"name": "scenario-stream-v15",
"schema": "v15/scenario-stream.schema.json",
"version_field": "contract_version",
"version": "15",
"sources": [
{
"path": "v15/fixtures/demo.scenario.jsonl",
"format": "jsonl"
},
{
"path": "v15/fixtures/quote-trade.scenario.jsonl",
"format": "jsonl"
},
{
"path": "v15/fixtures/order-book.scenario.jsonl",
"format": "jsonl"
},
{
"path": "strategy/v13/fixtures/external.scenario.jsonl",
"format": "jsonl"
}
]
},
{
"name": "journal-v15",
"schema": "v15/journal.schema.json",
"version_field": "contract_version",
"version": "15",
"sources": [
{
"path": "v15/fixtures/demo.journal.jsonl",
"format": "jsonl"
},
{
"path": "v15/fixtures/fill-clipped.journal.jsonl",
"format": "jsonl"
},
{
"path": "v15/fixtures/quote-trade.journal.jsonl",
"format": "jsonl"
},
{
"path": "v15/fixtures/order-book.journal.jsonl",
"format": "jsonl"
}
]
},
{
"name": "strategy-message-v13",
"schema": "strategy/v13/message.schema.json",
"version_field": "strategy_protocol_version",
"version": "13",
"sources": [
{
"path": "strategy/v13/fixtures/external.strategy.jsonl",
"format": "jsonl",
"extract": [
"message"
]
}
]
},
{
"name": "strategy-transcript-v13",
"schema": "strategy/v13/transcript.schema.json",
"version_field": "strategy_protocol_version",
"version": "13",
"sources": [
{
"path": "strategy/v13/fixtures/external.strategy.jsonl",
"format": "jsonl"
}
]
}
]
}
61 changes: 61 additions & 0 deletions contracts/strategy/v13/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# External strategy protocol v13

Version 13 is a synchronous JSON Lines protocol over child-process standard input and output.
Trading Engine sends `initialize`, ordered `event` requests, and `shutdown`. The strategy answers
with `ready`, `intents`, and `stopped`. It may answer any request with `error`.
Protocol v11 remains available for scenario contract v13; earlier versions retain their frozen
shapes.

Every message repeats `strategy_protocol_version: "13"` and a positive canonical
`strategy_sequence`. A response must repeat the sequence of its request. Only one request is
outstanding. Trading Engine rejects unknown or duplicate fields, invalid canonical values,
oversized lines, a wrong version or sequence, unexpected response types, EOF, timeout, and a
nonzero process exit.

The event context contains the replay clock, a marked base-currency portfolio, deterministic group
exposure snapshots, all working orders, and the latest available bar for each instrument. Every
callback emitted for a market slice uses
that slice's `received_at` as `now` and uses its complete bars and FX vector. The portfolio reports
cash, equity, net, long, short, and gross market value plus every attributed cash ledger and
configured position. Position quantities and weights reflect applied fills. Weights are truncated
toward zero to six decimal places. `weights_available` is false and all weights are null when
equity is zero or negative.

The `initialize` request identifies scenario contract v15 and includes the exact `initial_portfolio`
snapshot alongside the legacy cash projection. It also carries the complete versioned venue
calendars, nested execution configuration, financing policy, and settlement policy, so a strategy
can construct DAY orders and reject incompatible execution, financing, or settlement state before
replay.

Matching pauses after each strategy callback. The engine applies the response against the exact
account and OMS state exposed by that callback before delivering another callback or considering
the next eligible order. Later same-slice contexts include the effects of earlier responses. The
eligible-order sequence is fixed at the start of matching, so newly submitted orders wait for a
later slice. Cancelling an order before its turn leaves its unused slice capacity available to the
next eligible order.

Event payloads cover completed market slices with effective-time borrow and cash-rate observations
plus explicit settlement failures, fills, order updates, and rejected intents. Portfolio contexts
include cash-interest attribution and settled and unsettled cash and position quantities. Response
intents use the scenario v15 intent shapes. Market-slice events include lifecycle transitions and
the expanded corporate-action catalog, plus causally ordered quote/trade market events.
Protocol v13 also carries bounded order-book snapshots and incrementals and advertises the
`order_book_v1` configuration, including its maximum depth.

External replay requires an empty batch schedule and empty streamed intent batches. The engine
records accepted messages in both directions in a deterministic transcript. A response rejected
for invalid JSON, fields, version, sequence, EOF, or size is never stored as an accepted exchange.
Instead, the partial transcript ends with a `rejected_strategy_response` diagnostic record. Version
1 rejection diagnostics use the shared
[`diagnostic/v1`](../../diagnostic/v1/README.md) contract. The transcript schema narrows that
contract to the `strategy.protocol` and `resource.limit` codes in the `strategy` phase. The record
includes the structured rejection diagnostic and at most the first 256 raw response bytes encoded
as lowercase hexadecimal. `observed_bytes` counts bytes available when the engine rejected the
response, and `truncated` reports whether the prefix omits observed bytes. The transcript and audit
journal retain partial files after failure and finalize only after their respective success checks.

- `message.schema.json` validates individual requests and responses.
- `transcript.schema.json` validates accepted exchanges and rejected-response diagnostics.
- `fixtures/external.scenario.json` is the batch replay fixture.
- `fixtures/external.scenario.jsonl` is its bounded-memory stream form.
- `fixtures/external.strategy.jsonl` is the canonical protocol transcript.
Loading
Loading