briskapi 0.2.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.
- briskapi-0.2.0/LICENSE +21 -0
- briskapi-0.2.0/PKG-INFO +201 -0
- briskapi-0.2.0/README.md +187 -0
- briskapi-0.2.0/briskapi/LICENSE-pybrisk.txt +21 -0
- briskapi-0.2.0/briskapi/__init__.py +67 -0
- briskapi-0.2.0/briskapi/__main__.py +3 -0
- briskapi-0.2.0/briskapi/_archive.py +62 -0
- briskapi-0.2.0/briskapi/_live.py +376 -0
- briskapi-0.2.0/briskapi/_market.py +136 -0
- briskapi-0.2.0/briskapi/_recording.py +192 -0
- briskapi-0.2.0/briskapi/archive.json +5 -0
- briskapi-0.2.0/briskapi/cli.py +337 -0
- briskapi-0.2.0/briskapi/decoder/assets.json +13 -0
- briskapi-0.2.0/briskapi/decoder/decoder.cjs +282 -0
- briskapi-0.2.0/briskapi/decoder/sbi.cjs +144 -0
- briskapi-0.2.0/briskapi/decoder/web.cjs +44 -0
- briskapi-0.2.0/briskapi/references/historical_mock.json +4140 -0
- briskapi-0.2.0/briskapi/sbi.py +266 -0
- briskapi-0.2.0/briskapi/schema.py +351 -0
- briskapi-0.2.0/briskapi/timing.py +72 -0
- briskapi-0.2.0/briskapi.egg-info/PKG-INFO +201 -0
- briskapi-0.2.0/briskapi.egg-info/SOURCES.txt +30 -0
- briskapi-0.2.0/briskapi.egg-info/dependency_links.txt +1 -0
- briskapi-0.2.0/briskapi.egg-info/entry_points.txt +2 -0
- briskapi-0.2.0/briskapi.egg-info/requires.txt +4 -0
- briskapi-0.2.0/briskapi.egg-info/top_level.txt +1 -0
- briskapi-0.2.0/pyproject.toml +29 -0
- briskapi-0.2.0/setup.cfg +4 -0
- briskapi-0.2.0/tests/test_api.py +403 -0
- briskapi-0.2.0/tests/test_archive.py +561 -0
- briskapi-0.2.0/tests/test_sbi.py +244 -0
- briskapi-0.2.0/tests/test_timing.py +92 -0
briskapi-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 honvl
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
briskapi-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: briskapi
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Unofficial Python API, live feed and shared archive for BRiSK auction data
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Source, https://github.com/honvl/BRiSKapi
|
|
7
|
+
Requires-Python: >=3.12
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: boto3<2,>=1.41
|
|
11
|
+
Provides-Extra: pandas
|
|
12
|
+
Requires-Dist: pandas>=2; extra == "pandas"
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+
# briskapi
|
|
16
|
+
|
|
17
|
+
[English](README.md) | [日本語](README.ja.md)
|
|
18
|
+
|
|
19
|
+
An unofficial, pybrisk-style Python API and `brisk` command line for BRiSK auction
|
|
20
|
+
data. Consume a live feed, query recordings at any point in time, pull shared
|
|
21
|
+
recordings from a public archive, and use SBI BRiSK with your own account. This
|
|
22
|
+
is an independent project, not affiliated with or endorsed by BRiSK, Tachibana,
|
|
23
|
+
SBI, TSE or JPX.
|
|
24
|
+
|
|
25
|
+
> **Data sources:**
|
|
26
|
+
> - **No account needed:** the public BRiSK Next demo of 27 September 2021 (one
|
|
27
|
+
> pre-open snapshot and the first three minutes after the open), replayed at
|
|
28
|
+
> its recorded pace. This is not live market data.
|
|
29
|
+
> - **With an SBI Securities BRiSK subscription:** SBI BRiSK market data (candles,
|
|
30
|
+
> margin, alerts, schedule, watchlist) and an experimental live feed.
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
Python 3.12+. Live feeds and recording also need Node 22+, because BRiSK's own
|
|
35
|
+
decoder is a WebAssembly module that runs under Node.
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
pip install 'briskapi[pandas]' # `import briskapi` and the `brisk` command
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
BRiSK's decoder and demo data are downloaded at runtime; the package doesn't
|
|
42
|
+
include them. Optional prebuilt Rust tools (`brisk_quote_ingest`,
|
|
43
|
+
`brisk_recording`) for Linux, macOS and Windows are attached to each
|
|
44
|
+
[GitHub release](https://github.com/honvl/BRiSKapi/releases). To work from source,
|
|
45
|
+
clone the repository and run `pip install -e '.[pandas]'`.
|
|
46
|
+
|
|
47
|
+
## Live feed
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
import briskapi
|
|
51
|
+
|
|
52
|
+
feed = briskapi.connect(web=True, codes=["7203", "6758"]) # returns once initial state is in
|
|
53
|
+
toyota = briskapi.Ticker("7203")
|
|
54
|
+
toyota.quote() # current quote, updated as each frame arrives
|
|
55
|
+
toyota.auction() # indicative price/volume and market-order imbalance
|
|
56
|
+
|
|
57
|
+
feed.on_quote(lambda q: print(q["code"], q["indicative_price"]), codes="6758")
|
|
58
|
+
for q in feed.quotes("7203"): # one item per update; ends with the session
|
|
59
|
+
if q["last_price"]:
|
|
60
|
+
print("opened at", q["last_price"], q["time"])
|
|
61
|
+
break
|
|
62
|
+
|
|
63
|
+
briskapi.Market().imbalances(top=10).to_pandas()
|
|
64
|
+
feed.wait() # or feed.close(); `with briskapi.connect(...) as feed:` also works
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Options: `web=True` (fetch from the demo site) or `cache=DIR` (a local copy of
|
|
68
|
+
the demo assets), `codes`, `speed` (`1` real time, `0` as fast as possible) and
|
|
69
|
+
`history=True` (keep updates for `Ticker.history()`). Callbacks and iterators
|
|
70
|
+
first receive each security's current quote, then every update in order. A slow
|
|
71
|
+
consumer slows the feed instead of losing updates.
|
|
72
|
+
|
|
73
|
+
## Recordings and the archive
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
briskapi.recordings(source="historical_mock") # published recordings; no AWS account needed
|
|
77
|
+
briskapi.pull("archive/20210927/SHA256") # download, verify, decode and cache; becomes the default
|
|
78
|
+
briskapi.load("recordings/my-session") # or a local recording (events.jsonl[.gz] or folder)
|
|
79
|
+
briskapi.record("recordings/my-session", web=True) # record the demo yourself
|
|
80
|
+
|
|
81
|
+
briskapi.Ticker("7203").quote(at="08:59:59.99") # state at any JST time
|
|
82
|
+
briskapi.Ticker("7203").history(start="09:00", end="09:01") # every update in a window
|
|
83
|
+
briskapi.Market().snapshot(at="09:00:00").to_pandas()
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## SBI BRiSK
|
|
87
|
+
|
|
88
|
+
For SBI Securities customers with a BRiSK subscription. Log in on
|
|
89
|
+
[sbi.brisk.jp](https://sbi.brisk.jp) in your browser, then pass its session
|
|
90
|
+
cookies: copy them from DevTools, or use `pycookiecheat`'s
|
|
91
|
+
`chrome_cookies("https://sbi.brisk.jp")`.
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from briskapi import sbi
|
|
95
|
+
|
|
96
|
+
sbi.login(cookies={"session_bfaf77a2": "v2.local..."}) # remember=True saves them (owner-only file)
|
|
97
|
+
toyota = briskapi.Ticker("7203")
|
|
98
|
+
toyota.candles("5m").to_pandas() # price bars: 5m (today), 1d, 1w or 1mo
|
|
99
|
+
toyota.margin(days=30) # margin balances and stock-lending fees
|
|
100
|
+
market = briskapi.Market()
|
|
101
|
+
market.turnover() # turnover and shares outstanding, all stocks
|
|
102
|
+
market.lists() # NK225, recent IPOs, …
|
|
103
|
+
market.events() # basket orders, limit up/down, volume surges
|
|
104
|
+
market.schedule() # trading date, status and session times
|
|
105
|
+
market.watchlist() # your saved codes
|
|
106
|
+
|
|
107
|
+
feed = sbi.connect(codes=["7203"]) # live (experimental)
|
|
108
|
+
toyota.quote() # same calls as any feed
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Results use the conventions below. Errors are `sbi.SessionExpiredError` (log in
|
|
112
|
+
again), `briskapi.NotFoundError`, `sbi.RateLimitError` and `sbi.APIError`.
|
|
113
|
+
Requests are limited to one per second.
|
|
114
|
+
|
|
115
|
+
The live feed runs SBI's own decoder under Node, downloaded with your session;
|
|
116
|
+
no browser is involved. It hasn't yet been validated against a live SBI session,
|
|
117
|
+
so it fails with an explicit error rather than guessing. Please report what you
|
|
118
|
+
see. Your cookies go only to sbi.brisk.jp, and SBI market data never leaves
|
|
119
|
+
your computer. With sharing on, a session contributes only a timing summary (see
|
|
120
|
+
below).
|
|
121
|
+
|
|
122
|
+
## API reference
|
|
123
|
+
|
|
124
|
+
| Call | Returns |
|
|
125
|
+
| --- | --- |
|
|
126
|
+
| `briskapi.connect(...)` | Live `Feed`; becomes the default source |
|
|
127
|
+
| `Ticker(code).info()` | Name, lot size, tick type, base price and daily limits |
|
|
128
|
+
| `Ticker(code).quote(at=None)` | Bid/ask, indicative price/volume, market-order and closing quantities, last trade |
|
|
129
|
+
| `Ticker(code).auction(at=None)` | Indicative auction state with `market_order_imbalance` (market buy minus sell) |
|
|
130
|
+
| `Ticker(code).history(start, end)` | Every update in order |
|
|
131
|
+
| `Market().stocks()` | Master for every security |
|
|
132
|
+
| `Market().snapshot(at=None)` | Every security's quote |
|
|
133
|
+
| `Market().imbalances(at=None, top=None)` | Securities ranked by absolute market-order imbalance |
|
|
134
|
+
| `Market().summary()` | Source, date, coverage and clock range |
|
|
135
|
+
| `Feed.quotes(codes)` / `Feed.on_quote(fn, codes)` | Live updates as they arrive |
|
|
136
|
+
| `briskapi.recordings()` / `.pull()` / `.load()` | Archive listing, verified download, local file |
|
|
137
|
+
| `briskapi.record(output, web=True, ...)` | A recording of the demo, shared per your choice |
|
|
138
|
+
| `briskapi.consent(...)` | Your sharing choice |
|
|
139
|
+
| `Ticker(code).candles(interval)` / `.margin(days)` | SBI BRiSK price bars; margin balances and lending fees |
|
|
140
|
+
| `Market().turnover()` / `.lists()` / `.events()` / `.schedule()` / `.watchlist()` | SBI BRiSK market data |
|
|
141
|
+
| `briskapi.sbi.login()` / `.connect()` | SBI BRiSK session and live feed |
|
|
142
|
+
|
|
143
|
+
Prices are yen floats, with `None` for the vendor's zero "unavailable" value.
|
|
144
|
+
Times are JST `datetime`s on the trading date. Quantities are shares; side, flag
|
|
145
|
+
and status codes are raw vendor values. `raw=True` returns vendor fields
|
|
146
|
+
(`*_price10` in tenths of a yen, `*_us` in microseconds since JST midnight).
|
|
147
|
+
Tabular results are lists of dicts with `.to_pandas()`. Errors are
|
|
148
|
+
`briskapi.BriskError` and `briskapi.NotFoundError`. A whole-market query reads a
|
|
149
|
+
recording once (about six seconds for the complete 420 MB demo).
|
|
150
|
+
|
|
151
|
+
## Command line
|
|
152
|
+
|
|
153
|
+
```sh
|
|
154
|
+
brisk live --web --codes 7203,6758 # one JSON object per quote update (--raw for vendor fields)
|
|
155
|
+
brisk live --sbi --codes 7203 # SBI BRiSK; cookies from BRISK_SBI_COOKIES (JSON)
|
|
156
|
+
brisk record --web --output recordings/s1 # record a replay (shared if you agreed)
|
|
157
|
+
brisk list --date 20210927 --source historical_mock
|
|
158
|
+
brisk pull archive/20210927/SHA256 --output recordings/downloaded
|
|
159
|
+
brisk consent [--accept | --revoke] # show or change sharing
|
|
160
|
+
brisk upload recordings/s1 # retry sharing a recording
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Each command has `--help`. `pull` verifies everything before writing and never
|
|
164
|
+
overwrites an existing folder.
|
|
165
|
+
|
|
166
|
+
## Sharing recordings
|
|
167
|
+
|
|
168
|
+
The first time you record or start a demo live session from the command line,
|
|
169
|
+
the tool shows what would be shared and asks once; Enter accepts. After that,
|
|
170
|
+
every complete demo session is uploaded and published automatically. The Python
|
|
171
|
+
API never asks: until you decide, sessions stay on your computer.
|
|
172
|
+
|
|
173
|
+
- **SBI sessions share timing only:** percentiles of decode time, data age at
|
|
174
|
+
receipt and frame spacing, a stall count, the frame count, the trading date,
|
|
175
|
+
the first and last minute, and your alias and license. Never prices,
|
|
176
|
+
quantities or codes. `briskapi.Archive().timing()` lists everyone's reports.
|
|
177
|
+
- **What a demo session shares:** the market data you recorded, local timing measurements
|
|
178
|
+
(including your computer's clock, which shows when you recorded), and a public
|
|
179
|
+
alias (random `anon-…` by default) and license. Your IP address is used only to
|
|
180
|
+
rate limit uploads.
|
|
181
|
+
- **Visibility:** published recordings are public and permanent, and you cannot
|
|
182
|
+
delete them yourself. See [PRIVACY.md](PRIVACY.md).
|
|
183
|
+
- **Opting out:** `brisk consent --revoke`, `BRISK_CONTRIBUTE=0`, or `--no-upload`
|
|
184
|
+
for one run.
|
|
185
|
+
- **License:** accepting declares that you may redistribute the recordings under
|
|
186
|
+
the chosen data license (CC0-1.0 or CC-BY-4.0). This project's open-source
|
|
187
|
+
license gives no rights to vendor or exchange data. If you can't make that
|
|
188
|
+
declaration, turn sharing off.
|
|
189
|
+
- Partial replays (`--limit-frames`) and sessions closed early are never shared.
|
|
190
|
+
|
|
191
|
+
## More documentation
|
|
192
|
+
|
|
193
|
+
- [ARCHITECTURE.md](ARCHITECTURE.md): how it works, data format, archive integrity and limits
|
|
194
|
+
- [PRIVACY.md](PRIVACY.md): privacy policy
|
|
195
|
+
- [CONTRIBUTING.md](CONTRIBUTING.md): development, tests and releases
|
|
196
|
+
- [tools/brisk_mock/README.md](tools/brisk_mock/README.md): Rust collector, field definitions, timing and latency
|
|
197
|
+
- [tools/brisk_mock/NAUTILUS_V2.md](tools/brisk_mock/NAUTILUS_V2.md): NautilusTrader v2 integration
|
|
198
|
+
- [infra/README.md](infra/README.md): deploying your own archive
|
|
199
|
+
- [THIRD_PARTY.md](THIRD_PARTY.md): decoder, data and pybrisk attribution
|
|
200
|
+
|
|
201
|
+
Software is MIT licensed.
|
briskapi-0.2.0/README.md
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# briskapi
|
|
2
|
+
|
|
3
|
+
[English](README.md) | [日本語](README.ja.md)
|
|
4
|
+
|
|
5
|
+
An unofficial, pybrisk-style Python API and `brisk` command line for BRiSK auction
|
|
6
|
+
data. Consume a live feed, query recordings at any point in time, pull shared
|
|
7
|
+
recordings from a public archive, and use SBI BRiSK with your own account. This
|
|
8
|
+
is an independent project, not affiliated with or endorsed by BRiSK, Tachibana,
|
|
9
|
+
SBI, TSE or JPX.
|
|
10
|
+
|
|
11
|
+
> **Data sources:**
|
|
12
|
+
> - **No account needed:** the public BRiSK Next demo of 27 September 2021 (one
|
|
13
|
+
> pre-open snapshot and the first three minutes after the open), replayed at
|
|
14
|
+
> its recorded pace. This is not live market data.
|
|
15
|
+
> - **With an SBI Securities BRiSK subscription:** SBI BRiSK market data (candles,
|
|
16
|
+
> margin, alerts, schedule, watchlist) and an experimental live feed.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
Python 3.12+. Live feeds and recording also need Node 22+, because BRiSK's own
|
|
21
|
+
decoder is a WebAssembly module that runs under Node.
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
pip install 'briskapi[pandas]' # `import briskapi` and the `brisk` command
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
BRiSK's decoder and demo data are downloaded at runtime; the package doesn't
|
|
28
|
+
include them. Optional prebuilt Rust tools (`brisk_quote_ingest`,
|
|
29
|
+
`brisk_recording`) for Linux, macOS and Windows are attached to each
|
|
30
|
+
[GitHub release](https://github.com/honvl/BRiSKapi/releases). To work from source,
|
|
31
|
+
clone the repository and run `pip install -e '.[pandas]'`.
|
|
32
|
+
|
|
33
|
+
## Live feed
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
import briskapi
|
|
37
|
+
|
|
38
|
+
feed = briskapi.connect(web=True, codes=["7203", "6758"]) # returns once initial state is in
|
|
39
|
+
toyota = briskapi.Ticker("7203")
|
|
40
|
+
toyota.quote() # current quote, updated as each frame arrives
|
|
41
|
+
toyota.auction() # indicative price/volume and market-order imbalance
|
|
42
|
+
|
|
43
|
+
feed.on_quote(lambda q: print(q["code"], q["indicative_price"]), codes="6758")
|
|
44
|
+
for q in feed.quotes("7203"): # one item per update; ends with the session
|
|
45
|
+
if q["last_price"]:
|
|
46
|
+
print("opened at", q["last_price"], q["time"])
|
|
47
|
+
break
|
|
48
|
+
|
|
49
|
+
briskapi.Market().imbalances(top=10).to_pandas()
|
|
50
|
+
feed.wait() # or feed.close(); `with briskapi.connect(...) as feed:` also works
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Options: `web=True` (fetch from the demo site) or `cache=DIR` (a local copy of
|
|
54
|
+
the demo assets), `codes`, `speed` (`1` real time, `0` as fast as possible) and
|
|
55
|
+
`history=True` (keep updates for `Ticker.history()`). Callbacks and iterators
|
|
56
|
+
first receive each security's current quote, then every update in order. A slow
|
|
57
|
+
consumer slows the feed instead of losing updates.
|
|
58
|
+
|
|
59
|
+
## Recordings and the archive
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
briskapi.recordings(source="historical_mock") # published recordings; no AWS account needed
|
|
63
|
+
briskapi.pull("archive/20210927/SHA256") # download, verify, decode and cache; becomes the default
|
|
64
|
+
briskapi.load("recordings/my-session") # or a local recording (events.jsonl[.gz] or folder)
|
|
65
|
+
briskapi.record("recordings/my-session", web=True) # record the demo yourself
|
|
66
|
+
|
|
67
|
+
briskapi.Ticker("7203").quote(at="08:59:59.99") # state at any JST time
|
|
68
|
+
briskapi.Ticker("7203").history(start="09:00", end="09:01") # every update in a window
|
|
69
|
+
briskapi.Market().snapshot(at="09:00:00").to_pandas()
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## SBI BRiSK
|
|
73
|
+
|
|
74
|
+
For SBI Securities customers with a BRiSK subscription. Log in on
|
|
75
|
+
[sbi.brisk.jp](https://sbi.brisk.jp) in your browser, then pass its session
|
|
76
|
+
cookies: copy them from DevTools, or use `pycookiecheat`'s
|
|
77
|
+
`chrome_cookies("https://sbi.brisk.jp")`.
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from briskapi import sbi
|
|
81
|
+
|
|
82
|
+
sbi.login(cookies={"session_bfaf77a2": "v2.local..."}) # remember=True saves them (owner-only file)
|
|
83
|
+
toyota = briskapi.Ticker("7203")
|
|
84
|
+
toyota.candles("5m").to_pandas() # price bars: 5m (today), 1d, 1w or 1mo
|
|
85
|
+
toyota.margin(days=30) # margin balances and stock-lending fees
|
|
86
|
+
market = briskapi.Market()
|
|
87
|
+
market.turnover() # turnover and shares outstanding, all stocks
|
|
88
|
+
market.lists() # NK225, recent IPOs, …
|
|
89
|
+
market.events() # basket orders, limit up/down, volume surges
|
|
90
|
+
market.schedule() # trading date, status and session times
|
|
91
|
+
market.watchlist() # your saved codes
|
|
92
|
+
|
|
93
|
+
feed = sbi.connect(codes=["7203"]) # live (experimental)
|
|
94
|
+
toyota.quote() # same calls as any feed
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Results use the conventions below. Errors are `sbi.SessionExpiredError` (log in
|
|
98
|
+
again), `briskapi.NotFoundError`, `sbi.RateLimitError` and `sbi.APIError`.
|
|
99
|
+
Requests are limited to one per second.
|
|
100
|
+
|
|
101
|
+
The live feed runs SBI's own decoder under Node, downloaded with your session;
|
|
102
|
+
no browser is involved. It hasn't yet been validated against a live SBI session,
|
|
103
|
+
so it fails with an explicit error rather than guessing. Please report what you
|
|
104
|
+
see. Your cookies go only to sbi.brisk.jp, and SBI market data never leaves
|
|
105
|
+
your computer. With sharing on, a session contributes only a timing summary (see
|
|
106
|
+
below).
|
|
107
|
+
|
|
108
|
+
## API reference
|
|
109
|
+
|
|
110
|
+
| Call | Returns |
|
|
111
|
+
| --- | --- |
|
|
112
|
+
| `briskapi.connect(...)` | Live `Feed`; becomes the default source |
|
|
113
|
+
| `Ticker(code).info()` | Name, lot size, tick type, base price and daily limits |
|
|
114
|
+
| `Ticker(code).quote(at=None)` | Bid/ask, indicative price/volume, market-order and closing quantities, last trade |
|
|
115
|
+
| `Ticker(code).auction(at=None)` | Indicative auction state with `market_order_imbalance` (market buy minus sell) |
|
|
116
|
+
| `Ticker(code).history(start, end)` | Every update in order |
|
|
117
|
+
| `Market().stocks()` | Master for every security |
|
|
118
|
+
| `Market().snapshot(at=None)` | Every security's quote |
|
|
119
|
+
| `Market().imbalances(at=None, top=None)` | Securities ranked by absolute market-order imbalance |
|
|
120
|
+
| `Market().summary()` | Source, date, coverage and clock range |
|
|
121
|
+
| `Feed.quotes(codes)` / `Feed.on_quote(fn, codes)` | Live updates as they arrive |
|
|
122
|
+
| `briskapi.recordings()` / `.pull()` / `.load()` | Archive listing, verified download, local file |
|
|
123
|
+
| `briskapi.record(output, web=True, ...)` | A recording of the demo, shared per your choice |
|
|
124
|
+
| `briskapi.consent(...)` | Your sharing choice |
|
|
125
|
+
| `Ticker(code).candles(interval)` / `.margin(days)` | SBI BRiSK price bars; margin balances and lending fees |
|
|
126
|
+
| `Market().turnover()` / `.lists()` / `.events()` / `.schedule()` / `.watchlist()` | SBI BRiSK market data |
|
|
127
|
+
| `briskapi.sbi.login()` / `.connect()` | SBI BRiSK session and live feed |
|
|
128
|
+
|
|
129
|
+
Prices are yen floats, with `None` for the vendor's zero "unavailable" value.
|
|
130
|
+
Times are JST `datetime`s on the trading date. Quantities are shares; side, flag
|
|
131
|
+
and status codes are raw vendor values. `raw=True` returns vendor fields
|
|
132
|
+
(`*_price10` in tenths of a yen, `*_us` in microseconds since JST midnight).
|
|
133
|
+
Tabular results are lists of dicts with `.to_pandas()`. Errors are
|
|
134
|
+
`briskapi.BriskError` and `briskapi.NotFoundError`. A whole-market query reads a
|
|
135
|
+
recording once (about six seconds for the complete 420 MB demo).
|
|
136
|
+
|
|
137
|
+
## Command line
|
|
138
|
+
|
|
139
|
+
```sh
|
|
140
|
+
brisk live --web --codes 7203,6758 # one JSON object per quote update (--raw for vendor fields)
|
|
141
|
+
brisk live --sbi --codes 7203 # SBI BRiSK; cookies from BRISK_SBI_COOKIES (JSON)
|
|
142
|
+
brisk record --web --output recordings/s1 # record a replay (shared if you agreed)
|
|
143
|
+
brisk list --date 20210927 --source historical_mock
|
|
144
|
+
brisk pull archive/20210927/SHA256 --output recordings/downloaded
|
|
145
|
+
brisk consent [--accept | --revoke] # show or change sharing
|
|
146
|
+
brisk upload recordings/s1 # retry sharing a recording
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Each command has `--help`. `pull` verifies everything before writing and never
|
|
150
|
+
overwrites an existing folder.
|
|
151
|
+
|
|
152
|
+
## Sharing recordings
|
|
153
|
+
|
|
154
|
+
The first time you record or start a demo live session from the command line,
|
|
155
|
+
the tool shows what would be shared and asks once; Enter accepts. After that,
|
|
156
|
+
every complete demo session is uploaded and published automatically. The Python
|
|
157
|
+
API never asks: until you decide, sessions stay on your computer.
|
|
158
|
+
|
|
159
|
+
- **SBI sessions share timing only:** percentiles of decode time, data age at
|
|
160
|
+
receipt and frame spacing, a stall count, the frame count, the trading date,
|
|
161
|
+
the first and last minute, and your alias and license. Never prices,
|
|
162
|
+
quantities or codes. `briskapi.Archive().timing()` lists everyone's reports.
|
|
163
|
+
- **What a demo session shares:** the market data you recorded, local timing measurements
|
|
164
|
+
(including your computer's clock, which shows when you recorded), and a public
|
|
165
|
+
alias (random `anon-…` by default) and license. Your IP address is used only to
|
|
166
|
+
rate limit uploads.
|
|
167
|
+
- **Visibility:** published recordings are public and permanent, and you cannot
|
|
168
|
+
delete them yourself. See [PRIVACY.md](PRIVACY.md).
|
|
169
|
+
- **Opting out:** `brisk consent --revoke`, `BRISK_CONTRIBUTE=0`, or `--no-upload`
|
|
170
|
+
for one run.
|
|
171
|
+
- **License:** accepting declares that you may redistribute the recordings under
|
|
172
|
+
the chosen data license (CC0-1.0 or CC-BY-4.0). This project's open-source
|
|
173
|
+
license gives no rights to vendor or exchange data. If you can't make that
|
|
174
|
+
declaration, turn sharing off.
|
|
175
|
+
- Partial replays (`--limit-frames`) and sessions closed early are never shared.
|
|
176
|
+
|
|
177
|
+
## More documentation
|
|
178
|
+
|
|
179
|
+
- [ARCHITECTURE.md](ARCHITECTURE.md): how it works, data format, archive integrity and limits
|
|
180
|
+
- [PRIVACY.md](PRIVACY.md): privacy policy
|
|
181
|
+
- [CONTRIBUTING.md](CONTRIBUTING.md): development, tests and releases
|
|
182
|
+
- [tools/brisk_mock/README.md](tools/brisk_mock/README.md): Rust collector, field definitions, timing and latency
|
|
183
|
+
- [tools/brisk_mock/NAUTILUS_V2.md](tools/brisk_mock/NAUTILUS_V2.md): NautilusTrader v2 integration
|
|
184
|
+
- [infra/README.md](infra/README.md): deploying your own archive
|
|
185
|
+
- [THIRD_PARTY.md](THIRD_PARTY.md): decoder, data and pybrisk attribution
|
|
186
|
+
|
|
187
|
+
Software is MIT licensed.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 obichan117
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Python API for BRiSK auction data: recordings, the shared archive and the public demo.
|
|
2
|
+
|
|
3
|
+
import briskapi
|
|
4
|
+
|
|
5
|
+
feed = briskapi.connect(web=True) # live: state updates as frames arrive
|
|
6
|
+
briskapi.Ticker("7203").quote() # current auction quote
|
|
7
|
+
for q in feed.quotes("7203"): ... # or feed.on_quote(callback)
|
|
8
|
+
|
|
9
|
+
briskapi.pull(prefix) # or briskapi.load(path) / briskapi.record(...)
|
|
10
|
+
briskapi.Ticker("7203").quote(at="08:59:59")
|
|
11
|
+
briskapi.Market().imbalances(top=10).to_pandas()
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from briskapi import cli as _cli
|
|
16
|
+
from briskapi._archive import Archive
|
|
17
|
+
from briskapi._live import Feed, connect as _connect, record as _record, stream
|
|
18
|
+
from briskapi._market import Market, Ticker
|
|
19
|
+
from briskapi._recording import JST, BriskError, NotFoundError, Recording, Table
|
|
20
|
+
|
|
21
|
+
__version__ = '0.2.0'
|
|
22
|
+
__all__ = ['JST', 'Archive', 'BriskError', 'Feed', 'Market', 'NotFoundError', 'Recording', 'Table', 'Ticker',
|
|
23
|
+
'connect', 'consent', 'current', 'load', 'pull', 'record', 'recordings', 'stream']
|
|
24
|
+
|
|
25
|
+
_current: Recording | Feed | None = None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def load(source) -> Recording | Feed:
|
|
29
|
+
"""Use a live Feed or a recording (path, directory or Recording) as the default for Ticker and Market."""
|
|
30
|
+
global _current
|
|
31
|
+
_current = source if isinstance(source, (Recording, Feed)) else Recording(source)
|
|
32
|
+
return _current
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def current() -> Recording | Feed:
|
|
36
|
+
if _current is None:
|
|
37
|
+
raise BriskError('Nothing loaded: use briskapi.connect(...), briskapi.load(path), briskapi.pull(prefix) or briskapi.record(...)')
|
|
38
|
+
return _current
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def connect(**options) -> Feed:
|
|
42
|
+
"""Start a live feed (see Feed) and make it the default for Ticker and Market."""
|
|
43
|
+
return load(_connect(**options))
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def recordings(date=None, source=None) -> Table:
|
|
47
|
+
"""Published archive recordings (see Archive.recordings)."""
|
|
48
|
+
return Archive().recordings(date, source)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def pull(prefix, output=None) -> Recording:
|
|
52
|
+
"""Download and verify an archive recording, then make it the default."""
|
|
53
|
+
return load(Archive().pull(prefix, output))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def record(output, **options) -> Recording:
|
|
57
|
+
"""Record the public demo (see briskapi._live.record), contribute per consent and make it the default."""
|
|
58
|
+
return load(_record(output, **options))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def consent(accept=False, revoke=False, contributor=None, license=None) -> dict | None:
|
|
62
|
+
"""Show (no arguments), accept or revoke automatic contribution. See PRIVACY.md."""
|
|
63
|
+
if accept and revoke:
|
|
64
|
+
raise ValueError('Choose accept or revoke')
|
|
65
|
+
if accept:
|
|
66
|
+
return _cli.save_consent(True, contributor, license)
|
|
67
|
+
return _cli.save_consent(False) if revoke else _cli.load_consent()
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""The shared public archive: list, pull (verified and cached) and contribute."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import re
|
|
7
|
+
|
|
8
|
+
from briskapi import cli
|
|
9
|
+
from briskapi._recording import Recording, Table
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def cache_dir() -> Path:
|
|
13
|
+
return Path(os.environ.get('XDG_CACHE_HOME') or Path.home() / '.cache') / 'brisk'
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Archive:
|
|
17
|
+
"""Recordings published in the Tokyo archive. Reading needs no AWS account.
|
|
18
|
+
|
|
19
|
+
archive = Archive()
|
|
20
|
+
rows = archive.recordings(source="historical_mock")
|
|
21
|
+
rec = archive.pull(rows[0]["prefix"])
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, config=None, s3=None):
|
|
25
|
+
self.config = cli.settings(Path(config) if config else None)
|
|
26
|
+
self._s3 = s3
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def s3(self):
|
|
30
|
+
if self._s3 is None:
|
|
31
|
+
self._s3 = cli.client(self.config)
|
|
32
|
+
return self._s3
|
|
33
|
+
|
|
34
|
+
def recordings(self, date=None, source=None) -> Table:
|
|
35
|
+
"""Published recordings, optionally filtered by YYYYMMDD trading date and source."""
|
|
36
|
+
rows = []
|
|
37
|
+
for prefix, m in cli.manifests(self.s3, self.config['bucket'], date):
|
|
38
|
+
s = m['summary']
|
|
39
|
+
if source is None or s['source'] == source:
|
|
40
|
+
rows.append({'prefix': prefix, 'source': s['source'], 'trading_date': s['trading_date'],
|
|
41
|
+
'securities': len(s['codes']), 'batches': s['batches'],
|
|
42
|
+
'quote_updates': s['quote_updates'], 'bytes': m['bytes'],
|
|
43
|
+
'contributor': m['contributor'], 'license': m['license'], 'sha256': m['sha256']})
|
|
44
|
+
return Table(rows)
|
|
45
|
+
|
|
46
|
+
def timing(self, date=None) -> Table:
|
|
47
|
+
"""Published timing-only reports (from SBI BRiSK sessions), optionally for one YYYYMMDD date."""
|
|
48
|
+
return Table({'key': key, **report} for key, report in cli.timing_reports(self.s3, self.config['bucket'], date))
|
|
49
|
+
|
|
50
|
+
def pull(self, prefix, output=None) -> Recording:
|
|
51
|
+
"""Download, verify and decode one recording. Without `output`, downloads are cached."""
|
|
52
|
+
if not re.fullmatch(r'archive/\d{8}/[0-9a-f]{64}', prefix):
|
|
53
|
+
raise ValueError('Invalid archive prefix')
|
|
54
|
+
target = Path(output) if output else cache_dir() / prefix
|
|
55
|
+
# Cache entries only appear after verification (pull moves them atomically).
|
|
56
|
+
if output or not target.exists():
|
|
57
|
+
cli.pull(self.s3, self.config['bucket'], prefix, target)
|
|
58
|
+
return Recording(target)
|
|
59
|
+
|
|
60
|
+
def contribute(self, directory, timeout=660) -> dict:
|
|
61
|
+
"""Upload a prepared package and wait for automatic validation and publication."""
|
|
62
|
+
return cli.contribute(Path(directory), self.config['api_url'], timeout)
|