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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

- Publish scenario/journal contract v16 and strategy protocol v14 with typed, dimensioned strategy
metrics while retaining string-only metric compatibility through v15 and protocol v13.

- 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
Expand Down
24 changes: 13 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ scenario slices and scheduled or external intents
- Current-equity weight sizing at synchronized closing marks with lot rounding
- Persistent target reconciliation through bounded market-order attempts
- Direct market and limit orders, cancellations, and metrics
- Typed strategy metrics with exact numeric, string, and boolean values, bounded dimensions,
units, and aggregation metadata
- Signed long/short position, order, lot, tick, gross-exposure, leverage, and margin risk
- Deterministic liquidation-first matching, then sell-before-buy and FIFO priority
- Shared per-instrument volume participation, partial fills, and GTC limits
Expand Down Expand Up @@ -98,23 +100,23 @@ Validate the included scenario with an in-memory replay:

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

Run it and create a journal:

```sh
opam exec -- dune exec trading-engine -- \
--input contracts/v15/fixtures/demo.scenario.json \
--input contracts/v16/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/v15/fixtures/demo.scenario.jsonl \
--input contracts/v16/fixtures/demo.scenario.jsonl \
--input-format jsonl \
--journal demo.journal.jsonl
```
Expand All @@ -123,7 +125,7 @@ Run an external strategy against an empty-schedule scenario:

