tickvault-ob 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. tickvault_ob-0.1.0/.github/workflows/ci.yml +68 -0
  2. tickvault_ob-0.1.0/.github/workflows/release.yml +100 -0
  3. tickvault_ob-0.1.0/.gitignore +10 -0
  4. tickvault_ob-0.1.0/CONTRIBUTING.md +102 -0
  5. tickvault_ob-0.1.0/Cargo.lock +2940 -0
  6. tickvault_ob-0.1.0/Cargo.toml +63 -0
  7. tickvault_ob-0.1.0/LICENSE-APACHE +202 -0
  8. tickvault_ob-0.1.0/LICENSE-MIT +21 -0
  9. tickvault_ob-0.1.0/PKG-INFO +148 -0
  10. tickvault_ob-0.1.0/README.md +526 -0
  11. tickvault_ob-0.1.0/bindings/Cargo.toml +21 -0
  12. tickvault_ob-0.1.0/bindings/LICENSE-APACHE +202 -0
  13. tickvault_ob-0.1.0/bindings/LICENSE-MIT +21 -0
  14. tickvault_ob-0.1.0/bindings/README.md +121 -0
  15. tickvault_ob-0.1.0/bindings/src/lib.rs +845 -0
  16. tickvault_ob-0.1.0/bindings/tests/conftest.py +82 -0
  17. tickvault_ob-0.1.0/bindings/tests/test_archive.py +66 -0
  18. tickvault_ob-0.1.0/bindings/tests/test_arrow.py +70 -0
  19. tickvault_ob-0.1.0/bindings/tests/test_gate_ten_lines.py +68 -0
  20. tickvault_ob-0.1.0/bindings/tests/test_iteration.py +121 -0
  21. tickvault_ob-0.1.0/bindings/tests/test_plot.py +86 -0
  22. tickvault_ob-0.1.0/bindings/tests/test_semantics.py +106 -0
  23. tickvault_ob-0.1.0/bindings/tests/test_typing.py +80 -0
  24. tickvault_ob-0.1.0/docs/.nojekyll +0 -0
  25. tickvault_ob-0.1.0/docs/app.js +366 -0
  26. tickvault_ob-0.1.0/docs/data/binance-us/_manifest.jsonl +1 -0
  27. tickvault_ob-0.1.0/docs/data/binance-us/venue=binance-us/symbol=BTC-USDT/date=2026-08-25/part-1787637355193065875-0000.parquet +0 -0
  28. tickvault_ob-0.1.0/docs/data/bitstamp/_manifest.jsonl +1 -0
  29. tickvault_ob-0.1.0/docs/data/bitstamp/venue=bitstamp/symbol=BTC-USD/date=2026-08-25/part-1787637358288785208-0000.parquet +0 -0
  30. tickvault_ob-0.1.0/docs/data/bybit/_manifest.jsonl +1 -0
  31. tickvault_ob-0.1.0/docs/data/bybit/venue=bybit/symbol=BTC-USDT/date=2026-08-25/part-1787637354762284125-0000.parquet +0 -0
  32. tickvault_ob-0.1.0/docs/data/coinbase/_manifest.jsonl +1 -0
  33. tickvault_ob-0.1.0/docs/data/coinbase/venue=coinbase/symbol=BTC-USD/date=2026-08-25/part-1787637356715735750-0000.parquet +0 -0
  34. tickvault_ob-0.1.0/docs/data/coverage.json +277 -0
  35. tickvault_ob-0.1.0/docs/data/index.json +94 -0
  36. tickvault_ob-0.1.0/docs/data/kraken/_manifest.jsonl +1 -0
  37. tickvault_ob-0.1.0/docs/data/kraken/venue=kraken/symbol=BTC-USD/date=2026-08-25/part-1787637356351189292-0000.parquet +0 -0
  38. tickvault_ob-0.1.0/docs/data/okx/_manifest.jsonl +1 -0
  39. tickvault_ob-0.1.0/docs/data/okx/venue=okx/symbol=BTC-USDT/date=2026-08-25/part-1787637354945811709-0000.parquet +0 -0
  40. tickvault_ob-0.1.0/docs/index.html +206 -0
  41. tickvault_ob-0.1.0/docs/pkg/tickvault_viewer.d.ts +108 -0
  42. tickvault_ob-0.1.0/docs/pkg/tickvault_viewer.js +429 -0
  43. tickvault_ob-0.1.0/docs/pkg/tickvault_viewer_bg.wasm +0 -0
  44. tickvault_ob-0.1.0/docs/pkg/tickvault_viewer_bg.wasm.d.ts +21 -0
  45. tickvault_ob-0.1.0/docs/python.md +110 -0
  46. tickvault_ob-0.1.0/docs/querying.md +97 -0
  47. tickvault_ob-0.1.0/docs/reconstruction.md +102 -0
  48. tickvault_ob-0.1.0/docs/schema.md +175 -0
  49. tickvault_ob-0.1.0/docs/style.css +153 -0
  50. tickvault_ob-0.1.0/docs/venues.md +380 -0
  51. tickvault_ob-0.1.0/examples/capture.rs +34 -0
  52. tickvault_ob-0.1.0/pyproject.toml +42 -0
  53. tickvault_ob-0.1.0/python/tickvault/__init__.py +286 -0
  54. tickvault_ob-0.1.0/python/tickvault/__init__.pyi +124 -0
  55. tickvault_ob-0.1.0/python/tickvault/py.typed +0 -0
  56. tickvault_ob-0.1.0/scripts/build-viewer.sh +32 -0
  57. tickvault_ob-0.1.0/scripts/make-demo-data.py +127 -0
  58. tickvault_ob-0.1.0/scripts/refresh-demo-data.sh +52 -0
  59. tickvault_ob-0.1.0/src/bin/tickvault.rs +1580 -0
  60. tickvault_ob-0.1.0/src/book/checksum.rs +278 -0
  61. tickvault_ob-0.1.0/src/book/l3.rs +1014 -0
  62. tickvault_ob-0.1.0/src/book/mod.rs +594 -0
  63. tickvault_ob-0.1.0/src/book/replay.rs +244 -0
  64. tickvault_ob-0.1.0/src/clock.rs +445 -0
  65. tickvault_ob-0.1.0/src/config.rs +372 -0
  66. tickvault_ob-0.1.0/src/error.rs +118 -0
  67. tickvault_ob-0.1.0/src/fixed.rs +532 -0
  68. tickvault_ob-0.1.0/src/gap.rs +1109 -0
  69. tickvault_ob-0.1.0/src/latency.rs +381 -0
  70. tickvault_ob-0.1.0/src/lib.rs +60 -0
  71. tickvault_ob-0.1.0/src/limits.rs +402 -0
  72. tickvault_ob-0.1.0/src/pipeline.rs +822 -0
  73. tickvault_ob-0.1.0/src/query/aggregate.rs +554 -0
  74. tickvault_ob-0.1.0/src/query/mod.rs +300 -0
  75. tickvault_ob-0.1.0/src/query/replay.rs +187 -0
  76. tickvault_ob-0.1.0/src/reconstruct/checkpoint.rs +501 -0
  77. tickvault_ob-0.1.0/src/reconstruct/mod.rs +725 -0
  78. tickvault_ob-0.1.0/src/recorder.rs +303 -0
  79. tickvault_ob-0.1.0/src/sequence.rs +1000 -0
  80. tickvault_ob-0.1.0/src/session.rs +1580 -0
  81. tickvault_ob-0.1.0/src/status.rs +240 -0
  82. tickvault_ob-0.1.0/src/store/compact.rs +475 -0
  83. tickvault_ob-0.1.0/src/store/manifest.rs +480 -0
  84. tickvault_ob-0.1.0/src/store/mod.rs +18 -0
  85. tickvault_ob-0.1.0/src/store/reader.rs +386 -0
  86. tickvault_ob-0.1.0/src/store/recovery.rs +581 -0
  87. tickvault_ob-0.1.0/src/store/retention.rs +390 -0
  88. tickvault_ob-0.1.0/src/store/rows.rs +464 -0
  89. tickvault_ob-0.1.0/src/store/schema.rs +700 -0
  90. tickvault_ob-0.1.0/src/store/writer.rs +583 -0
  91. tickvault_ob-0.1.0/src/supervise.rs +446 -0
  92. tickvault_ob-0.1.0/src/symbols.rs +467 -0
  93. tickvault_ob-0.1.0/src/transport/http.rs +81 -0
  94. tickvault_ob-0.1.0/src/transport/mod.rs +14 -0
  95. tickvault_ob-0.1.0/src/transport/replay.rs +121 -0
  96. tickvault_ob-0.1.0/src/transport/ws.rs +71 -0
  97. tickvault_ob-0.1.0/src/types.rs +186 -0
  98. tickvault_ob-0.1.0/src/venue/binance_us.rs +326 -0
  99. tickvault_ob-0.1.0/src/venue/bitstamp.rs +674 -0
  100. tickvault_ob-0.1.0/src/venue/bybit.rs +373 -0
  101. tickvault_ob-0.1.0/src/venue/coinbase.rs +442 -0
  102. tickvault_ob-0.1.0/src/venue/kraken.rs +539 -0
  103. tickvault_ob-0.1.0/src/venue/mod.rs +552 -0
  104. tickvault_ob-0.1.0/src/venue/okx.rs +390 -0
  105. tickvault_ob-0.1.0/src/venue/registry.rs +239 -0
  106. tickvault_ob-0.1.0/tests/common/mod.rs +848 -0
  107. tickvault_ob-0.1.0/tests/conformance.rs +487 -0
  108. tickvault_ob-0.1.0/tests/fixtures/README.md +50 -0
  109. tickvault_ob-0.1.0/tests/fixtures/binance_us_depth.jsonl +25 -0
  110. tickvault_ob-0.1.0/tests/fixtures/binance_us_snapshot.json +1 -0
  111. tickvault_ob-0.1.0/tests/fixtures/bitstamp_diff.jsonl +12 -0
  112. tickvault_ob-0.1.0/tests/fixtures/bitstamp_live_orders.jsonl +501 -0
  113. tickvault_ob-0.1.0/tests/fixtures/bitstamp_snapshot.json +1 -0
  114. tickvault_ob-0.1.0/tests/fixtures/bitstamp_snapshot_l3.json +1 -0
  115. tickvault_ob-0.1.0/tests/fixtures/bybit_orderbook.jsonl +10 -0
  116. tickvault_ob-0.1.0/tests/fixtures/coinbase_l2.jsonl +12 -0
  117. tickvault_ob-0.1.0/tests/fixtures/kraken_book.jsonl +8 -0
  118. tickvault_ob-0.1.0/tests/fixtures/okx_books.jsonl +8 -0
  119. tickvault_ob-0.1.0/tests/gate_crash_recovery.rs +319 -0
  120. tickvault_ob-0.1.0/tests/gate_gap_detection.rs +587 -0
  121. tickvault_ob-0.1.0/tests/gate_idle_feed.rs +160 -0
  122. tickvault_ob-0.1.0/tests/gate_l3.rs +588 -0
  123. tickvault_ob-0.1.0/tests/gate_query.rs +318 -0
  124. tickvault_ob-0.1.0/tests/gate_reconstruct.rs +269 -0
  125. tickvault_ob-0.1.0/tickvault.example.toml +69 -0
