Metadata-Version: 2.4
Name: lse-data
Version: 0.6.0
Summary: Python SDK for London Strategic Edge real-time market data
Project-URL: Homepage, https://londonstrategicedge.com
Project-URL: Documentation, https://github.com/londonstrategicedge/lse-data
Project-URL: Repository, https://github.com/londonstrategicedge/lse-data
Project-URL: Issues, https://github.com/londonstrategicedge/lse-data/issues
Author-email: London Strategic Edge <support@londonstrategicedge.com>
License-Expression: MIT
License-File: LICENSE
Keywords: crypto,forex,market-data,options,real-time,stocks,trading,websocket
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial :: Investment
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Requires-Dist: websockets>=11.0
Provides-Extra: pandas
Requires-Dist: pandas>=1.5; extra == 'pandas'
Description-Content-Type: text/markdown

# lse-data

Python SDK for [London Strategic Edge](https://londonstrategicedge.com) real-time market data.

Stream live prices for **4,000+ instruments** including stocks, crypto, forex, indices, commodities, ETFs, and 81,000+ options contracts.

## Install

```bash
pip install lse-data
```

## Command-line (easiest)

After install, save your key once and use the `lse` command anywhere:

```bash
lse auth lse_live_xxxxxxxxxxxx

# Fetch 30 days of gold 1h candles
lse candles XAU/USD --days 30 --timeframe 1h

# Write 5 years of gold 1m to CSV
lse candles XAU/USD --start 2021-01-01 --end 2026-01-01 --timeframe 1m --csv gold_5y.csv

# Stream live ticks
lse stream XAU/USD BTC/USD AAPL

# Browse the symbol catalog
lse catalog --category commodity
```

## Quick start

```python
from lse import LSE

client = LSE(api_key="your_api_key")

for tick in client.stream(["BTC/USD", "AAPL", "EUR/USD"]):
    print(f"{tick.symbol}: ${tick.price}")
```

Get your API key at [londonstrategicedge.com/data](https://londonstrategicedge.com/data).

## Features

- Historical OHLCV candles for 4,000+ instruments (REST, no WebSocket needed)
- Real-time WebSocket streaming with auto-reconnect
- 4,000+ symbols: US/UK/EU/Asia stocks, crypto, forex, indices, commodities, ETFs
- 81,000+ option contracts via `subscribe_options()`
- Symbol catalog API for discovery before subscribing
- Server-side symbol validation (invalid symbols rejected immediately)
- Dynamic subscribe/unsubscribe at runtime
- Graceful disconnect (from callbacks or other threads)
- Sync and async interfaces
- Callback and iterator patterns
- Zero config, just an API key

## Usage

### Historical candles

Fetch OHLCV candles for any instrument. No WebSocket connection needed.

```python
from lse import LSE

client = LSE(api_key="your_key")

# As a list of dicts
result = client.candles("XAU/USD", start="2021-01-01", end="2026-01-01", timeframe="1d")
print(f"{result['rows']} candles, plan: {result['plan']}")
for c in result["data"][-3:]:
    print(f"{c['timestamp']}  close={c['close']}")

# As a pandas DataFrame (pip install lse-data[pandas])
df = client.candles("AAPL", "2025-01-01", "2026-01-01", timeframe="1h", as_dataframe=True)
print(df.tail())
```

**Supported timeframes:** `1m`, `5m`, `15m`, `30m`, `1h`, `2h`, `4h`, `1d`

Works for all 4,000+ instruments: stocks, crypto, forex, ETFs, commodities, indices.

### Stream ticks (simplest)

```python
from lse import LSE

client = LSE(api_key="your_key")

for tick in client.stream(["BTC/USD", "ETH/USD", "AAPL"]):
    print(f"{tick.symbol:12s} ${tick.price:>12,.2f}")
```

### Callback style

```python
from lse import LSE

def on_tick(tick):
    print(f"{tick.symbol}: {tick.price}")

client = LSE(api_key="your_key")
client.on("tick", on_tick)
client.connect(symbols=["BTC/USD", "ETH/USD"])
```

### Async streaming

```python
import asyncio
from lse import LSE

async def main():
    client = LSE(api_key="your_key")
    async for tick in client.stream_async(["BTC/USD"]):
        print(tick)

asyncio.run(main())
```

### Save to CSV

```python
import csv, datetime
from lse import LSE

client = LSE(api_key="your_key")

with open("ticks.csv", "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["time", "symbol", "price", "bid", "ask"])

    for tick in client.stream(["BTC/USD", "ETH/USD"]):
        writer.writerow([
            datetime.datetime.now().isoformat(),
            tick.symbol, tick.price, tick.bid, tick.ask,
        ])
```

## Tick object

Each tick has these fields:

| Field | Type | Description |
|-------|------|-------------|
| `symbol` | `str` | Instrument symbol (e.g. `BTC/USD`, `AAPL`) |
| `price` | `float` | Latest price |
| `bid` | `float` | Bid price (if available) |
| `ask` | `float` | Ask price (if available) |
| `volume` | `float` | Volume (if available) |
| `timestamp` | `float` | Unix timestamp |
| `name` | `str` | Human-readable name (e.g. `Apple Inc.`) |

## Events

When using the callback style with `.on()`:

| Event | Callback args | Description |
|-------|---------------|-------------|
| `tick` | `Tick` | New price tick |
| `connected` | (none) | WebSocket connected |
| `authenticated` | (none) | API key accepted |
| `disconnected` | (none) | Connection lost (will auto-reconnect) |
| `error` | `str` | Error message |

## Symbol catalog

Query available instruments before subscribing. No WebSocket connection needed.

```python
from lse import LSE

client = LSE(api_key="your_key")

# Get all available symbols
all_symbols = client.catalog()
print(f"{len(all_symbols)} instruments available")

# Filter by category: stock, crypto, forex, etf, commodity, index
stocks = client.catalog(category="stock")
crypto = client.catalog(category="crypto")

# Each entry has symbol, display_name, and category
for s in crypto[:5]:
    print(f"{s['symbol']:12s} {s['display_name']:20s} {s['category']}")
```

The catalog returns every subscribable instrument. Use it to build symbol pickers, validate user input, or discover what is available.

### Available categories

| Category | Count | Examples |
|----------|-------|---------|
| stock | ~3,987 | AAPL, NVDA, TSLA, 0005.HK, 7203.T |
| forex | ~62 | EUR/USD, GBP/JPY, USD/CHF |
| crypto | ~58 | BTC/USD, ETH/USD, SOL/USD |
| etf | ~25 | SPY, QQQ, IWM, GLD |
| commodity | ~23 | XAU/USD, WTICO/USD, NATGAS/USD |
| index | ~13 | US30, NAS100, UK100 |

## Options streaming

Subscribe to entire options chains by underlying. One call gives you every contract (calls + puts, all strikes, all expiries).

```python
from lse import LSE

client = LSE(api_key="your_key")

def on_tick(tick):
    print(f"{tick.symbol}: ${tick.price:.2f}")

client.on("tick", on_tick)
client.subscribe_options(["AAPL", "TSLA"])
client.connect()
```

To stop receiving a chain:

```python
client.unsubscribe_options(["TSLA"])
```

## Unsubscribe

Remove symbols at runtime without disconnecting:

```python
client.unsubscribe(["BTC/USD"])      # stop one symbol
client.subscribe(["SOL/USD"])        # add another
```

## Disconnect

Stop the stream and exit cleanly. Works from callbacks or another thread:

```python
tick_count = 0

def on_tick(tick):
    global tick_count
    tick_count += 1
    if tick_count >= 100:
        client.disconnect()  # connect()/stream() returns

client.on("tick", on_tick)
client.connect(symbols=["BTC/USD"])
print("Done, collected 100 ticks")
```

Async version:

```python
await client.disconnect_async()
```

## Requirements

- Python 3.8+
- `websockets` (installed automatically)

## License

MIT
