Skip to main content

Strict-ordering bar feed for backtests and live strategies. Lookahead-proof by construction.

Project description

lightcone

Strict-ordering bar feed for backtests and live trading strategies. Lookahead-proof by construction.

Only the past light cone influences the present.

tests Python License Zero dependencies


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

  1. Bars are delivered one at a time through a feed.
  2. Each delivery returns an opaque token. The strategy MUST call confirm(token) before requesting the next bar.
  3. Each bar is wrapped in a BarView that exposes only the fields the strategy declared in advance.
  4. 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.extras is auto-frozen via MappingProxyType (external mutation can't leak in)
  • BarView blocks all underscore-prefixed access — no view._bar.high escape hatch
  • FieldNotDeclared does NOT inherit from AttributeError, so hasattr() 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lightcone_feed-0.1.0.tar.gz (22.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lightcone_feed-0.1.0-py3-none-any.whl (22.2 kB view details)

Uploaded Python 3

File details

Details for the file lightcone_feed-0.1.0.tar.gz.

File metadata

  • Download URL: lightcone_feed-0.1.0.tar.gz
  • Upload date:
  • Size: 22.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for lightcone_feed-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3fbde9286345ccbc0206871f4b6abdbb4927b0b57b2026a66cb99e4bebcee634
MD5 9676ac000ce77a3e54f32c0806028a4f
BLAKE2b-256 df40e28ec31a7ed7e8cc5c125424c332f64b54f365493dce8e7b2cfbe8675f38

See more details on using hashes here.

Provenance

The following attestation bundles were made for lightcone_feed-0.1.0.tar.gz:

Publisher: publish.yml on JaggerTheBoss/lightcone-feed

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lightcone_feed-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: lightcone_feed-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 22.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for lightcone_feed-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 81849a8d44b5d39fbb3124cc7dc29c477fd9f2f8f633c7e4316aa46950ad0b12
MD5 4f5d941696dbf8ee33378af7d18f0dd9
BLAKE2b-256 bbb026cd23941b80ed27d69a2e18a8d52b321e62919ee188da79e7caf0cfbd11

See more details on using hashes here.

Provenance

The following attestation bundles were made for lightcone_feed-0.1.0-py3-none-any.whl:

Publisher: publish.yml on JaggerTheBoss/lightcone-feed

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page