@@ -0,0 +1,68 @@
1
+ name: ci
2
+
3
+ on: [push, pull_request]
4
+
5
+ env:
6
+ CARGO_TERM_COLOR: always
7
+
8
+ jobs:
9
+ # Formatting, lints and the whole suite. Clippy is -D warnings because a
10
+ # warning nobody fails on is a warning nobody reads.
11
+ test:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - run: rustup component add rustfmt clippy
16
+ - run: cargo fmt --check
17
+ - run: cargo clippy --all-targets -- -D warnings
18
+ - run: cargo test --release
19
+
20
+ # The phase 3 acceptance gate, and the reason the archive can claim anything
21
+ # about crashes: SIGKILL the writer at randomised offsets during sustained
22
+ # write, restart, and assert every file reads back and the truncation point is
23
+ # recorded. It spawns and kills real processes, so it lives behind --ignored
24
+ # and runs here rather than on every developer's `cargo test`.
25
+ crash-gate:
26
+ runs-on: ubuntu-latest
27
+ timeout-minutes: 20
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+ - run: cargo test --release --test gate_crash_recovery -- --ignored --nocapture
31
+
32
+ # Two claims. The read half of the crate compiles without the capture half,
33
+ # which is what makes the viewer possible; and the viewer rebuilds the same
34
+ # book the library does, which is what makes the viewer honest.
35
+ wasm:
36
+ runs-on: ubuntu-latest
37
+ steps:
38
+ - uses: actions/checkout@v4
39
+ - run: rustup target add wasm32-unknown-unknown
40
+ # The feature split: no tokio, no TLS stack, no C compression codec.
41
+ - run: cargo check --lib --no-default-features --target wasm32-unknown-unknown
42
+ - name: viewer compiles to wasm
43
+ working-directory: viewer
44
+ run: cargo build --release --target wasm32-unknown-unknown
45
+ - name: viewer agrees with the library
46
+ working-directory: viewer
47
+ run: cargo test --release
48
+
49
+ # The bindings, against a wheel rather than a source tree, so the tests
50
+ # exercise what someone actually installs.
51
+ python:
52
+ runs-on: ubuntu-latest
53
+ steps:
54
+ - uses: actions/checkout@v4
55
+ - uses: actions/setup-python@v5
56
+ with:
57
+ python-version: '3.12'
58
+ # The Python tests replay committed tapes through this binary to build a
59
+ # fixture archive, so they need it built but never need a live venue.
60
+ - run: cargo build --release --bin tickvault
61
+ - run: pip install maturin pytest pyarrow polars pandas matplotlib
62
+ - name: build and install the wheel
63
+ working-directory: bindings
64
+ run: |
65
+ maturin build --release --out dist
66
+ pip install --no-index --find-links dist tickvault-ob
67
+ - working-directory: bindings
68
+ run: pytest tests -q
@@ -0,0 +1,100 @@
1
+ name: release
2
+
3
+ # Tag driven. `git tag v0.1.0 && git push --tags` builds wheels for every
4
+ # platform and publishes them, so the README's `pip install tickvault` stops
5
+ # being a claim about something that does not exist.
6
+ on:
7
+ push:
8
+ tags: ['v*']
9
+ # Buildable on demand too, so the wheels can be checked without claiming a
10
+ # version on PyPI.
11
+ workflow_dispatch:
12
+
13
+ jobs:
14
+ wheels:
15
+ name: wheel (${{ matrix.target }})
16
+ runs-on: ${{ matrix.os }}
17
+ strategy:
18
+ fail-fast: false
19
+ matrix:
20
+ include:
21
+ - os: ubuntu-latest
22
+ target: x86_64-unknown-linux-gnu
23
+ - os: macos-latest
24
+ target: aarch64-apple-darwin
25
+ # macos-latest runners are Apple silicon, so an Intel Mac would
26
+ # otherwise fall back to the sdist and compile Rust at install time.
27
+ - os: macos-latest
28
+ target: x86_64-apple-darwin
29
+ - os: windows-latest
30
+ target: x86_64-pc-windows-msvc
31
+ steps:
32
+ - uses: actions/checkout@v4
33
+ - uses: actions/setup-python@v5
34
+ with:
35
+ python-version: '3.12'
36
+ # One wheel per platform covers every Python from 3.9 up, because the
37
+ # extension is built against the stable ABI. Without that it would be a
38
+ # wheel per platform per interpreter version.
39
+ - name: build
40
+ uses: PyO3/maturin-action@v1
41
+ with:
42
+ command: build
43
+ target: ${{ matrix.target }}
44
+ args: --release --out dist --manifest-path bindings/Cargo.toml
45
+ manylinux: auto
46
+ - uses: actions/upload-artifact@v4
47
+ with:
48
+ name: wheels-${{ matrix.target }}
49
+ path: dist
50
+
51
+ sdist:
52
+ runs-on: ubuntu-latest
53
+ steps:
54
+ - uses: actions/checkout@v4
55
+ - uses: PyO3/maturin-action@v1
56
+ with:
57
+ command: sdist
58
+ args: --out dist --manifest-path bindings/Cargo.toml
59
+ - uses: actions/upload-artifact@v4
60
+ with:
61
+ name: sdist
62
+ path: dist
63
+
64
+ # Checks the wheel actually installs and works before anything is published.
65
+ # A release that ships a broken wheel is worse than no release.
66
+ verify:
67
+ needs: [wheels]
68
+ runs-on: ubuntu-latest
69
+ steps:
70
+ - uses: actions/checkout@v4
71
+ - uses: actions/setup-python@v5
72
+ with:
73
+ python-version: '3.12'
74
+ - uses: actions/download-artifact@v4
75
+ with:
76
+ name: wheels-x86_64-unknown-linux-gnu
77
+ path: dist
78
+ # The Python tests replay committed tapes through this binary, so they
79
+ # need it built and never need a live venue.
80
+ - run: cargo build --release --bin tickvault
81
+ - run: pip install pytest pyarrow polars pandas matplotlib
82
+ - run: pip install --no-index --find-links dist tickvault-ob
83
+ - working-directory: bindings
84
+ run: pytest tests -q
85
+
86
+ publish:
87
+ needs: [wheels, sdist, verify]
88
+ if: startsWith(github.ref, 'refs/tags/')
89
+ runs-on: ubuntu-latest
90
+ environment: pypi
91
+ # Trusted publishing: PyPI verifies this workflow rather than a long-lived
92
+ # token living in the repo's secrets.
93
+ permissions:
94
+ id-token: write
95
+ steps:
96
+ - uses: actions/download-artifact@v4
97
+ with:
98
+ path: dist
99
+ merge-multiple: true
100
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,10 @@
1
+ /target
2
+
3
+ # Python build artefacts from the bindings.
4
+ __pycache__/
5
+ *.so
6
+ .pytest_cache/
7
+
8
+ # wasm build output
9
+ viewer/pkg/
10
+ viewer/target/
@@ -0,0 +1,102 @@
1
+ # Contributing to tickvault
2
+
3
+ Thanks for looking. tickvault records order books, and its whole claim is that
4
+ the resulting dataset is honest about its own holes. So the bar for anything
5
+ touching what the archive says about itself is deliberately high, and the bar
6
+ for everything else is normal.
7
+
8
+ ## The contract you must not break
9
+
10
+ **Nothing may claim to be clean unless it was checked.** That is the sentence
11
+ the repo exists to defend, and most of the review of a change goes into whether
12
+ it quietly weakens one of these:
13
+
14
+ - **A detected gap stops the book.** Never stitch deltas across a hole. A
15
+ stitched book looks continuous and is wrong, which is the exact failure that
16
+ makes free order book data untrustworthy.
17
+ - **Unverifiable is not clean.** A message that could not be checked is counted
18
+ apart from one that was checked and passed. Bitstamp's aggregated feed reports
19
+ 0% verified, and it is never rounded up to look like the others.
20
+ - **Null is not zero.** Where the data cannot answer, it returns nothing. A
21
+ one-sided book has no mid. An aggregated feed does not know what traded.
22
+ Writing a zero there is a claim, and a false one.
23
+ - **Our faults are labelled as ours.** Rows lost because the writer fell behind
24
+ are counted separately from messages the venue never sent. Same for retention:
25
+ data we chose to stop keeping is a different manifest entry from data we lost.
26
+ - **Never blame the venue for our own defect.** If our decimal rendering lost
27
+ digits, or the book was shallower than the checksum covers, that message is
28
+ unverifiable, not a gap.
29
+
30
+ If a change of yours makes a gate fail, the change is wrong, not the gate. Three
31
+ of the gates were written after a passing test turned out to be passing for the
32
+ wrong reason, which is why they assert properties rather than outputs.
33
+
34
+ ## Getting oriented
35
+
36
+ | Path | What lives there |
37
+ |---|---|
38
+ | `src/venue/` | The `Venue` trait, six implementations, and the capability matrix that keeps the ingest loop free of special cases. |
39
+ | `src/session.rs` | The ingest loop. Exactly two branches on venue capabilities; everything else is data. |
40
+ | `src/gap.rs` | Suspect windows and the report they feed. The product. |
41
+ | `src/store/` | Parquet schema, writer, manifest, recovery, retention. |
42
+ | `src/reconstruct/`, `src/query/` | Rebuilding a book at an instant, and reading the archive. |
43
+ | `src/supervise.rs`, `src/status.rs` | Running as a service, and answering for it. |
44
+ | `docs/venues.md` | Per-venue findings, measured rather than read off a doc page. |
45
+ | `docs/schema.md` | Every column, and what null means in it. |
46
+ | `tests/gate_*.rs` | The gates. Each states a property. |
47
+ | `viewer/` | The reconstruction engine compiled to wasm, behind the demo page. |
48
+ | `bindings/` | The Python package. |
49
+
50
+ ## Building and testing
51
+
52
+ ```bash
53
+ cargo test # the suite
54
+ cargo test -- --ignored # real SIGKILLs, plus one live venue reconciliation
55
+ cargo clippy --all-targets -- -D warnings
56
+ cargo fmt --check
57
+ ```
58
+
59
+ CI runs all of that except the live reconciliation, which measures Bitstamp's two
60
+ feeds against each other and would make the build depend on a venue's afternoon.
61
+
62
+ The Python and wasm halves have their own commands:
63
+
64
+ ```bash
65
+ cd bindings && maturin develop --release && pytest tests
66
+ scripts/build-viewer.sh && cd viewer && cargo test
67
+ ```
68
+
69
+ ## Adding a venue
70
+
71
+ This is meant to be mechanical rather than archaeological, and the conformance
72
+ suite in `tests/conformance.rs` is what makes it so. Implement `Venue`, declare
73
+ its capabilities honestly, add a captured fixture, and the suite will tell you
74
+ what is inconsistent.
75
+
76
+ Two things worth knowing before you start:
77
+
78
+ - **Measure the feed, do not read the docs.** Nearly every interesting line in
79
+ `docs/venues.md` contradicts what the venue's documentation implies. Capture a
80
+ tape with `tickvault record --out tape.jsonl` and look at it.
81
+ - **Declare what the venue cannot prove.** A venue with no sequencing gets a
82
+ `MonotonicTimestamp` scheme and a blind spot entry, not a hopeful guess. The
83
+ capability matrix is what keeps the honesty rules enforceable in one place.
84
+
85
+ ## Style
86
+
87
+ Commits are one logical change each, buildable on their own, with a subject in
88
+ the imperative and a body explaining why rather than what. Several of the
89
+ existing messages record a measurement that overturned an assumption; that is
90
+ the useful kind.
91
+
92
+ No em dashes anywhere, in code, comments, docs or commit messages.
93
+
94
+ Comments explain why, not what. If a comment restates the line below it, delete
95
+ one of them.
96
+
97
+ ## Publishing a number
98
+
99
+ Any figure in the README has to be reproducible by a command in the README.
100
+ `tickvault bench` backs the throughput claim, `tests/gate_*.rs` back the
101
+ correctness ones, and `docs/venues.md` says which machine and which capture each
102
+ measurement came from. A number without a way to check it does not belong here.