```sh
opam exec -- dune exec trading-engine -- \
--input contracts/strategy/v13/fixtures/external.scenario.json \
--input contracts/strategy/v14/fixtures/external.scenario.json \
--journal external.journal.jsonl \
--strategy-executable ./my-strategy \
--strategy-arg=config.toml \
Expand Down Expand Up @@ -238,19 +240,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 v15 and conformance fixtures](contracts/v15/README.md)
- [Current contract v16 and conformance fixtures](contracts/v16/README.md)
- [Frozen contract v2](contracts/v2/README.md)
- [Historical contract v1](contracts/v1/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)
- [Scenario JSON Schema](contracts/v16/scenario.schema.json)
- [Scenario stream record JSON Schema](contracts/v16/scenario-stream.schema.json)
- [Journal record JSON Schema](contracts/v16/journal.schema.json)
- [External strategy protocol v14](contracts/strategy/v14/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/v13/message.schema.json)
- [Strategy transcript JSON Schema](contracts/strategy/v13/transcript.schema.json)
- [Strategy message JSON Schema](contracts/strategy/v14/message.schema.json)
- [Strategy transcript JSON Schema](contracts/strategy/v14/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 @@ -983,6 +983,68 @@
"schema_expectation": "accept",
"runtime_expectation": "accept",
"rule": "structural"
},
{
"name": "scenario-v16-valid",
"artifact": "scenario-v16",
"kind": "scenario",
"source": "v16/fixtures/demo.scenario.json",
"mutations": [],
"schema_expectation": "accept",
"runtime_expectation": "accept",
"rule": "structural"
},
{
"name": "scenario-v16-order-book-valid",
"artifact": "scenario-v16",
"kind": "scenario",
"source": "v16/fixtures/order-book.scenario.json",
"mutations": [],
"schema_expectation": "accept",
"runtime_expectation": "accept",
"rule": "structural"
},
{
"name": "scenario-stream-v16-valid",
"artifact": "scenario-stream-v16",
"kind": "scenario_stream",
"source": "v16/fixtures/order-book.scenario.jsonl",
"mutations": [],
"schema_expectation": "accept",
"runtime_expectation": "accept",
"rule": "structural"
},
{
"name": "strategy-ready-valid-v14",
"artifact": "strategy-message-v14",
"kind": "strategy_response",
"source": "strategy/v14/fixtures/external.strategy.jsonl",
"record": 2,
"extract": [
"message"
],
"expected_sequence": "1",
"protocol_version": "14",
"mutations": [],
"schema_expectation": "accept",
"runtime_expectation": "accept",
"rule": "structural"
},
{
"name": "strategy-intents-valid-v14",
"artifact": "strategy-message-v14",
"kind": "strategy_response",
"source": "strategy/v14/fixtures/external.strategy.jsonl",
"record": 4,
"extract": [
"message"
],
"expected_sequence": "2",
"protocol_version": "14",
"mutations": [],
"schema_expectation": "accept",
"runtime_expectation": "accept",
"rule": "structural"
}
],
"schema_only_cases": [
Expand Down Expand Up @@ -1625,6 +1687,63 @@
},
"mutations": [],
"schema_expectation": "accept"
},
{
"name": "strategy-stopped-valid-v14",
"artifact": "strategy-message-v14",
"instance": {
"strategy_protocol_version": "14",
"strategy_sequence": "7",
"message_type": "stopped",
"payload": {}
},
"mutations": [],
"schema_expectation": "accept",
"parser_expectation": "accept",
"parser_expected": "stopped"
},
{
"name": "strategy-error-valid-v14",
"artifact": "strategy-message-v14",
"instance": {
"strategy_protocol_version": "14",
"strategy_sequence": "7",
"message_type": "error",
"payload": {
"message": "fixture failure"
}
},
"mutations": [],
"schema_expectation": "accept"
},
{
"name": "strategy-v14-rejected-response-branch",
"artifact": "strategy-transcript-v14",
"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 @@ -1139,6 +1139,109 @@
"format": "jsonl"
}
]
},
{
"name": "scenario-v16",
"schema": "v16/scenario.schema.json",
"version_field": "contract_version",
"version": "16",
"sources": [
{
"path": "v16/fixtures/demo.scenario.json",
"format": "json"
},
{
"path": "v16/fixtures/fill-clipped.scenario.json",
"format": "json"
},
{
"path": "v16/fixtures/quote-trade.scenario.json",
"format": "json"
},
{
"path": "v16/fixtures/order-book.scenario.json",
"format": "json"
},
{
"path": "strategy/v14/fixtures/external.scenario.json",
"format": "json"
}
]
},
{
"name": "scenario-stream-v16",
"schema": "v16/scenario-stream.schema.json",
"version_field": "contract_version",
"version": "16",
"sources": [
{
"path": "v16/fixtures/demo.scenario.jsonl",
"format": "jsonl"
},
{
"path": "v16/fixtures/quote-trade.scenario.jsonl",
"format": "jsonl"
},
{
"path": "v16/fixtures/order-book.scenario.jsonl",
"format": "jsonl"
},
{
"path": "strategy/v14/fixtures/external.scenario.jsonl",
"format": "jsonl"
}
]
},
{
"name": "journal-v16",
"schema": "v16/journal.schema.json",
"version_field": "contract_version",
"version": "16",
"sources": [
{
"path": "v16/fixtures/demo.journal.jsonl",
"format": "jsonl"
},
{
"path": "v16/fixtures/fill-clipped.journal.jsonl",
"format": "jsonl"
},
{
"path": "v16/fixtures/quote-trade.journal.jsonl",
"format": "jsonl"
},
{
"path": "v16/fixtures/order-book.journal.jsonl",
"format": "jsonl"
}
]
},
{
"name": "strategy-message-v14",
"schema": "strategy/v14/message.schema.json",
"version_field": "strategy_protocol_version",
"version": "14",
"sources": [
{
"path": "strategy/v14/fixtures/external.strategy.jsonl",
"format": "jsonl",
"extract": [
"message"
]
}
]
},
{
"name": "strategy-transcript-v14",
"schema": "strategy/v14/transcript.schema.json",
"version_field": "strategy_protocol_version",
"version": "14",
"sources": [
{
"path": "strategy/v14/fixtures/external.strategy.jsonl",
"format": "jsonl"
}
]
}
]
}
64 changes: 64 additions & 0 deletions contracts/strategy/v14/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# External strategy protocol v14

Version 14 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 v13 remains available for scenario contract v15; earlier versions retain their frozen
shapes.

Every message repeats `strategy_protocol_version: "14"` 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.

Intent batches use the scenario v16 typed metric contract. `emit_metric.value` declares a numeric,
string, or boolean value, with optional unit, aggregation, and bounded dimensions.

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 v16 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 v16 intent shapes. Market-slice events include lifecycle transitions and
the expanded corporate-action catalog, plus causally ordered quote/trade market events.
Protocol v14 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