BRiSK Next mock auction collector¶
Account-free development against the public Next demo, with a Rust latest-state collector and the demo's actual WASM book decoder hosted in Node. No browser or Tachibana account is needed to run it. Assets are downloaded separately, pinned by SHA-256 and never committed to this repository.
From the repository root, using Python from .venv:
.venv/bin/python tools/brisk_mock/download_mock.py --cache /tmp/brisk-mock-cache
cargo build --release --manifest-path rust/brisk_quote_ingest/Cargo.toml
rust/brisk_quote_ingest/target/release/brisk_quote_ingest \
--cache /tmp/brisk-mock-cache --latest /tmp/brisk-latest.json
Node 22+ and Rust 1.92+ are required. There are no
npm dependencies. Replay runs at its recorded pace by default. Add --speed 0
for an unpaced benchmark, --codes 7203,6758,8306,9984,6920,5659 for a basket,
or --events /tmp/brisk-events.jsonl for a lossless decoded batch recording.
Missing codes fail explicitly; a 2021 mock cannot cover later listings such as
alphabetic codes. An omitted --codes selects the entire mock master dynamically.
Connect to the public web demo¶
Use --web instead of --cache to fetch the pinned decoder, master, snapshot and
frame assets directly from https://next-demo.brisk.jp/ on each start. No Python
download step or local asset cache is required:
cargo build --release --manifest-path rust/brisk_quote_ingest/Cargo.toml
rust/brisk_quote_ingest/target/release/brisk_quote_ingest \
--web --latest /tmp/brisk-web-latest.json
# Or stream decoded batches directly:
node briskapi/decoder/decoder.cjs --web --codes 7203,8306
This uses the actual public demo's transport: HTTPS assets followed by locally
scheduled historical frames. Its browser code calls wsMock() rather than opening
a market-data WebSocket. There is no live market-data WebSocket to connect to on
this demo. Output remains source=historical_mock, dated 2021-09-27, and explicitly
records input_transport.kind=https_recorded_assets, the website origin and local
asset-fetch duration. That duration is a startup download measurement, not feed
or exchange latency. Cache mode records input_transport.kind=local_cache.
Every downloaded asset must match the existing SHA-256 pin. Requests have a 30-second timeout, redirects are rejected, and each decoded response is limited to 32 MiB. HTTP errors, interrupted downloads or changed assets stop startup; Rust marks the book invalid and never publishes it as running. The complete frame asset is fetched before replay, matching the site's behavior. Web mode does not save vendor assets to disk or silently fall back to stale cached data.
Relation to upstream live streaming¶
Upstream pybrisk's live reader
attaches to an authenticated SBI BRiSK Neo browser, lets that browser maintain
the live connection and vendor WASM state, and extracts decoded events through
CDP. Its endpoints are fixed to sbi.brisk.jp. This is a useful browser-based
live architecture reference; it is not a verified Tachibana BRiSK Next connector.
The reader also polls every 500 ms and extracts QR events, which does not provide
the complete auction state this collector needs.
briskapi's own broker live feed (briskapi.connect(site=...), brisk live --site sbi or another
broker's site) does not use a browser or CDP. briskapi/decoder/brisk.cjs logs in
with your session cookies, downloads the site's decoder, master and snapshot, opens the
WebSocket itself and runs the same Node Decoder as this demo host (protocol version
18000 for the brokers' BRiSK: SBI, e-shiten, Matsui, Monex, SMBC Nikko). It is experimental and has not been
validated against a live broker session.
Its 18000 master record layout, the session schedule and the catch-up can be checked offline, without an account:
This downloads pinned copies of SBI's decoder of March 2026 and, from pybrisk's
capture of sbi.brisk.jp, the master file, the boot's schedule_info and the catch-up
request's issue lists with its reply (only these are taken out of the capture, which
also holds their expired session). It then runs the Decoder on them under Node's
permission model and prints a report: issues, record size, agreement with the master
file, tick types, a limit change read back, and the catch-up with and without the
schedule (price bars, issues advanced, stock views that read back the decoder's frame
numbers, and whether briskapi's catch-up request is the vendor client's), and the
archive's copy of that day's recorded stream replayed behind an opening frame-number
message made in the demo's layout (every message accepted, issues updated, heartbeats,
and ping replies that echo their pings). With the
demo's assets (--demo-cache, default $BRISK_MOCK_CACHE) it also loads the 2021 demo's
snapshot into SBI's decoder under 2021's hours and compares every quote with the demo
decoder's. Like the demo assets, these stay in your cache and out of Git. Needs Node
22.13 or later.
A live Next adapter still needs an authenticated Next session to establish its actual bootstrap, master/snapshot, WebSocket handshake, keepalives and catch-up behavior. The upstream native wire decoder remains experimental. Downloading this demo, or hosting its vendor WASM decoder in Node, does not verify those live transport details. The demo protocol version is 16000; upstream's SBI research describes version 18000, which must not be substituted into this adapter blindly.
For immediate frame batches without Rust/file publication:
The Rust state is also available as the brisk_quote_ingest::State library for a
future signal engine. Feed ingestion is event driven. The optional latest JSON
file is published atomically every 20 ms when dirty (--publish-ms changes this);
this publication interval is independent of decoder ingestion. Use the streamed
batches or in-process state for immediate signals. The pipe applies backpressure
instead of dropping book updates. A slow consumer therefore creates lag, which
must be measured before production use.
Data and timing¶
Each quote preserves issue_id, the complete master code, frame and source
time, plus bid/ask with the quantity and order count at each, indicative price and
matched volume, indicative opening price, market-buy/sell quantities, separate
closing-condition market quantities, special quote flags/time, the reference price,
traded volume and turnover (turnover10, tenths of a yen: price times shares, so
turnover10 / volume / 10 is the VWAP in yen), and the issue status (0-7, the
decoder's; 1 is pre-open, 2 the morning session). bid_levels and ask_levels hold
each side's ten best prices that have orders, best first, as [price10, quantity,
orders]; bid_closing_levels and ask_closing_levels the same for the
closing-condition (引け条件付) limit orders. bid_total_quantity, bid_total_orders,
ask_total_… and bid_closing_total_…, ask_closing_total_… sum each group's limit
orders over the whole board. Prices suffixed price10 are tenths of a yen; a zero price is the vendor's
unavailable sentinel. The indicative matching price excludes closing-condition
orders; closing indicative fields remain separate. reference_price10 is the price
the decoder's indicative matching starts from (the special quote's price, otherwise
the last, otherwise the base price), not a second estimate of the opening price; in
continuous trading it equals the last price. indicative_imbalance_side and
closing_indicative_imbalance_side are 1 when the sell quantity at that indicative
price exceeds the buy quantity (or nothing matches), else 0. Buy/sell and quote enums
are preserved as raw vendor values; no unverified tradability or execution rule is
derived from them. Policy version 5 renamed auction_reference_price10 and
indicative_side to these names, and added the book, turnover, the closing
imbalance side and SBI's issue status. Policy version 6 added the closing-condition books, the board totals and trades. An
issue whose quote the decoder can't read (its state for that issue is inconsistent) is
listed in the batch's skipped_issues instead, until it updates.
Bootstrap, history and quote batches carry trades: every execution the decoder recorded
since the previous batch (history batches: those its snapshot restored), by issue and in the decoder's order, as {issue_id, code, frame,
time_us, price10, quantity, side}. quantity is shares, time_us the execution's time
(the same clock as source_time_us) and side the decoder's raw type: 1 when the trade
was at or above the prevailing ask (buyer-initiated), 2 at or below the bid, 0 for most
opening auction prints. An issue's volume and turnover change by exactly its trades.
source_time_us is microseconds since JST midnight on trading_date, as BRiSK's
server stamps it: absolute in the snapshot, then moved by each update's delta. The
decoder has no clock of its own, and whether the server's stamps are exchange event
times is not established (see ARCHITECTURE.md).
received_unix_ms on stream batches is the local mock replay receipt time with
millisecond precision. decode_ns measures local decode plus quote extraction (with a live host's quote
workers, the host's decode plus the slowest worker's share).
Neither difference establishes live exchange latency.
The initial snapshot is at 2021-09-27 08:59:59.999955 JST, with 4,131 securities and 3,891 nonzero indicative prices. Toyota has price10 101500 (JPY 10,150), matched volume 304,700, market buys 201,300 and market sells 105,700, with no trade yet. The mock container has 18,001 frames labelled 09:00:00.000–09:02:59.990; the final decoded market clock is 09:02:59.999896. Thus it provides one genuine historical pre-open snapshot and the opening transition, not a pre-open time series.
All output is labelled source=historical_mock. replay_running means an
initialized replay is running, not that quotes are live. Completion, sequence
gaps, time/frame regressions, malformed input, child failure and interruption
invalidate that status. Consumers must also check published_unix_ms freshness
to detect a killed or stalled process; a quiet ticker's last update is separate
from stream health. Initial snapshot/frame-number catch-up is checked before
publishing. Restart loads a fresh snapshot; there is no automatic live reconnect.
Latency indication¶
For strategies, consume the decoder's JSON batches directly (or briskapi.Feed)
rather than polling the latest-state file, which is published on a 20 ms timer.
The NautilusTrader v2 actor that used to live in this repository, with its
in-process Rust state, is maintained outside it. The standalone CLI described here
remains useful for recording and latest-state files.
The terminal prints local latency indicators once per second; --status-ms 0
disables this display. The latest-state JSON contains a latency object with
last/p50/p95/p99 values over the most recent 512 frame batches, plus session sample
counts and maxima:
decode: local WASM decode and auction-field extraction.local_receive_to_state: Node mock receipt through decode, JSON serialization, pipe/backpressure, and Rust parsing/state application. Uses same-host wall clocks at millisecond receipt precision; negative readings are excluded and counted as clock anomalies. Clock synchronization/steps still affect readings.replay_schedule_lateness: monotonic scheduling/backpressure delay against the requested replay pace. Unpaced replay (--speed 0) leaves this unavailable.exchange_delay_ms: explicitly null, with a reason. This historical mock does not retain original exchange-to-client receipt times, and the origin of its source timestamp has not been established.
The original quote clock and trading date remain available. A source timestamp of 08:59:59.999955 and a client arrival time of 09:00:00.020000 would indicate 20.045 ms age, not zero delay. For live data, receipt-minus-source becomes an exchange latency estimate only after verifying TSE origin and local/source clock alignment. Otherwise it must be labelled source-clock age. The browser bundle exposes a separate server heartbeat clock; its extrapolation to the client does not independently prove exchange timing. A quiet security's old update time measures quote age, not network latency. The UI publication timestamp can also be used to detect a stalled collector.
Upstream recordings¶
Checked 7 October 2026:
pybriskmain at 43603e4 contains protocol research/mappings but excludes the raw binary capture.gh-pagesat ca4c77d does contain raw recordings: 30,602 binary frame files, master and decoder assets. Its capture summary lists 30,566 entries and creation time2026-03-11 12:17:45. The summary's 60 received nine-bytef0pong payloads, interpreted as little-endian epoch nanoseconds, span 12:12:40.884003–12:17:35.884913 JST. This agrees with lunchtime provenance and does not establish a morning pre-open recording.- No GitHub releases are published. No morning pre-open stream was found in the published branches inspected. The site's 2021 mock is a separate dataset.
Verification¶
Download assets first; fixture integration checks are opt-in to avoid a network dependency in ordinary unit tests. Set the cache environment variable for the complete suite:
BRISK_MOCK_CACHE=/tmp/brisk-mock-cache node --test --experimental-test-coverage tools/brisk_mock/*.test.cjs
BRISK_MOCK_CACHE=/tmp/brisk-mock-cache cargo test --manifest-path rust/brisk_quote_ingest/Cargo.toml
cargo clippy --manifest-path rust/brisk_quote_ingest/Cargo.toml --all-targets -- -D warnings
node tools/brisk_mock/benchmark.cjs /tmp/brisk-mock-cache
.venv/bin/python tools/brisk_mock/verify_browser.py --cache /tmp/brisk-mock-cache
tools/brisk_mock/test_reference.py (same cache variable) replays the demo and
checks that it matches the archive's committed reference fingerprint, which the
service uses to accept only genuine demo replays. Uploaded live broker recordings
have separate structural and continuity checks without a reference replay.
The last check uses installed Playwright/Chromium and compares six auction fields for six securities with the public demo's own JS accessors while its tutorial keeps replay paused. It exposes the market object in an in-memory response; it does not save or redistribute the vendor bundle. Complete replay asserts 731,251 quote updates across all 4,131 securities and verifies Toyota's opening trade.
The legacy demo ABI is not proof of the current live Next protocol. Production requires a current account/session bootstrap, current master (including alphabetic and class-share identity), measured feed continuity/latency, and validation against the current live books. This implementation has no order transport and does not change the paper runner or dashboard.