Skip to content

Python quickstart

Requirements

  • Python 3.10+

1. Install

pip install lrvx

2. First indicator

import lrvx

ema = lrvx.EMA(20)

prices = [100 + i * 0.1 for i in range(50)]
for price in prices:
    value = ema.update(price)
    if value is not None:
        print(f"EMA(20): {value:.4f}")

All streaming indicators return None during warmup and a float once ready. Check .ready to test without calling update.

3. First strategy

import lrvx

registry = lrvx.SymbolRegistry()
btc = registry.add_symbol("binance", "BTCUSDT", tick_size=0.01)

class SMACross(lrvx.Strategy):
    def __init__(self, symbols):
        super().__init__(symbols)
        self.fast = lrvx.SMA(10)
        self.slow = lrvx.SMA(30)

    def on_trade(self, ctx, trade):
        f = self.fast.update(trade.price)
        s = self.slow.update(trade.price)
        if f is None or s is None:
            return
        if f > s and ctx.is_flat():
            self.market_buy(0.01)
        elif f < s and ctx.is_long():
            self.close_position()

def on_signal(sig):
    print(sig.side, sig.order_type, sig.quantity)

runner = lrvx.Runner(registry, on_signal)
runner.add_strategy(SMACross([btc]))
runner.start()

# Feed market data from your source:
# runner.on_trade(btc, price, qty, is_buy, ts_ns)

runner.stop()

4. Backtest

bt = lrvx.BacktestRunner(registry, fee_rate=0.0004, initial_capital=10_000)
bt.set_strategy(SMACross([btc]))

stats = bt.run_csv("btcusdt_1m.csv", "BTCUSDT")
print(stats["return_pct"], stats["sharpe_ratio"], stats["max_drawdown_pct"])

CSV format: one header line, then OHLCV bars — timestamp,open,high,low,close,volume. Only the timestamp and close columns are read; each row is replayed as a single trade, so on_trade fires. Flat fee rate, no funding, no liquidation, no rate limits, no queue position. Use for an indicator sanity check, not for a decision about real capital.

5. Venue physics

stack = lrvx.VenueStack.binance_um_futures(account_id=42, equity=10_000.0)
acct = stack.account()
liq = stack.liquidation()
fees = stack.fees()
funding = stack.funding()
exec_ = stack.executor()

One call wires the cross-margin Account, the MM tier ladder + ADL ranking, the 30d VIP fee schedule (bound to the account), the funding settlement schedule, the venue-specific rate-limit policy, and the venue-availability hook. Other factories: bybit_linear, okx_swap, deribit. For custom venues see lrvx.assemble_custom_venue(...).

VenueStack is a standalone simulation: you can drive its subsystems directly, as above, or call runner.set_venue_stack(stack) to have BacktestRunner drive it for you and pick up the venue's fill mechanics during run_csv / run_bars. VenueStack itself is never a constructor argument — BacktestRunner takes it through set_venue_stack after construction.

Full pattern: Realistic backtest in one call.


Building from source

Two ways to get here: you need the current main branch before a release is published, or pip install lrvx found no wheel for your platform and interpreter and fell back to the source distribution. Both compile the C++ core on your machine and need the same things.

Requirements

  • GCC 14+ or Clang 18+ (the core is C++23)
  • CMake 3.22+
  • Python 3.10+
  • LZ4 headers and library — liblz4-dev (Debian/Ubuntu), lz4 (Homebrew), lz4-devel (Fedora/RHEL). Without them the build fetches and compiles lz4 itself, which needs git and network access.
git clone https://github.com/lrvx/lrvx.git
cd lrvx
pip install .

pip install . is run from the repository root, not from python/: pyproject.toml lives at the root because the C++ sources the extension links sit there. scikit-build-core handles the cmake build internally, and the module installs into your environment the same way as the PyPI package.

The published source distribution (lrvx-<version>.tar.gz) carries those same sources, so the fallback path works the same way without a clone:

pip install --no-binary lrvx lrvx

Expect minutes, not seconds — this compiles the core library and the binding.


Next steps