lightcone
Strict-ordering bar feed for backtests and live trading strategies. Lookahead-proof by construction.
Only the past light cone influences the present.
Why this exists
Every major Python backtest framework has known lookahead pitfalls. The classic failure mode: each bar's "scene" / "context" object holds references to mutable state. Future bars mutate that state. By the time your trading loop reads bars[10].scene.zone.broken, the value reflects bars 11..N — your trading decision read the future.
Tests can catch known lookahead patterns. They cannot catch the unknown ones.
The structural approach: make it impossible for the strategy to see a bar before it has confirmed processing all earlier bars. Then lookahead bugs are not testable failures — they are architectural impossibilities.
That's lightcone.
How it works
- Bars are delivered one at a time through a feed.
- Each delivery returns an opaque token. The strategy MUST call
confirm(token)before requesting the next bar. - Each bar is wrapped in a BarView that exposes only the fields the strategy declared in advance.
- Backtest and live use the same API. Only the data source changes.
Install
pip install lightcone-feed
Zero dependencies. Python 3.9+.
Quick start
from lightcone import Lightcone, OHLCV, FeedExhausted, from_ohlcv_rows
# Build a feed from Binance/HL-style OHLCV rows
feed = from_ohlcv_rows(
{("BTC", "5m"): btc_rows, ("ETH", "5m"): eth_rows},
config=OHLCV,
)
while True:
try:
bar, key, token = feed.next_bar()
except FeedExhausted:
break
# Your strategy reads only declared fields
if bar.close > bar.open and bar.volume > some_threshold:
decide_long(asset=key, ts=bar.ts)
feed.confirm(token) # ← MUST call before requesting next bar
Try to peek at a field you didn't declare → FieldNotDeclared. Try to skip confirm() and request the next bar → NotConfirmed. Try to confirm with the wrong token → BadToken.
Configuration profiles
from lightcone import CLOSE_ONLY, OHLCV, FULL_TAPE, custom
CLOSE_ONLY # → ts + close. Discretionary / human-trader replay.
OHLCV # → ts + OHLCV. Standard algorithmic backtest.
FULL_TAPE # → OHLCV + n_trades + taker_buy. Microstructure.
cfg = custom("close", "volume", "n_trades")
cfg = custom("close", extras=["funding_rate"])
Multi-asset / multi-timeframe
feed = Lightcone(streams={
("BTC", "5m"): btc_5m,
("BTC", "15m"): btc_15m,
("ETH", "5m"): eth_5m,
})
Bars across all streams come out in strict timestamp order via a min-heap, with deterministic tie-breaking. Same API for one stream or fifty.
Fill simulation (for limit / stop strategies)
from lightcone import Order, Side, OrderType, simulate_fill
fill = simulate_fill(
Order(Side.BUY, qty=1.0, order_type=OrderType.LIMIT, price=97.0),
bar,
slippage_bps=2.0,
)
The fill simulator reads the bar's full OHLC range — that's separate from the strategy's declared-field view, so your decision logic can't peek at high/low while the fill logic still uses them realistically.
Hardening
- Bars are frozen dataclasses; immutable post-construction
Bar.extrasis auto-frozen viaMappingProxyType(external mutation can't leak in)BarViewblocks all underscore-prefixed access — noview._bar.highescape hatchFieldNotDeclareddoes NOT inherit fromAttributeError, sohasattr()cannot silently swallow it- Tokens are 16 random bytes, compared with
secrets.compare_digest - Stream sequences are snapshotted to tuples — caller mutation can't affect the feed
- Strictly ascending timestamps required within each stream
Performance
| Workload | Throughput |
|---|---|
| 1M bars, single stream | ~400k bars/sec |
| 1M bars, 10 streams via heap | ~370k bars/sec |
| Per-bar overhead | ~2.5 microseconds |
| Memory | ~80 bytes / Bar |
The feed will never be your bottleneck. Strategy logic dominates by 10-100x.
What lightcone is NOT
- Not a full backtest framework. It's the data layer. Your strategy code, P&L tracking, and reporting live outside.
- Not thread-safe. Single-threaded use only. If parallelizing, give each thread its own feed.
- Not a training pipeline. Model training is offline batch work that uses the full timeline. Use lightcone for inference (backtest and live).
- Not a sandbox. A determined caller can read the feed's internal state. The contract catches accidents, not adversaries.
Documentation
| Doc | Read it for |
|---|---|
docs/CONTRACT.md |
The seven protocol rules. Read first. |
docs/API.md |
Reference for every public symbol. |
docs/ARCHITECTURE.md |
Why the package is designed the way it is. |
docs/EXAMPLES.md |
Backtest, multi-asset, fill sim, walk-forward recipes. |
docs/LIVE.md |
Wiring lightcone to a live WebSocket data source. |
Testing
pip install -e ".[dev]"
pytest lightcone/tests/
95 tests, ~14s runtime, 100% line coverage on production modules.
License
Apache-2.0. See LICENSE.
Contributing
See CONTRIBUTING.md. lightcone is small and focused — read that first.
Metadata
Release files for lightcone-feed 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| lightcone_feed-0.1.0.tar.gz | 22.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lightcone_feed-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 44.9 kB
Release files / lightcone_feed-0.1.0.tar.gz
| Download URL | lightcone_feed-0.1.0.tar.gz |
|---|---|
| Size | 22.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3fbde9286345ccbc0206871f4b6abdbb4927b0b57b2026a66cb99e4bebcee634
|
|
BLAKE2b-256 checksum How to use checksums |
df40e28ec31a7ed7e8cc5c125424c332f64b54f365493dce8e7b2cfbe8675f38
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 14, 2026.
Transparency logRelease files / lightcone_feed-0.1.0-py3-none-any.whl
| Download URL | lightcone_feed-0.1.0-py3-none-any.whl |
|---|---|
| Size | 22.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
81849a8d44b5d39fbb3124cc7dc29c477fd9f2f8f633c7e4316aa46950ad0b12
|
|
BLAKE2b-256 checksum How to use checksums |
bbb026cd23941b80ed27d69a2e18a8d52b321e62919ee188da79e7caf0cfbd11
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 14, 2026.
Transparency log