lse-data 3.0__tar.gz → 3.0.1__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.
- {lse_data-3.0 → lse_data-3.0.1}/CHANGELOG.md +18 -0
- {lse_data-3.0 → lse_data-3.0.1}/PKG-INFO +22 -25
- {lse_data-3.0 → lse_data-3.0.1}/README.md +20 -23
- {lse_data-3.0 → lse_data-3.0.1}/docs/api.md +98 -78
- {lse_data-3.0 → lse_data-3.0.1}/examples/history_file.py +5 -5
- {lse_data-3.0 → lse_data-3.0.1}/lse/__init__.py +1 -1
- {lse_data-3.0 → lse_data-3.0.1}/lse/client.py +353 -145
- {lse_data-3.0 → lse_data-3.0.1}/lse/data3.py +61 -25
- {lse_data-3.0 → lse_data-3.0.1}/pyproject.toml +2 -2
- {lse_data-3.0 → lse_data-3.0.1}/.gitignore +0 -0
- {lse_data-3.0 → lse_data-3.0.1}/LICENSE +0 -0
- {lse_data-3.0 → lse_data-3.0.1}/examples/async_stream.py +0 -0
- {lse_data-3.0 → lse_data-3.0.1}/examples/basic_stream.py +0 -0
- {lse_data-3.0 → lse_data-3.0.1}/examples/callback_style.py +0 -0
- {lse_data-3.0 → lse_data-3.0.1}/examples/catalogue.py +0 -0
- {lse_data-3.0 → lse_data-3.0.1}/examples/disconnect_example.py +0 -0
- {lse_data-3.0 → lse_data-3.0.1}/examples/macro_series.py +0 -0
- {lse_data-3.0 → lse_data-3.0.1}/examples/options_data.py +0 -0
- {lse_data-3.0 → lse_data-3.0.1}/examples/options_stream.py +0 -0
- {lse_data-3.0 → lse_data-3.0.1}/examples/reference_rows.py +0 -0
- {lse_data-3.0 → lse_data-3.0.1}/examples/save_to_csv.py +0 -0
- {lse_data-3.0 → lse_data-3.0.1}/examples/unsubscribe_example.py +0 -0
- {lse_data-3.0 → lse_data-3.0.1}/lse/cli.py +0 -0
- {lse_data-3.0 → lse_data-3.0.1}/lse/py.typed +0 -0
- {lse_data-3.0 → lse_data-3.0.1}/lse/tui.py +0 -0
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## LSE Data 3.0.1
|
|
4
|
+
|
|
5
|
+
Fixes to the 3.0 client; the calls and their names are the same. `pip install -U lse-data`.
|
|
6
|
+
|
|
7
|
+
Fixed
|
|
8
|
+
|
|
9
|
+
- Direct `rows()` downloads, including `candles()`, verify the response SHA-256 and declared size before parsing. A damaged or shortened CSV is refused instead of becoming partial history.
|
|
10
|
+
- Long weekly and monthly `candles()` reads keep each candle whole. Internal date chunks previously split a week or month into two partial rows. Timestamp-bounded daily reads also stay whole across exchange session boundaries, and intraday chunks join a candle that crosses a session boundary. Requested start/end bounds and the row limit are preserved.
|
|
11
|
+
- A `429` could come back as nothing. With `retries=0`, a call that waited out a `429` returned `None` (`usage()` and every JSON call), or raised `no-response` (`rows()`, `candles()`, the reference readers) or `download-missing` (`export()`), although the server would have answered the next ask; a client that had waited once could do the same on a later call with the default retries. Now every call waits a `Retry-After` of two minutes or less once, the wait does not use up a retry, nothing is carried from one call to the next, and a refusal that stands is raised as `LSEError` with the server's own code and sentence (`calls-exhausted`, `connections-exhausted`, `rows-exhausted`, `allowance-exhausted`).
|
|
12
|
+
- Crypto streams again from the default client. Crypto moved to `wss://london-ws.londonstrategicedge.com` on 8 November 2026, and `stream(["BTC/USD", "AAPL"])` on the default address then gave one old price for BTC/USD and nothing after it. The client now opens the crypto socket beside the default one, with the same key, for the symbols the catalogue lists as crypto, and their ticks arrive in the same loop and callbacks; `subscribe()` and `unsubscribe()` while connected go to the right socket. A client made with `url=` uses that socket alone, as before. If the crypto socket refuses the key, the `error` event carries its sentence with that address and the other symbols keep streaming.
|
|
13
|
+
- A missing-data answer is recognised by its code, whatever its sentence: the server's sentence now begins "No stored data for this selection" and says why.
|
|
14
|
+
|
|
15
|
+
Changed
|
|
16
|
+
|
|
17
|
+
- `stream(..., start=...)` and `stream_async(..., start=...)`: replay was removed from the sockets on 25 October 2026, and a `start` left the loop waiting for ticks that never came. The server's refusal is now raised as `LSEError` (410, `REPLAY_REMOVED`) with its sentence. For history use `candles()`, `rows()` or `export()`.
|
|
18
|
+
- The README's examples run as written: the Level 2 and Level 3 examples ask for a minute by time, the years-of-candles example asks for five years (about half of the 2,500,000 rows one export may read), the options flow examples name their day.
|
|
19
|
+
- The guide (`docs/api.md`) describes the server as it answers now: files are sent at once and not kept (the prepared-job routes answer `404 export-unknown`), paid plans download at 250 Mbit/s, one export reads at most 2,500,000 rows (`413 export-too-wide`), the free plan reads 12,500,000 rows a day (`429 rows-exhausted`), and `/v3/usage` reports both under `rows`.
|
|
20
|
+
|
|
3
21
|
## LSE Data 3.0
|
|
4
22
|
|
|
5
23
|
Every read of history now comes from `https://download.londonstrategicedge.com/v3`: eleven markets, over 76,000 instruments and 67 million US options contracts, resumable CSV and Parquet exports checked by SHA-256, macro and reference data, options chains and flow. The websocket, the key and the package are the same. [docs/api.md](https://github.com/londonstrategicedge/lse-data/blob/main/docs/api.md) describes every call.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lse-data
|
|
3
|
-
Version: 3.0
|
|
4
|
-
Summary: Python client for London Strategic Edge market data: live streaming, LSE Data 3.0 history as CSV and Parquet with
|
|
3
|
+
Version: 3.0.1
|
|
4
|
+
Summary: Python client for London Strategic Edge market data: live streaming, LSE Data 3.0 history as CSV and Parquet with checksum-verified downloads, macro and reference data, options chains and flow
|
|
5
5
|
Project-URL: Homepage, https://londonstrategicedge.com
|
|
6
6
|
Project-URL: Documentation, https://github.com/londonstrategicedge/lse-data/blob/main/docs/api.md
|
|
7
7
|
Project-URL: Repository, https://github.com/londonstrategicedge/lse-data
|
|
@@ -85,7 +85,7 @@ latest = client.candles("BTCUSDT", "1d", limit=30, order="desc")
|
|
|
85
85
|
|
|
86
86
|
# The last ten rows of anything, and what an export would weigh, before you ask for it
|
|
87
87
|
peek = client.preview("us_stocks", "AAPL", "5m")
|
|
88
|
-
size = client.estimate("us_stocks", "AAPL", "1m", "
|
|
88
|
+
size = client.estimate("us_stocks", "AAPL", "1m", "2021-10-21", "2026-10-21", format="parquet")
|
|
89
89
|
|
|
90
90
|
# Macro series and yields: (date, value) rows, any series in one call
|
|
91
91
|
cpi = client.series("US.core_inflation_rate", start="2020-01-01")
|
|
@@ -117,19 +117,23 @@ Rows are held in memory, so keep them to days or weeks. Years of candles, ticks
|
|
|
117
117
|
|
|
118
118
|
## Files: CSV and Parquet
|
|
119
119
|
|
|
120
|
-
`export()` saves a selection as a file and returns its path.
|
|
120
|
+
`export()` saves a selection as a file and returns its path. Every export is sent whole with its size and SHA-256 and verified when it finishes; a download that drops is requested again from the start. The free plan includes 50 GB a month.
|
|
121
121
|
|
|
122
122
|
```python
|
|
123
|
-
path = client.export("us_stocks", "AAPL", "1m", "
|
|
123
|
+
path = client.export("us_stocks", "AAPL", "1m", "2021-10-21", "2026-10-21", format="parquet") # five years of one-minute candles
|
|
124
124
|
path = client.export("us_stocks", "AAPL", "tick", "2026-10-21", "2026-10-21", format="csv") # the trade slice
|
|
125
|
-
path = client.export("nasdaq", "NVDA", "tick", "2026-10-14", "2026-10-14", data="book")
|
|
126
|
-
path = client.export("cme", "ESZ6", "tick", "2026-10-13", "2026-10-13", data="orders")
|
|
125
|
+
path = client.export("nasdaq", "NVDA", "tick", "2026-10-14 14:30:00", "2026-10-14 14:31:00", data="book") # the Level 2 book, a minute of it
|
|
126
|
+
path = client.export("cme", "ESZ6", "tick", "2026-10-13 14:30:00", "2026-10-13 14:31:00", data="orders") # Level 3 orders, a minute of them
|
|
127
127
|
path = client.macro_export("observation", "US.core_inflation_rate", "1957-02-01", "2026-07-01", format="csv")
|
|
128
128
|
path = client.reference_export("company_profiles", "AAPL", format="csv")
|
|
129
129
|
|
|
130
130
|
df = client.history("AAPL", timeframe="1d", start="2020-01-01", end="2026-10-01") # a DataFrame with the frames extra
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
+
One export reads at most 2,500,000 rows, on every plan; a wider one is refused with `413 export-too-wide`, which says how many rows it would have read. Five years of AAPL's one-minute candles are about 1.25 million rows. The book and the orders of a busy instrument run to millions of rows a day, so ask for them by time: two UTC timestamps, an hour or less at a time. `estimate()` with the same arguments says how many rows a selection holds before you download it.
|
|
134
|
+
|
|
135
|
+
The free plan also reads at most 12,500,000 rows a day (`429 rows-exhausted` until 00:00 UTC) and 12.5 GiB a week (`429 allowance-exhausted` until Monday 00:00 UTC), at 50 Mbit/s. A paid plan has neither limit and downloads at 250 Mbit/s. Every plan has one download open at a time; one more answers `429 connections-exhausted` and names the file to wait for. `client.usage()` shows your figures and what is used.
|
|
136
|
+
|
|
133
137
|
`pip install 'lse-data[frames]'` adds DataFrames to `history()`, `dataset()` and `load(path)`.
|
|
134
138
|
|
|
135
139
|
CME Globex and Nasdaq TotalView are paid feeds. Their rows need the feed's plan, and a free key gets an error naming the plan. Tick counts, dates, table sizes and estimates are open to every key.
|
|
@@ -140,13 +144,13 @@ The whole US options tape, every contract, with implied volatility and the Greek
|
|
|
140
144
|
|
|
141
145
|
```python
|
|
142
146
|
chain = client.options("apple", type="call", max_dte=30)
|
|
143
|
-
prints = client.options_flow("NVDA", min_premium=100_000)
|
|
144
|
-
sweep = client.options_flow(min_premium=250_000, limit=200)
|
|
147
|
+
prints = client.options_flow("NVDA", min_premium=100_000, start="2026-11-09", end="2026-11-09")
|
|
148
|
+
sweep = client.options_flow(min_premium=250_000, start="2026-11-09", end="2026-11-09", limit=200)
|
|
145
149
|
bars = client.option_candles("AAPL", strike=100, expiry="2026-11-20", type="call")
|
|
146
150
|
names = client.options_underlyings()
|
|
147
151
|
```
|
|
148
152
|
|
|
149
|
-
`options()` returns the chain, one row per contract with the last trade, volume, premium, implied volatility and Greeks. `options_flow()` returns prints with their premium and venue; leave out the underlying to scan every name.
|
|
153
|
+
`options()` returns the chain, one row per contract with the last trade, volume, premium, implied volatility and Greeks. `options_flow()` returns prints with their premium and venue; leave out the underlying to scan every name. `start` and `end` set the window, up to seven days without an underlying; without them it is today (UTC), and a session's prints are stored after it ends, so name the days you want. `option_candles()` returns candles for one contract. `subscribe_options(["AAPL"])` streams every AAPL contract live as `OptionTick` objects, which add `underlying`, `right`, `strike`, `expiry`, `dte`, `premium` and `notional` to a tick. With `from lse import tape`, `client.on("tick", tape())` prints them as a readable table.
|
|
150
154
|
|
|
151
155
|
## Find instruments
|
|
152
156
|
|
|
@@ -180,7 +184,9 @@ client.on("tick", lambda t: print(t.symbol, t.price))
|
|
|
180
184
|
client.connect(["BTC/USD"])
|
|
181
185
|
```
|
|
182
186
|
|
|
183
|
-
Events are `tick`, `connected`, `authenticated`, `disconnected
|
|
187
|
+
Events are `tick`, `connected`, `authenticated`, `disconnected` and `error`.
|
|
188
|
+
|
|
189
|
+
Crypto streams from `wss://london-ws.londonstrategicedge.com`; the default socket carries the other symbols of these examples. The client opens the crypto socket beside the default one, with the same key, for the crypto symbols you ask for, so one loop or callback carries both; a plan's connections are counted on each socket. If the crypto socket refuses the key, the `error` event says so with that address and the other symbols keep streaming. `LSE(api_key, url=...)` uses the one socket you name and nothing else; the [WebSocket documentation](https://londonstrategicedge.com/websocket-documentation) lists the sockets and what each carries.
|
|
184
190
|
|
|
185
191
|
Change subscriptions while connected:
|
|
186
192
|
|
|
@@ -190,17 +196,7 @@ client.unsubscribe(["BTC/USD"])
|
|
|
190
196
|
client.subscribe_options(["AAPL"]) # every AAPL contract at once
|
|
191
197
|
```
|
|
192
198
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
Pass `start` to replay up to 24 hours of history before the live ticks, on the same connection.
|
|
196
|
-
|
|
197
|
-
```python
|
|
198
|
-
from datetime import datetime, timedelta, timezone
|
|
199
|
-
|
|
200
|
-
start = (datetime.now(timezone.utc) - timedelta(hours=1)).strftime("%Y-%m-%dT%H:%M:%S") # UTC
|
|
201
|
-
for tick in client.stream(["BTC/USD"], start=start):
|
|
202
|
-
print("replay" if tick.replay else "live", tick.symbol, tick.price)
|
|
203
|
-
```
|
|
199
|
+
The sockets carry live ticks only. Replay, `stream(..., start=...)`, was removed on 25 October 2026: the server refuses it and the client raises that refusal as `LSEError` (code `REPLAY_REMOVED`). For history use `candles()`, `rows()` or `export()`.
|
|
204
200
|
|
|
205
201
|
### Async
|
|
206
202
|
|
|
@@ -236,7 +232,7 @@ with LSE() as client:
|
|
|
236
232
|
...
|
|
237
233
|
```
|
|
238
234
|
|
|
239
|
-
A tick has `symbol`, `price`, `bid`, `ask`, `volume`, `timestamp` (ISO 8601)
|
|
235
|
+
A tick has `symbol`, `price`, `bid`, `ask`, `volume`, `timestamp` (ISO 8601) and `name`; `tick.datetime` is the parsed timestamp.
|
|
240
236
|
|
|
241
237
|
## Settings
|
|
242
238
|
|
|
@@ -247,9 +243,9 @@ Every setting of `LSE()` is optional:
|
|
|
247
243
|
| `timeout` | `60` | seconds to wait for each HTTP call |
|
|
248
244
|
| `retries` | `3` | retries of a call that got no answer, or a 429, 500, 502, 503 or 504 |
|
|
249
245
|
| `poll_seconds` | `0.5` | how often a prepared export is polled |
|
|
250
|
-
| `wait_for_limit` | `True` |
|
|
246
|
+
| `wait_for_limit` | `True` | on a `429`, wait the server's `Retry-After` once in a call, when it is two minutes or less, and ask again without using up a retry; `False` never waits |
|
|
251
247
|
| `data_url` | `https://download.londonstrategicedge.com` | the LSE Data 3.0 server |
|
|
252
|
-
| `url` | `wss://data-ws.londonstrategicedge.com` | the live WebSocket |
|
|
248
|
+
| `url` | `wss://data-ws.londonstrategicedge.com` | the live WebSocket; left at its default, crypto symbols are streamed from `wss://london-ws.londonstrategicedge.com` beside it |
|
|
253
249
|
|
|
254
250
|
```python
|
|
255
251
|
client = LSE(api_key="your_key", timeout=120, wait_for_limit=False)
|
|
@@ -272,6 +268,7 @@ Scripts written for 0.14 keep working: the method names and row shapes are the s
|
|
|
272
268
|
- Symbols follow the catalogue. The 0.x spellings still resolve: `EUR/USD` to `EUR_USD`, `BTC/USD` to `BTCUSDT` (crypto is quoted in Tether).
|
|
273
269
|
- `series()` takes catalogue codes (`US10Y`, `US.core_inflation_rate`). `cpi_yoy` and `fdtr` still work, as `US.inflation_rate` and `US.interest_rate`. A name matching several series raises `LSEError` with code `series-ambiguous` and lists them.
|
|
274
270
|
- `get()` read the retired tables. It now raises `LSEError` (410, `removed`) naming the methods to use.
|
|
271
|
+
- `stream(..., start=...)` replayed recent ticks before the live ones. Replay was removed on 25 October 2026; the call raises `LSEError` (410, `REPLAY_REMOVED`).
|
|
275
272
|
|
|
276
273
|
[CHANGELOG.md](https://github.com/londonstrategicedge/lse-data/blob/main/CHANGELOG.md) lists every change and [docs/api.md](https://github.com/londonstrategicedge/lse-data/blob/main/docs/api.md) every call.
|
|
277
274
|
|
|
@@ -53,7 +53,7 @@ latest = client.candles("BTCUSDT", "1d", limit=30, order="desc")
|
|
|
53
53
|
|
|
54
54
|
# The last ten rows of anything, and what an export would weigh, before you ask for it
|
|
55
55
|
peek = client.preview("us_stocks", "AAPL", "5m")
|
|
56
|
-
size = client.estimate("us_stocks", "AAPL", "1m", "
|
|
56
|
+
size = client.estimate("us_stocks", "AAPL", "1m", "2021-10-21", "2026-10-21", format="parquet")
|
|
57
57
|
|
|
58
58
|
# Macro series and yields: (date, value) rows, any series in one call
|
|
59
59
|
cpi = client.series("US.core_inflation_rate", start="2020-01-01")
|
|
@@ -85,19 +85,23 @@ Rows are held in memory, so keep them to days or weeks. Years of candles, ticks
|
|
|
85
85
|
|
|
86
86
|
## Files: CSV and Parquet
|
|
87
87
|
|
|
88
|
-
`export()` saves a selection as a file and returns its path.
|
|
88
|
+
`export()` saves a selection as a file and returns its path. Every export is sent whole with its size and SHA-256 and verified when it finishes; a download that drops is requested again from the start. The free plan includes 50 GB a month.
|
|
89
89
|
|
|
90
90
|
```python
|
|
91
|
-
path = client.export("us_stocks", "AAPL", "1m", "
|
|
91
|
+
path = client.export("us_stocks", "AAPL", "1m", "2021-10-21", "2026-10-21", format="parquet") # five years of one-minute candles
|
|
92
92
|
path = client.export("us_stocks", "AAPL", "tick", "2026-10-21", "2026-10-21", format="csv") # the trade slice
|
|
93
|
-
path = client.export("nasdaq", "NVDA", "tick", "2026-10-14", "2026-10-14", data="book")
|
|
94
|
-
path = client.export("cme", "ESZ6", "tick", "2026-10-13", "2026-10-13", data="orders")
|
|
93
|
+
path = client.export("nasdaq", "NVDA", "tick", "2026-10-14 14:30:00", "2026-10-14 14:31:00", data="book") # the Level 2 book, a minute of it
|
|
94
|
+
path = client.export("cme", "ESZ6", "tick", "2026-10-13 14:30:00", "2026-10-13 14:31:00", data="orders") # Level 3 orders, a minute of them
|
|
95
95
|
path = client.macro_export("observation", "US.core_inflation_rate", "1957-02-01", "2026-07-01", format="csv")
|
|
96
96
|
path = client.reference_export("company_profiles", "AAPL", format="csv")
|
|
97
97
|
|
|
98
98
|
df = client.history("AAPL", timeframe="1d", start="2020-01-01", end="2026-10-01") # a DataFrame with the frames extra
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
+
One export reads at most 2,500,000 rows, on every plan; a wider one is refused with `413 export-too-wide`, which says how many rows it would have read. Five years of AAPL's one-minute candles are about 1.25 million rows. The book and the orders of a busy instrument run to millions of rows a day, so ask for them by time: two UTC timestamps, an hour or less at a time. `estimate()` with the same arguments says how many rows a selection holds before you download it.
|
|
102
|
+
|
|
103
|
+
The free plan also reads at most 12,500,000 rows a day (`429 rows-exhausted` until 00:00 UTC) and 12.5 GiB a week (`429 allowance-exhausted` until Monday 00:00 UTC), at 50 Mbit/s. A paid plan has neither limit and downloads at 250 Mbit/s. Every plan has one download open at a time; one more answers `429 connections-exhausted` and names the file to wait for. `client.usage()` shows your figures and what is used.
|
|
104
|
+
|
|
101
105
|
`pip install 'lse-data[frames]'` adds DataFrames to `history()`, `dataset()` and `load(path)`.
|
|
102
106
|
|
|
103
107
|
CME Globex and Nasdaq TotalView are paid feeds. Their rows need the feed's plan, and a free key gets an error naming the plan. Tick counts, dates, table sizes and estimates are open to every key.
|
|
@@ -108,13 +112,13 @@ The whole US options tape, every contract, with implied volatility and the Greek
|
|
|
108
112
|
|
|
109
113
|
```python
|
|
110
114
|
chain = client.options("apple", type="call", max_dte=30)
|
|
111
|
-
prints = client.options_flow("NVDA", min_premium=100_000)
|
|
112
|
-
sweep = client.options_flow(min_premium=250_000, limit=200)
|
|
115
|
+
prints = client.options_flow("NVDA", min_premium=100_000, start="2026-11-09", end="2026-11-09")
|
|
116
|
+
sweep = client.options_flow(min_premium=250_000, start="2026-11-09", end="2026-11-09", limit=200)
|
|
113
117
|
bars = client.option_candles("AAPL", strike=100, expiry="2026-11-20", type="call")
|
|
114
118
|
names = client.options_underlyings()
|
|
115
119
|
```
|
|
116
120
|
|
|
117
|
-
`options()` returns the chain, one row per contract with the last trade, volume, premium, implied volatility and Greeks. `options_flow()` returns prints with their premium and venue; leave out the underlying to scan every name.
|
|
121
|
+
`options()` returns the chain, one row per contract with the last trade, volume, premium, implied volatility and Greeks. `options_flow()` returns prints with their premium and venue; leave out the underlying to scan every name. `start` and `end` set the window, up to seven days without an underlying; without them it is today (UTC), and a session's prints are stored after it ends, so name the days you want. `option_candles()` returns candles for one contract. `subscribe_options(["AAPL"])` streams every AAPL contract live as `OptionTick` objects, which add `underlying`, `right`, `strike`, `expiry`, `dte`, `premium` and `notional` to a tick. With `from lse import tape`, `client.on("tick", tape())` prints them as a readable table.
|
|
118
122
|
|
|
119
123
|
## Find instruments
|
|
120
124
|
|
|
@@ -148,7 +152,9 @@ client.on("tick", lambda t: print(t.symbol, t.price))
|
|
|
148
152
|
client.connect(["BTC/USD"])
|
|
149
153
|
```
|
|
150
154
|
|
|
151
|
-
Events are `tick`, `connected`, `authenticated`, `disconnected
|
|
155
|
+
Events are `tick`, `connected`, `authenticated`, `disconnected` and `error`.
|
|
156
|
+
|
|
157
|
+
Crypto streams from `wss://london-ws.londonstrategicedge.com`; the default socket carries the other symbols of these examples. The client opens the crypto socket beside the default one, with the same key, for the crypto symbols you ask for, so one loop or callback carries both; a plan's connections are counted on each socket. If the crypto socket refuses the key, the `error` event says so with that address and the other symbols keep streaming. `LSE(api_key, url=...)` uses the one socket you name and nothing else; the [WebSocket documentation](https://londonstrategicedge.com/websocket-documentation) lists the sockets and what each carries.
|
|
152
158
|
|
|
153
159
|
Change subscriptions while connected:
|
|
154
160
|
|
|
@@ -158,17 +164,7 @@ client.unsubscribe(["BTC/USD"])
|
|
|
158
164
|
client.subscribe_options(["AAPL"]) # every AAPL contract at once
|
|
159
165
|
```
|
|
160
166
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
Pass `start` to replay up to 24 hours of history before the live ticks, on the same connection.
|
|
164
|
-
|
|
165
|
-
```python
|
|
166
|
-
from datetime import datetime, timedelta, timezone
|
|
167
|
-
|
|
168
|
-
start = (datetime.now(timezone.utc) - timedelta(hours=1)).strftime("%Y-%m-%dT%H:%M:%S") # UTC
|
|
169
|
-
for tick in client.stream(["BTC/USD"], start=start):
|
|
170
|
-
print("replay" if tick.replay else "live", tick.symbol, tick.price)
|
|
171
|
-
```
|
|
167
|
+
The sockets carry live ticks only. Replay, `stream(..., start=...)`, was removed on 25 October 2026: the server refuses it and the client raises that refusal as `LSEError` (code `REPLAY_REMOVED`). For history use `candles()`, `rows()` or `export()`.
|
|
172
168
|
|
|
173
169
|
### Async
|
|
174
170
|
|
|
@@ -204,7 +200,7 @@ with LSE() as client:
|
|
|
204
200
|
...
|
|
205
201
|
```
|
|
206
202
|
|
|
207
|
-
A tick has `symbol`, `price`, `bid`, `ask`, `volume`, `timestamp` (ISO 8601)
|
|
203
|
+
A tick has `symbol`, `price`, `bid`, `ask`, `volume`, `timestamp` (ISO 8601) and `name`; `tick.datetime` is the parsed timestamp.
|
|
208
204
|
|
|
209
205
|
## Settings
|
|
210
206
|
|
|
@@ -215,9 +211,9 @@ Every setting of `LSE()` is optional:
|
|
|
215
211
|
| `timeout` | `60` | seconds to wait for each HTTP call |
|
|
216
212
|
| `retries` | `3` | retries of a call that got no answer, or a 429, 500, 502, 503 or 504 |
|
|
217
213
|
| `poll_seconds` | `0.5` | how often a prepared export is polled |
|
|
218
|
-
| `wait_for_limit` | `True` |
|
|
214
|
+
| `wait_for_limit` | `True` | on a `429`, wait the server's `Retry-After` once in a call, when it is two minutes or less, and ask again without using up a retry; `False` never waits |
|
|
219
215
|
| `data_url` | `https://download.londonstrategicedge.com` | the LSE Data 3.0 server |
|
|
220
|
-
| `url` | `wss://data-ws.londonstrategicedge.com` | the live WebSocket |
|
|
216
|
+
| `url` | `wss://data-ws.londonstrategicedge.com` | the live WebSocket; left at its default, crypto symbols are streamed from `wss://london-ws.londonstrategicedge.com` beside it |
|
|
221
217
|
|
|
222
218
|
```python
|
|
223
219
|
client = LSE(api_key="your_key", timeout=120, wait_for_limit=False)
|
|
@@ -240,6 +236,7 @@ Scripts written for 0.14 keep working: the method names and row shapes are the s
|
|
|
240
236
|
- Symbols follow the catalogue. The 0.x spellings still resolve: `EUR/USD` to `EUR_USD`, `BTC/USD` to `BTCUSDT` (crypto is quoted in Tether).
|
|
241
237
|
- `series()` takes catalogue codes (`US10Y`, `US.core_inflation_rate`). `cpi_yoy` and `fdtr` still work, as `US.inflation_rate` and `US.interest_rate`. A name matching several series raises `LSEError` with code `series-ambiguous` and lists them.
|
|
242
238
|
- `get()` read the retired tables. It now raises `LSEError` (410, `removed`) naming the methods to use.
|
|
239
|
+
- `stream(..., start=...)` replayed recent ticks before the live ones. Replay was removed on 25 October 2026; the call raises `LSEError` (410, `REPLAY_REMOVED`).
|
|
243
240
|
|
|
244
241
|
[CHANGELOG.md](https://github.com/londonstrategicedge/lse-data/blob/main/CHANGELOG.md) lists every change and [docs/api.md](https://github.com/londonstrategicedge/lse-data/blob/main/docs/api.md) every call.
|
|
245
242
|
|
|
@@ -69,22 +69,45 @@ and its HTTP status says the kind: 400 the request is wrong, 401 the key, 403 th
|
|
|
69
69
|
The refusal codes are listed at the end. Browsers may call the server only from LSE's own website, so call it from
|
|
70
70
|
your own code, not from a web page on another site.
|
|
71
71
|
|
|
72
|
-
**Files.** An export answers
|
|
73
|
-
`x-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
72
|
+
**Files.** An export answers the bytes at once: `200` with `Content-Disposition` naming the file, `Content-Length`,
|
|
73
|
+
`x-checksum-sha256` (the file's SHA-256), `x-export-id` (the server's name for this export in its log), `x-export-rows`
|
|
74
|
+
(the rows it charged) and `x-lse3-adjusted` 1 or 0. The file is built whole before the first byte goes out, so the
|
|
75
|
+
size and checksum are exact, and nothing is kept once it has been sent (since 2026-11-06; before it a large or slow
|
|
76
|
+
export became a prepared job kept 24 hours). `prepare=1` is accepted and ignored. `/v3/jobs/<id>` and
|
|
77
|
+
`/v3/jobs/<id>/file`, the prepared-file routes of before, answer `404 export-unknown`: a download that was cut is
|
|
78
|
+
requested again from the start. A selection with no stored rows answers `404 data-unavailable` instead of an empty
|
|
79
|
+
file; its message begins "No stored data for this selection" and says why. Parquet files type `size` as double,
|
|
80
|
+
because split-adjusted volumes can be fractional.
|
|
80
81
|
|
|
81
82
|
**One download at a time.** A key has one download open at a time, on every plan. While an export of this key is
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
being built or sent, one more `/v3/export`, `/v3/dataset/export`, macro or reference export answers
|
|
84
|
+
`429 connections-exhausted` (`429 exports-busy` while the first is still building), with the message "One download at a
|
|
85
|
+
time. <file> is still coming." naming the file to wait for, and `Retry-After: 5`; the same request once the first is
|
|
86
|
+
done goes through. The bytes are paced per key: 50 Mbit/s on the free plan, 250 Mbit/s on a paid plan.
|
|
87
|
+
`GET /v3/usage` shows the pair as `rate_mbit` and `connections`, and `open` says whether a download is running now.
|
|
88
|
+
|
|
89
|
+
**Rows an export and rows a day.** Every export is measured in rows before it is built, and the plan sets two
|
|
90
|
+
figures, which `GET /v3/usage` reports under `rows`:
|
|
91
|
+
|
|
92
|
+
| Plan | Rows one export may read | Rows a day |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| Free | 2,500,000 | 12,500,000, reset at 00:00 UTC |
|
|
95
|
+
| Paid tiers | 2,500,000 | no daily limit |
|
|
96
|
+
|
|
97
|
+
An export past the first answers `413 export-too-wide` before anything is built, with both figures in the sentence;
|
|
98
|
+
so does one the server could not measure within 10 seconds. Past the rows a day it answers `429 rows-exhausted`, with
|
|
99
|
+
`Retry-After` and `retry_after` giving the seconds to 00:00 UTC. Nothing is charged for a selection with no rows or
|
|
100
|
+
for a refused export. Ask for a long history in pieces: `/v3/estimate` says how many rows a selection holds.
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
GET /v3/export?market=us_stocks&symbol=AAPL&timeframe=1m&from=2003-01-01&to=2026-10-24&format=csv
|
|
104
|
+
413 {"code": "export-too-wide", "message": "This export would read 4,132,206 rows; your plan allows at most 2,500,000 rows an export. Choose shorter dates."}
|
|
105
|
+
|
|
106
|
+
429 {"code": "rows-exhausted", "message": "Your plan allows 12,500,000 rows a day; 11,900,000 are used and this export would read 6,743. It resets at 00:00 UTC, in 5 h 12 min.", "retry_after": 18720}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The free plan also has a weekly allowance of 12.5 GiB, counted on the bytes of its exports; past it every export
|
|
110
|
+
answers `429 allowance-exhausted` until Monday 00:00 UTC. A paid plan has none.
|
|
88
111
|
|
|
89
112
|
**What an answer says about you.** No answer carries an email, a user id or a person's name. The one thing a caller
|
|
90
113
|
learns about itself is in `/v3/usage`: the key's own name as it was typed on the Data page, its plan and its product.
|
|
@@ -110,17 +133,22 @@ GET /v3/health
|
|
|
110
133
|
What this key may do and has used. No parameters. Answers `key` (the key's name as it was typed on the Data page),
|
|
111
134
|
`plan`, `product`, `markets` (the enabled markets the key opens), `rate_mbit`, `connections` (downloads at once),
|
|
112
135
|
`open` (downloads running now), `bytes_since_start`, `calls_per_minute`, `levels` and `history` per paid market (`l1`,
|
|
113
|
-
`l2`, `l3` months, -1 the whole archive, and the tier's label), `
|
|
114
|
-
`
|
|
136
|
+
`l2`, `l3` months, -1 the whole archive, and the tier's label), `rows` (`per_export`; `per_day`, -1 for a paid plan;
|
|
137
|
+
`used_today`; `day`; `resets_in_seconds`), `weekly` (`allowance_bytes`, -1 for a paid plan; `used_bytes`; `week` as
|
|
138
|
+
`2026-W46`) and `withheld` (null, or the sentence that explains why every download is refused).
|
|
115
139
|
|
|
116
140
|
```text
|
|
117
141
|
GET /v3/usage (a free key)
|
|
118
142
|
{"key": "Default", "plan": "free", "product": "global",
|
|
119
143
|
"markets": ["us_stocks", "uk_stocks", "ca_stocks", "forex", "crypto", "futures", "indices", "commodities", "us_options"],
|
|
120
|
-
"rate_mbit": 50.0, "connections": 1, "open": 0, "bytes_since_start":
|
|
121
|
-
"
|
|
144
|
+
"rate_mbit": 50.0, "connections": 1, "open": 0, "bytes_since_start": 29818, "calls_per_minute": 60, "levels": {}, "history": {},
|
|
145
|
+
"rows": {"day": "2026-11-11", "per_day": 12500000, "per_export": 2500000, "resets_in_seconds": 61553, "used_today": 996029},
|
|
146
|
+
"weekly": {"allowance_bytes": 13421772800, "used_bytes": 14457484, "week": "2026-W46"}, "withheld": null}
|
|
122
147
|
```
|
|
123
148
|
|
|
149
|
+
A key of a paid tier reads `"rate_mbit": 250.0`, `"rows": {"per_day": -1, "per_export": 2500000, ...}` and
|
|
150
|
+
`"weekly": {"allowance_bytes": -1, ...}`.
|
|
151
|
+
|
|
124
152
|
A key whose subscription ended reads `"plan": "cme:ended", "markets": [], "withheld": "your CME Group subscription has
|
|
125
153
|
ended; renew it to download CME Group data"`.
|
|
126
154
|
|
|
@@ -428,7 +456,7 @@ Trades, quotes, orders and book exist on the paid feeds only; on the included ma
|
|
|
428
456
|
`400 data-unavailable` ("This market offers timeframes, including tick"). Forex and commodities are priced from quotes,
|
|
429
457
|
not trades, so they have candles but no trade slice: `tick` on them answers `404 data-unavailable`. Candles are `time, open, high, low, close, volume, trades`; a daily, weekly or
|
|
430
458
|
monthly candle's `time` is the start of its first minute with a trade, in UTC (AAPL's 1 October 2026 candle reads
|
|
431
|
-
`2026-10-01 04:02:00`). Trades are `time, price, size, kind`; quotes `time, bid_price, ask_price, bid_size, ask_size`;
|
|
459
|
+
`2026-10-01 04:02:00`), and it carries one more column, `date`: the session's date, or the first day of its week or month. Trades are `time, price, size, kind`; quotes `time, bid_price, ask_price, bid_size, ask_size`;
|
|
432
460
|
orders `time, action, side, order_id, price, size`. The book is 67 columns: `time`, `sequence`, `action`, `side`, `price`, `size`, `depth`, then
|
|
433
461
|
ten bid and ten ask levels of price, size and orders. Greeks are one row per traded minute with `price_at`, `iv`,
|
|
434
462
|
`delta`, `gamma`, `theta`, `vega`, `option_price`, `price_source`, `underlying_price`, `years_to_expiry`, `rate` and
|
|
@@ -450,9 +478,10 @@ GET /v3/preview?market=us_stocks&symbol=AAPL&timeframe=5m&data=candles
|
|
|
450
478
|
|
|
451
479
|
#### GET /v3/estimate
|
|
452
480
|
|
|
453
|
-
The rows and bytes an export would have. Answers `rows`, `
|
|
454
|
-
little above it), `ceiling_bytes` (the most the file can weigh
|
|
455
|
-
|
|
481
|
+
The rows and bytes an export would have. Answers `rows`, `basis` (what was counted), `estimated_bytes` (the expected
|
|
482
|
+
size of the file, usually a little above it), `ceiling_bytes` (the most the file can weigh), `mode` (`stream` or
|
|
483
|
+
`file`, a field kept from the prepared jobs of before: every export is now sent at once), `filename`, `availability`
|
|
484
|
+
and `message`. `rows` is the figure the rows limits are judged on. Without `from` and `to` it describes the same
|
|
456
485
|
newest-ten-rows window the preview shows, with `latest_latest` in the file name.
|
|
457
486
|
|
|
458
487
|
A selection of a paid market the key may not download (no plan, a level the tier does not sell, dates before the plan's
|
|
@@ -471,67 +500,51 @@ GET /v3/estimate?market=nasdaq&symbol=NVDA&timeframe=tick&data=orders&from=2026-
|
|
|
471
500
|
|
|
472
501
|
```text
|
|
473
502
|
GET /v3/estimate?market=us_stocks&symbol=AAPL&timeframe=5m&from=2026-10-08&to=2026-10-14&format=csv&adjusted=1&data=candles
|
|
474
|
-
{"rows":
|
|
503
|
+
{"rows": 1041, "estimated_bytes": 91336, "ceiling_bytes": 265408, "mode": "stream", "filename": "AAPL_us_stocks_5m_2026-10-08_2026-10-14.csv", "message": null, ...}
|
|
475
504
|
|
|
476
505
|
GET /v3/estimate?market=us_stocks&symbol=AAPL&timeframe=5m&from=2026-10-17&to=2026-10-18 (a weekend)
|
|
477
|
-
{"rows": 0, "estimated_bytes": 0, "ceiling_bytes": 0, "mode": "stream",
|
|
506
|
+
{"rows": 0, "estimated_bytes": 0, "ceiling_bytes": 0, "mode": "stream",
|
|
507
|
+
"message": "No stored data for this selection: no candles of AAPL (pair 2000000040) are stored in the dates asked (no trading then, or dates not loaded).", ...}
|
|
478
508
|
```
|
|
479
509
|
|
|
480
510
|
#### GET /v3/export, and /v3/candles
|
|
481
511
|
|
|
482
|
-
The file. `/v3/candles` is a second name for the same call
|
|
483
|
-
|
|
484
|
-
`x-
|
|
485
|
-
|
|
486
|
-
weekly allowance
|
|
487
|
-
|
|
488
|
-
|
|
512
|
+
The file, by the file rules above. `/v3/candles` is a second name for the same call; `prepare=1` is accepted and
|
|
513
|
+
ignored. The answer (200) carries the bytes with `Content-Disposition`, `Content-Length`, `x-checksum-sha256`,
|
|
514
|
+
`x-export-id`, `x-export-rows` and `x-lse3-adjusted`. A selection with no rows answers `404 data-unavailable`; an
|
|
515
|
+
export past the rows one export may read `413 export-too-wide`; past the free plan's rows a day `429 rows-exhausted`;
|
|
516
|
+
past its weekly allowance `429 allowance-exhausted` with the figures: "Your plan's weekly allowance of 12.5 GiB is
|
|
517
|
+
used up (12.54 GiB this week); it resets Monday 00:00 UTC. A paid plan has no weekly allowance." A daily, weekly or
|
|
518
|
+
monthly candle carries its session's `date` as a last column.
|
|
489
519
|
|
|
490
520
|
```text
|
|
491
521
|
GET /v3/export?market=us_stocks&symbol=AAPL&timeframe=1d&from=2026-10-01&to=2026-10-14&format=csv&adjusted=1&data=candles
|
|
492
|
-
200 content-type: text/csv; charset=utf-8
|
|
522
|
+
200 content-type: text/csv; charset=utf-8 content-length: 851
|
|
493
523
|
content-disposition: attachment; filename="AAPL_us_stocks_1d_2026-10-01_2026-10-14.csv"
|
|
494
|
-
x-
|
|
495
|
-
|
|
496
|
-
"
|
|
497
|
-
"2026-10-
|
|
498
|
-
|
|
524
|
+
x-checksum-sha256: 05e6d3366eb6c948eb4dbc2460cb7b06c256d7992ec667dd0c88e8578055e812
|
|
525
|
+
x-export-id: 81ec941184f44427ade9e06cf33820bf x-export-rows: 10 x-lse3-adjusted: 1
|
|
526
|
+
"time","open","high","low","close","volume","trades","date"
|
|
527
|
+
"2026-10-01 04:02:00",334.18,334.83,325.82,330.79,15666143,265910,"2026-10-01"
|
|
528
|
+
"2026-10-02 04:00:00",331.14,334.54,330.17,333.53,15026716,228816,"2026-10-02"
|
|
529
|
+
... 10 rows, 851 bytes
|
|
499
530
|
|
|
500
|
-
GET /v3/export
|
|
501
|
-
|
|
502
|
-
"expires_at": 1792808165, "category": "market", "status_url": "/v3/jobs/c5bb197f076943f591cba223141d4510", "download_url": "/v3/jobs/c5bb197f076943f591cba223141d4510/file",
|
|
503
|
-
"error": null, "progress": null, "phase": null}
|
|
531
|
+
GET /v3/export?market=us_stocks&symbol=AAPL&timeframe=5m&from=2026-10-17&to=2026-10-18&format=csv (a weekend)
|
|
532
|
+
404 {"code": "data-unavailable", "message": "No stored data for this selection: no candles of AAPL (pair 2000000040) are stored in the dates asked (no trading then, or dates not loaded)."}
|
|
504
533
|
|
|
505
534
|
GET /v3/export?market=us_stocks&symbol=AAA&timeframe=1d&from=2026-10-01&to=2026-10-14
|
|
506
535
|
404 {"code": "data-unavailable", "message": "..."}
|
|
507
536
|
```
|
|
508
537
|
|
|
509
|
-
With `format=parquet` the same selection is a
|
|
538
|
+
With `format=parquet` the same selection is a 4,108-byte Parquet file (`application/vnd.apache.parquet`).
|
|
510
539
|
|
|
511
|
-
#### GET /v3/jobs/{id}
|
|
540
|
+
#### GET /v3/jobs/{id}, and /v3/jobs/{id}/file
|
|
512
541
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
and `phase`. The job must be this key's; the market of a market job must still be in the key's plan.
|
|
542
|
+
The prepared-file routes of before 2026-11-06, when a large export became a job that was polled and then fetched.
|
|
543
|
+
Exports are no longer kept after they are sent, so every id answers the same:
|
|
516
544
|
|
|
517
545
|
```text
|
|
518
546
|
GET /v3/jobs/21a88b355dc84b6982d4da81328764dc
|
|
519
|
-
{"
|
|
520
|
-
"filename": "AAPL_us_stocks_5m_2026-10-08_2026-10-08.csv", "expires_at": 1792808061, "category": "market", ...}
|
|
521
|
-
|
|
522
|
-
GET /v3/jobs/abc, or another key's id 404 {"code": "export-unknown", "message": "Export is not available"}
|
|
523
|
-
```
|
|
524
|
-
|
|
525
|
-
#### GET /v3/jobs/{id}/file
|
|
526
|
-
|
|
527
|
-
The file of a ready job, whole (200) or by `Range` (206), with `Content-Length`, `Accept-Ranges: bytes`, `ETag` (the
|
|
528
|
-
checksum in quotes), `x-checksum-sha256`, and `Content-Range` on a range. `If-Range` with a different ETag gives the
|
|
529
|
-
whole file (200). A range past the end answers 416 with `Content-Range: bytes */<length>` and no body. While the job
|
|
530
|
-
is still building the answer is 202 with the job; a failed build `409 export-failed`.
|
|
531
|
-
|
|
532
|
-
```text
|
|
533
|
-
GET /v3/jobs/d4194e84ef3c4364ad18525e9d802e51/file Range: bytes=0-99
|
|
534
|
-
206 content-range: bytes 0-99/715 etag: "8eaf9f0d83ae7ca3ddd09e272d285fbc893949ea5a04c87aa02b6d0b1d84ffc0" accept-ranges: bytes
|
|
547
|
+
404 {"code": "export-unknown", "message": "Exports are no longer kept after they are sent. Request the export again."}
|
|
535
548
|
```
|
|
536
549
|
|
|
537
550
|
#### Older calls
|
|
@@ -571,7 +584,7 @@ does not answer within 10 s `503 dataset-unavailable`.
|
|
|
571
584
|
GET /v3/dataset/export?market=us_stocks&symbol=AAPL&timeframe=5m&from=2026-10-08&to=2026-10-13&indicators=rsi:14,sma:20
|
|
572
585
|
&companion_market=us_stocks&companion_symbol=MSFT&companion_features=close,return,corr&corr_window=20
|
|
573
586
|
&hour_start=10&hour_end=15&tz=America/New_York&day_of_week=monday,tuesday,wednesday,thursday,friday&format=csv
|
|
574
|
-
200 content-length:
|
|
587
|
+
200 content-length: 28112 x-checksum-sha256: 18e8d02d2d469c31f5fbd88a482a01d090b6547265a66b0aaf95856d1da3ab35
|
|
575
588
|
content-disposition: attachment; filename="AAPL_us_stocks_5m_2026-10-08_2026-10-13_dataset.csv"
|
|
576
589
|
time,open,high,low,close,volume,trades,rsi_14,sma_20,msft_close,msft_return,corr_msft
|
|
577
590
|
2026-10-08 14:00:00,337.27,337.66,337.06,337.325,186128.0,3492,,,531.145,,
|
|
@@ -582,7 +595,7 @@ time,open,high,low,close,volume,trades,rsi_14,sma_20,msft_close,msft_return,corr
|
|
|
582
595
|
|
|
583
596
|
A key of a CME Group or Nasdaq TotalView tier opens its market's candles, `trades` and `quotes` (Level 1, from Lite),
|
|
584
597
|
`book` (Level 2) and `orders` (Level 3) as the tier sells them, within the tier's history months per level, lifts the free plan's weekly allowance
|
|
585
|
-
and paces downloads at
|
|
598
|
+
and its rows a day, and paces downloads at 250 Mbit/s instead of 50; one download at a time and 2,500,000 rows an export hold on every plan. Without the tier, its rows
|
|
586
599
|
answer `403 plan-required` naming the cheapest tier; its figures (counts, dates, sizes and estimates) answer every key. The pricing page shows an
|
|
587
600
|
illustrative sample of each feed's data and schema for anyone. The refusals a paid key meets are
|
|
588
601
|
`403 history-limit` (dates before the window, the body naming `earliest` and the next tier), `403 level-required` (a
|
|
@@ -655,7 +668,7 @@ named in the text above (`required_plan`, `plan`, `level`, `levels`, `earliest`,
|
|
|
655
668
|
| 400 | `underlying-required` | contract filters on a sweep |
|
|
656
669
|
| 400 | `window-bad` | to not after from |
|
|
657
670
|
| 400 | `window-too-wide` | a sweep over more than 7 days |
|
|
658
|
-
| 400, 404 | `data-unavailable` | 400: trades, quotes, orders or book on an included market, or greeks outside us_options; 404: tick on a quotes-only market, a pair with no data yet, or a selection with no stored rows |
|
|
671
|
+
| 400, 404 | `data-unavailable` | 400: trades, quotes, orders or book on an included market, or greeks outside us_options; 404: tick on a quotes-only market, a pair with no data yet, or a selection with no stored rows (the message begins "No stored data for this selection" and says why) |
|
|
659
672
|
| 401 | `key-missing` | no key in X-API-Key or ?key= |
|
|
660
673
|
| 401 | `key-unknown` | a key the server does not know |
|
|
661
674
|
| 403 | `account-required` | a key that belongs to no account |
|
|
@@ -667,7 +680,7 @@ named in the text above (`required_plan`, `plan`, `level`, `levels`, `earliest`,
|
|
|
667
680
|
| 403 | `plan-required` | a preview or an export of a paid market the key's plan does not open (its candles, trades, quotes, orders or book); required_plan names the cheapest tier |
|
|
668
681
|
| 404 | `dataset-unknown` | a dataset id the reference catalogue does not list |
|
|
669
682
|
| 404 | `date-not-trading` | cme or futures with no session in the dates asked |
|
|
670
|
-
| 404 | `export-unknown` |
|
|
683
|
+
| 404 | `export-unknown` | /v3/jobs: exports are no longer kept after they are sent |
|
|
671
684
|
| 404 | `file-unknown` | a kind and feed that name no market |
|
|
672
685
|
| 404 | `level-not-served` | orders or book on a market whose levels do not include L3 or L2 |
|
|
673
686
|
| 404 | `market-not-enabled` | a market switched off or coming soon; the message carries its label |
|
|
@@ -681,14 +694,15 @@ named in the text above (`required_plan`, `plan`, `level`, `levels`, `earliest`,
|
|
|
681
694
|
| 404 | `theme-unknown` | theme not light or dark |
|
|
682
695
|
| 404 | `underlying-unknown` | an underlying the market does not list |
|
|
683
696
|
| 404, 503 | `dataset-unavailable` | 404: a reference dataset not available yet; 503: the dataset builder did not answer |
|
|
684
|
-
|
|
|
685
|
-
| 410 | `export-expired` | past its 24 hours |
|
|
697
|
+
| 502 | `export-failed` | the build failed |
|
|
686
698
|
| 410 | `export-required` | /v3/files and /v3/file, once the key passes the plan checks |
|
|
699
|
+
| 413 | `export-too-wide` | an export past the rows one export may read (2,500,000 on every plan), or one the server could not measure within 10 seconds |
|
|
687
700
|
| 413 | `series-window-too-wide` | more than 100,000 rows |
|
|
688
|
-
| 429 | `allowance-exhausted` | a free key past its weekly bytes |
|
|
701
|
+
| 429 | `allowance-exhausted` | a free key past its weekly bytes (12.5 GiB); it resets Monday 00:00 UTC |
|
|
689
702
|
| 429 | `calls-exhausted` | past the plan's calls a minute; Retry-After says when |
|
|
690
|
-
| 429 | `connections-exhausted` | one more download while this key's one download is still open
|
|
691
|
-
| 429
|
|
703
|
+
| 429 | `connections-exhausted` | one more download while this key's one download is still open; Retry-After 5 |
|
|
704
|
+
| 429 | `rows-exhausted` | past the plan's rows a day (12,500,000 on the free plan); Retry-After and retry_after give the seconds to 00:00 UTC |
|
|
705
|
+
| 429, 503 | `exports-busy` | 429: this key's one download is still building (Retry-After 5); 503: the server's queue of waiting builds is full, or the export could not be measured just now (Retry-After 30) |
|
|
692
706
|
| 502 | `dataset-failed` | the dataset build failed |
|
|
693
707
|
| 502 | `query-invalid` | the data store refused the query as malformed |
|
|
694
708
|
| 502, 503 | `catalogue-invalid` | the catalogue answered badly (502), or could not be loaded (503) |
|
|
@@ -698,7 +712,6 @@ named in the text above (`required_plan`, `plan`, `level`, `levels`, `earliest`,
|
|
|
698
712
|
| 503 | `catalogue-busy` | too many catalogue reads at once |
|
|
699
713
|
| 503 | `catalogue-unavailable` | the catalogue did not answer |
|
|
700
714
|
| 503 | `estimate-unavailable` | the figures for a selection the key may not download could not be read |
|
|
701
|
-
| 503 | `export-unavailable` | the job could not be written or its file not opened |
|
|
702
715
|
| 503 | `overview-unavailable` | the overview figures could not be read |
|
|
703
716
|
| 503 | `query-busy` | too many reads at once |
|
|
704
717
|
| 504 | `macro-timeout` | past 25 seconds |
|
|
@@ -717,7 +730,8 @@ named in the text above (`required_plan`, `plan`, `level`, `levels`, `earliest`,
|
|
|
717
730
|
| `factors(market, symbol)` | `/v3/factors` |
|
|
718
731
|
| `overview(market, symbol)` | `/v3/overview` |
|
|
719
732
|
| `preview()`, `estimate()` | `/v3/preview`, `/v3/estimate` |
|
|
720
|
-
| `export()`, `history()
|
|
733
|
+
| `export()`, `history()` | `/v3/export` |
|
|
734
|
+
| `job()` | `/v3/jobs/{id}`, which no longer keeps anything |
|
|
721
735
|
| `rows()`, `candles()`, `option_candles()` | `/v3/export` as CSV, held in memory |
|
|
722
736
|
| `dataset_export()` | `/v3/dataset/export` |
|
|
723
737
|
| `options_chain()`, `options()` | `/v3/options/chain` |
|
|
@@ -730,8 +744,14 @@ named in the text above (`required_plan`, `plan`, `level`, `levels`, `earliest`,
|
|
|
730
744
|
|
|
731
745
|
`catalog()` covers every market, Nasdaq TotalView included, and lists the two contract markets by underlying.
|
|
732
746
|
|
|
733
|
-
The client keeps the key in the header, follows no redirect,
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
747
|
+
The client keeps the key in the header, follows no redirect, writes a download to a `.part` file beside the
|
|
748
|
+
destination, asks again from the start when a transfer is cut, and checks the SHA-256 before it places the
|
|
749
|
+
destination. A refusal raises `LSEError` with `status`, `code`, `message` and `required_plan`; an export that outlasts
|
|
750
|
+
its `timeout` raises it with code `timeout`. On a `429` that carries a `Retry-After` of two minutes or less
|
|
751
|
+
(`calls-exhausted`, `connections-exhausted`, `exports-busy`) the client waits that long once in a call and asks again,
|
|
752
|
+
unless it was made with `wait_for_limit=False`; a refusal that stands is raised with the server's code and sentence.
|
|
753
|
+
|
|
754
|
+
The same client streams live prices with the same key, `client.stream([...])`: the
|
|
755
|
+
[WebSocket documentation](https://londonstrategicedge.com/websocket-documentation) describes the sockets. Crypto
|
|
756
|
+
streams from `wss://london-ws.londonstrategicedge.com`, which a client on the default address opens beside the default
|
|
757
|
+
socket for the crypto symbols it is asked for.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
"""Pull history as a file: CSV or Parquet,
|
|
1
|
+
"""Pull history as a file: CSV or Parquet, checked by SHA-256.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
The server sends every export whole, with its size and SHA-256. If the
|
|
4
|
+
connection drops the client asks for it again, and the file is placed only
|
|
5
|
+
after its checksum matches what the server states. One export reads at most
|
|
6
|
+
2,500,000 rows; estimate() says how many a selection holds.
|
|
7
7
|
|
|
8
8
|
Usage:
|
|
9
9
|
LSE_API_KEY=lse_live_... python history_file.py
|