Skip to main content

Rust-backed Python package for target-weight backtests, portfolio metrics, deterministic order-book simulation, and pre-trade risk checks

Project description

nanobook

nanobook

CI crates.io docs.rs License: MIT cargo-deny

Rust execution layer for Python trading strategies.

nanobook is a small execution kernel for the part of a trading system that is easy to underestimate: state. Your Python code can keep doing research, signals, sizing, and scheduling. nanobook handles the execution mechanics around that strategy: portfolio accounting, transaction costs, stops, deterministic limit-order-book simulation, pre-trade risk checks, and optional IBKR rebalancing.

Use it when you want to ask: "if my strategy emits these target weights, what exactly happens to cash, holdings, risk checks, order-book events, and audit logs?"

Architecture

┌─────────────────────────────────────────────────┐
│        Your Python Strategy  (private)          │
│   Factors · Signals · Sizing · Scheduling       │
├─────────────────────────────────────────────────┤
│            nanobook (Rust, open-source)         │
│  ┌──────────┬──────────┬──────────┬──────────┐  │
│  │  Broker  │   Risk   │Portfolio │   LOB    │  │
│  │   IBKR   │  Engine  │Simulator │  Engine  │  │
│  │  Binance │ PreTrade │ Backtest │ 6M ops/s │  │
│  └──────────┴──────────┴──────────┴──────────┘  │
│   Rebalancer CLI: weights → diff → execute      │
└─────────────────────────────────────────────────┘

What You Can Do

  • Turn a Python target-weight schedule into holdings, returns, equity curve, stop events, and portfolio metrics.
  • Simulate transaction costs, fixed/trailing stops, and deterministic limit-order-book execution.
  • Test order-book behavior with replayable events instead of ad hoc mocks.
  • Run pre-trade risk checks for concentration, leverage, and short exposure.
  • Rebalance an IBKR account from a target-weight file with dry-run, confirmation, reconciliation, and audit logs.

Why It Is Worth a Look

  • The boundary is sharp: Python decides what to trade; Rust accounts for what happened.
  • The core is deterministic: same inputs, same order matching, same portfolio path, same replay.
  • The Python package is a native PyO3 extension, so heavy loops run outside the GIL instead of turning into another slow Python backtester.
  • The test suite is aimed at the failure modes trading code usually hides: edge cases, property tests, reference-parity fixtures, fuzz harnesses, and mutation-testing notes.
  • The scope is intentionally narrow: execution mechanics, not a UI, not a connector zoo, not a full research stack.

v0.10 Hardening

  • Checked arithmetic for trade notional and VWAP; NaN/overflow-safe broker conversions.
  • Fallible risk-engine construction instead of config-time panics.
  • rustls default TLS backend, zeroize-on-drop for Binance credentials, and scrubbed broker logs.
  • Audit logs constrained to the working directory, with 0o600 permissions on Unix.
  • cargo-fuzz harnesses for matching and ITCH, plus an 89.76 % mutation-testing baseline for the matcher.

Competitive Positioning

Project Scope Execution Model Python API Rust Core Auditability Niche
nanobook Execution kernel Deterministic LOB (6M ops/s) PyO3 native extension ✓ Full (LOB, portfolio, risk) High (event sourcing, property tests) Research → production bridge
vectorbt Research framework Vectorized backtesting ✓ Pure Python Medium (open source) Factor research, fast backtests
NautilusTrader Full platform Event-driven, multi-venue ✓ Python bindings ✓ Partial High (audit trails) Institutional quant trading
Hummingbot Bot platform Market making, arbitrage ✓ Pure Python Medium (logging) Crypto market making
Freqtrade Bot platform Technical analysis, backtesting ✓ Pure Python Low Crypto technical trading
LEAN Full platform Event-driven, multi-asset ✓ (C# core, Python API) ✗ (C#) High (institutional) Multi-asset backtesting & live

Strengths:

  • Deterministic execution: same inputs → same outputs (event replay)
  • Performance: LOB matching at 6M ops/sec, outside Python GIL
  • Auditability: event sourcing, property tests, mutation testing
  • Sharp boundary: Python for strategy, Rust for execution

Weaknesses:

  • No GUI: CLI-only, no web dashboard
  • Small community: single maintainer, no plugin ecosystem
  • Limited venue coverage: IBKR + Binance only (extensible via broker trait)
  • No FIX protocol: FIX 4.4/5.0 not planned
  • Not an OMS yet: event-sourced OMS on v1.0 roadmap

nanobook is a compact Rust execution kernel for Python strategies: limit-order-book matching, portfolio simulation, broker abstraction, pre-trade risk, and rebalancer, all in one MIT-licensed workspace.

Python computes what to trade — factor rankings, signals, target weights. nanobook executes how — order routing, risk checks, portfolio simulation, and a deterministic matching engine. Clean separation: strategy logic stays in Python, execution runs in Rust.

Workspace

Crate Description
nanobook Core Rust crate: deterministic LOB, portfolio simulator, metrics, backtest bridge, GARCH, optimizers
nanobook-broker Broker trait with IBKR and Binance adapters
nanobook-risk Pre-trade risk engine (position limits, leverage, short exposure)
nanobook-python PyO3 bindings for all layers
nanobook-rebalancer CLI: target weights → IBKR execution with audit trail

Install

Python:

pip install nanobook

Rust:

[dependencies]
nanobook = "0.10.0"

From source:

git clone https://github.com/ricardofrantz/nanobook
cd nanobook
cargo build --release
cargo test

# Python bindings
cd python && maturin develop --release

# Binance adapter (feature-gated, not in PyPI wheels)
cd python && maturin develop --release --features binance

The Bridge: Python Strategy → Rust Execution

The canonical integration pattern — Python computes a weight schedule, Rust simulates the portfolio and returns metrics:

import nanobook

result = nanobook.backtest_weights(
    weight_schedule=[
        [("AAPL", 0.5), ("MSFT", 0.5)],
        [("AAPL", 0.3), ("NVDA", 0.7)],
    ],
    price_schedule=[
        [("AAPL", 185_00), ("MSFT", 370_00)],
        [("AAPL", 190_00), ("MSFT", 380_00), ("NVDA", 600_00)],
    ],
    initial_cash=1_000_000_00,  # $1M in cents
    cost_bps=15,                # 15 bps round-trip
    stop_cfg={"trailing_stop_pct": 0.05},
)

print(f"Sharpe: {result['metrics'].sharpe:.2f}")
print(f"Max DD: {result['metrics'].max_drawdown:.1%}")
print(result["holdings"][-1])    # per-period symbol weights
print(result["stop_events"])     # stop trigger metadata

Your optimizer produces weights. backtest_weights() handles rebalancing, cost modeling, position tracking, and return computation at compiled speed with the GIL released.

Portfolio tools include fixed-parameter EWMA-style GARCH forecasting, optimizers (min-variance, max-Sharpe, risk-parity, inverse CVaR, inverse CDaR), and trailing/fixed stop-loss simulation — all accessible from Python.

Optimizer Example

import nanobook
import numpy as np

# Daily returns matrix (T × N)
returns = np.random.randn(252, 5) * 0.01

weights = nanobook.optimize_max_sharpe(returns, risk_free_rate=0.0)
print(dict(zip(["A","B","C","D","E"], weights)))

Layer Examples

LOB Engine (Rust)

use nanobook::{Exchange, Side, Price, TimeInForce};

let mut exchange = Exchange::new();
exchange.submit_limit(Side::Sell, Price(50_00), 100, TimeInForce::GTC);
let result = exchange.submit_limit(Side::Buy, Price(50_00), 100, TimeInForce::GTC);

assert_eq!(result.trades.len(), 1);
assert_eq!(result.trades[0].price, Price(50_00));

Portfolio + Metrics (Python)

portfolio = nanobook.Portfolio(1_000_000_00, nanobook.CostModel(commission_bps=5))
portfolio.rebalance_simple([("AAPL", 0.6)], [("AAPL", 150_00)])
portfolio.record_return([("AAPL", 155_00)])
metrics = portfolio.compute_metrics(252.0, 0.0)
print(f"Sharpe: {metrics.sharpe:.2f}")

Broker + Risk (Python)

# Pre-trade risk check
risk = nanobook.RiskEngine(max_position_pct=0.25, max_leverage=1.5)
checks = risk.check_order("AAPL", "buy", 100, 185_00,
                          equity_cents=1_000_000_00,
                          positions=[("AAPL", 200)])

# Execute through IBKR
broker = nanobook.IbkrBroker("127.0.0.1", 4002, client_id=1)
broker.connect()
oid = broker.submit_order("AAPL", "buy", 100, order_type="limit",
                          limit_price_cents=185_00)

Rebalancer CLI

# Build
cargo build -p nanobook-rebalancer --release

# Dry run — show plan without executing
rebalancer run target.json --dry-run

# Execute with confirmation prompt
rebalancer run target.json

# Compare actual vs target positions
rebalancer reconcile target.json

Performance

End-to-end ITCH replay performance (measured on NASDAQ TotalView-ITCH 2019-07-30, Apple M1 Pro, 16 GB RAM, N=973,285 measured events, warmup excluded)¹:

Stage p50 latency p95 latency p99 latency
ITCH parse 83 ns 166 ns 417 ns
LOB book-update 250 ns 1,042 ns 3,541 ns

¹ Reproducible by following examples/itch-replay/README.md and REPRODUCIBILITY.md. Numbers exclude warmup events and reflect single-threaded replay of a 1-minute NASDAQ trading window (09:30-09:31 ET). See examples/itch-replay/data/report-v2/report.html for full latency distribution histograms.

Kernel microbenchmarks

Single-threaded synthetic microbenchmarks (macOS arm64, v0.10.0, stock clocks)²:

Operation Latency Throughput
Submit (no match) ~155 ns ~6.4M ops/sec
Submit (with match) ~197 ns ~5M ops/sec
BBO query ~1.1 ns ~900M ops/sec
Cancel (tombstone, deep queue) ~385 ns ~2.6M ops/sec
L2 snapshot (10 levels) ~255 ns ~4M ops/sec

² Numbers are criterion medians measured with cargo bench --bench throughput. Hardware, build flags, and background load all move these ±10-20 %. See benches/README.md for the methodology and benches/v0.10-comparison.md for the v0.9.3 → v0.10.0 delta (the v0.10.0 submit path pays a ~20 ns cost for the new self-trade-prevention field even with STP off — a future revision will lift the off-path check out of the matching loop).

Note: End-to-end ITCH replay numbers above reflect real-world parsing and book-update performance on market data, while kernel microbenchmarks measure isolated operations on synthetic inputs.

Single-threaded throughput is roughly equivalent to Numba (both compile to LLVM IR). Where Rust wins: zero cold-start, true parallelism via Rayon with no GIL contention, and deterministic memory without GC pauses.

cargo bench

Feature Flags

Feature Default Description
event-log Yes Event recording for deterministic replay
serde No Serialize/deserialize all public types
persistence No File-based event sourcing (JSON Lines)
portfolio No Portfolio engine, position tracking, metrics, strategy trait
parallel No Rayon-based parallel parameter sweeps
itch No NASDAQ ITCH 5.0 binary protocol parser

Design Constraints

Engineering decisions that keep the system simple and fast:

  • Single-threaded — deterministic by design; same inputs always produce same outputs
  • In-process — no networking overhead; wrap externally if needed
  • Execution scope, not compliance — deterministic STP policies are included; regulatory workflows and circuit breakers are out of scope
  • No complex order types — no iceberg or pegged orders

Documentation

  • Documentation index — versioning, domain language, operations, audit, and learning notes.
  • docs.rs — Rust API docs.
  • Versioning policy — how nanobook handles SemVer while it remains pre-1.0.
  • Ubiquitous language — glossary for order, portfolio, broker, risk, and rebalancer terms.
  • Full developer reference is included below in this README (## Full Reference).

License

MIT

Full Reference

Developer Reference — Full API documentation for the nanobook workspace.


Table of Contents


Quick Start

[dependencies]
nanobook = "0.10.0"
use nanobook::{Exchange, Side, Price, TimeInForce};

let mut exchange = Exchange::new();
exchange.submit_limit(Side::Sell, Price(50_00), 100, TimeInForce::GTC);
let result = exchange.submit_limit(Side::Buy, Price(50_00), 100, TimeInForce::GTC);

assert_eq!(result.trades.len(), 1);
assert_eq!(result.trades[0].price, Price(50_00));

Core Concepts

Prices

Prices are integers in the smallest currency unit (cents for USD), avoiding floating-point errors.

let price = Price(100_50);  // $100.50
assert!(Price(100_00) < Price(101_00));

Display formats as dollars: Price(10050) prints as $100.50.

Constants: Price::ZERO, Price::MAX (market buys), Price::MIN (market sells).

Quantities and Timestamps

  • Quantity = u64 — shares or contracts, always positive.
  • Timestamp = u64 — monotonic nanosecond counter (not system clock), guaranteeing deterministic ordering.

Determinism

No randomness anywhere. Same sequence of operations always produces identical trades. Event replay reconstructs exact state.


Exchange API

Exchange is the main entry point, wrapping an OrderBook with order submission, cancellation, modification, and queries.

Order Submission

// Limit order — matches against opposite side, remainder handled by TIF
let result = exchange.submit_limit(Side::Buy, Price(100_00), 100, TimeInForce::GTC);

// Market order — IOC semantics at Price::MAX (buy) or Price::MIN (sell)
let result = exchange.submit_market(Side::Buy, 500);

Order Management

// Cancel — O(1) via tombstones
let result = exchange.cancel(order_id);  // CancelResult { success, cancelled_quantity, error }

// Modify — cancel + replace (loses time priority, gets new OrderId)
let result = exchange.modify(order_id, Price(101_00), 200);

Queries

let (bid, ask) = exchange.best_bid_ask();  // L1 — O(1)
let spread = exchange.spread();             // Option<i64>
let snap = exchange.depth(10);              // L2 — top 10 levels
let full = exchange.full_book();            // L3 — everything
let order = exchange.get_order(OrderId(1)); // Option<&Order>
let trades = exchange.trades();             // &[Trade]

Memory Management

exchange.clear_trades();           // Clear trade history
exchange.clear_order_history();    // Remove filled/cancelled orders
exchange.compact();                // Reclaim tombstone memory

Input Validation

The try_submit_* methods validate inputs before processing:

let err = exchange.try_submit_limit(Side::Buy, Price(0), 100, TimeInForce::GTC);
assert_eq!(err.unwrap_err(), ValidationError::ZeroPrice);

Time-in-Force Semantics

TIF Partial Fill? Rests on Book? No Liquidity
GTC Yes Yes (remainder) Rests entirely
IOC Yes No (remainder cancelled) Cancelled
FOK No No (all-or-nothing) Cancelled

Types Reference

Type Definition Description Display
Price struct Price(pub i64) Price in smallest units (cents) $100.50
Quantity type Quantity = u64 Number of shares/contracts
OrderId struct OrderId(pub u64) Unique order identifier O42
TradeId struct TradeId(pub u64) Unique trade identifier T7
Timestamp type Timestamp = u64 Nanosecond counter (not wall clock)

Result Types

pub struct SubmitResult {
    pub order_id: OrderId,
    pub status: OrderStatus,          // New | PartiallyFilled | Filled | Cancelled
    pub trades: Vec<Trade>,
    pub filled_quantity: Quantity,
    pub resting_quantity: Quantity,
    pub cancelled_quantity: Quantity,
}

pub struct Trade {
    pub id: TradeId,
    pub price: Price,                 // Resting order's price (aggressor gets price improvement)
    pub quantity: Quantity,
    pub aggressor_order_id: OrderId,
    pub passive_order_id: OrderId,
    pub aggressor_side: Side,
    pub timestamp: Timestamp,
}

Enums

Enum Variants Key Methods
Side Buy, Sell opposite()
TimeInForce GTC, IOC, FOK can_rest(), allows_partial()
OrderStatus New, PartiallyFilled, Filled, Cancelled is_active(), is_terminal()

Book Snapshots

pub struct BookSnapshot {
    pub bids: Vec<LevelSnapshot>,  // Highest price first
    pub asks: Vec<LevelSnapshot>,  // Lowest price first
    pub timestamp: Timestamp,
}

pub struct LevelSnapshot {
    pub price: Price,
    pub quantity: Quantity,
    pub order_count: usize,
}
Method Returns
snap.best_bid() / best_ask() Option<Price>
snap.spread() Option<i64>
snap.mid_price() Option<f64>
snap.total_bid_quantity() / total_ask_quantity() Quantity
snap.imbalance() Option<f64> — [-1.0, 1.0], positive = buy pressure
snap.weighted_mid() Option<f64> — leans toward less liquid side

Stop Orders & Trailing Stops

Stop Orders

// Stop-market: triggers market order when last trade price hits stop
exchange.submit_stop_market(Side::Sell, Price(95_00), 100);

// Stop-limit: triggers limit order at limit_price when stop hits
exchange.submit_stop_limit(Side::Sell, Price(95_00), Price(94_50), 100, TimeInForce::GTC);
Side Triggers When
Buy stop last_trade_price >= stop_price
Sell stop last_trade_price <= stop_price

Key behaviors: immediate trigger if price already past stop, cascade up to 100 iterations, cancel via exchange.cancel(stop_id).

Trailing Stops

Three trailing methods — stop price tracks the market and only moves in the favorable direction:

// Fixed: triggers if price drops $2.00 from peak
exchange.submit_trailing_stop_market(Side::Sell, Price(98_00), 100, TrailMethod::Fixed(200));

// Percentage: trail by 5% from peak
exchange.submit_trailing_stop_market(Side::Sell, Price(95_00), 100, TrailMethod::Percentage(0.05));

// Adaptive trail: 2x simple moving average of |Δ price| over the last
// 14 trades. NOT Wilder's ATR (no OHLC available at the stop module);
// for true Wilder ATR, pre-compute via `indicators::atr` on bar data
// and pass the result as `TrailMethod::Fixed(offset_cents)`.
exchange.submit_trailing_stop_market(Side::Sell, Price(95_00), 100,
    TrailMethod::SmaAbsChange { multiplier: 2.0, period: 14 });

Trailing stop-limit variant: submit_trailing_stop_limit() — same parameters plus limit_price and TimeInForce.


Event Replay

Feature flag: event-log (enabled by default)

Every operation is recorded as an Event. Replaying events on a fresh exchange produces identical state.

// Save events
let events = exchange.events().to_vec();

// Reconstruct exact state
let replayed = Exchange::replay(&events);
assert_eq!(exchange.best_bid_ask(), replayed.best_bid_ask());

Event types: SubmitLimit, SubmitMarket, Cancel, Modify.

Disable for max performance:

nanobook = { version = "0.10.0", default-features = false }

Symbol & MultiExchange

Symbol

Fixed-size instrument identifier. [u8; 8] inline — Copy, no heap allocation, max 8 ASCII bytes.

let sym = Symbol::new("AAPL");
assert!(Symbol::try_new("TOOLONGNAME").is_none());

MultiExchange

Independent per-symbol order books:

let mut multi = MultiExchange::new();
let aapl = Symbol::new("AAPL");

multi.get_or_create(&aapl).submit_limit(Side::Sell, Price(150_00), 100, TimeInForce::GTC);

for (sym, bid, ask) in multi.best_prices() {
    println!("{sym}: bid={bid:?} ask={ask:?}");
}

Portfolio Engine

Feature flag: portfolio

Tracks cash, positions, costs, returns, and equity over time.

use nanobook::portfolio::{Portfolio, CostModel};

let cost = CostModel { commission_bps: 5, slippage_bps: 3, min_trade_fee: 1_00 };
let mut portfolio = Portfolio::new(1_000_000_00, cost);

// Rebalance to target weights
portfolio.rebalance_simple(&[(Symbol::new("AAPL"), 0.6)], &[(Symbol::new("AAPL"), 150_00)]);

// Record period return and compute metrics
portfolio.record_return(&[(Symbol::new("AAPL"), 155_00)]);
let metrics = compute_metrics(portfolio.returns(), 252.0, 0.0);

Execution Modes

  • SimpleFill — instant at bar prices: portfolio.rebalance_simple(targets, prices)
  • LOBFill — route through Exchange matching engines: portfolio.rebalance_lob(targets, exchanges)

Position

Per-symbol tracking with VWAP entry price and realized PnL:

let mut pos = Position::new(Symbol::new("AAPL"));
pos.apply_fill(100, 150_00);   // buy 100 @ $150
pos.apply_fill(-50, 160_00);   // sell 50 @ $160 → $500 realized PnL

Financial Metrics

compute_metrics(&returns, periods_per_year, risk_free) returns: total_return, cagr, volatility, sharpe, sortino, max_drawdown, calmar, num_periods, winning_periods, losing_periods.

Parallel Sweep

Feature flag: parallel (implies portfolio)

use nanobook::portfolio::sweep::sweep;

let results = sweep(&params, 12.0, 0.0, |&leverage| {
    vec![0.01 * leverage, -0.005 * leverage]
});

Strategy Trait

Feature flag: portfolio

Implement compute_weights() for batch-oriented backtesting:

impl Strategy for MomentumStrategy {
    fn compute_weights(
        &self,
        bar_index: usize,
        prices: &[(Symbol, i64)],
        _portfolio: &Portfolio,
    ) -> Vec<(Symbol, f64)> {
        if bar_index < self.lookback { return vec![]; }
        let w = 1.0 / prices.len() as f64;
        prices.iter().map(|(sym, _)| (*sym, w)).collect()
    }
}

let result = run_backtest(&strategy, &price_series, 1_000_000_00, CostModel::zero(), 12.0, 0.0);

Built-in: EqualWeight strategy. Parallel variant: sweep_strategy().


Backtest Bridge

The bridge between Python strategy code and Rust execution. Python computes a weight schedule, Rust simulates the portfolio at compiled speed.

Rust API

use nanobook::backtest_bridge::backtest_weights;

let result = backtest_weights(
    &weight_schedule,    // &[Vec<(Symbol, f64)>] — target weights per period
    &price_schedule,     // &[Vec<(Symbol, i64)>] — prices per period
    1_000_000_00,        // initial cash in cents
    15,                  // cost in basis points
    252.0,               // periods per year
    0.0,                 // risk-free rate per period
);

Returns BacktestBridgeResult:

Field Type Description
returns Vec<f64> Per-period returns
equity_curve Vec<i64> Equity at each period (cents)
final_cash i64 Ending cash balance
metrics Option<Metrics> Sharpe, Sortino, max drawdown, etc.
holdings Vec<Vec<(Symbol, f64)>> Per-period holdings weights
symbol_returns Vec<Vec<(Symbol, f64)>> Per-period close-to-close symbol returns
stop_events Vec<BacktestStopEvent> Stop trigger metadata (index, symbol, price, reason)

Python API

result = nanobook.py_backtest_weights(
    weight_schedule=[[("AAPL", 0.5), ("MSFT", 0.5)], ...],
    price_schedule=[[("AAPL", 185_00), ("MSFT", 370_00)], ...],
    initial_cash=1_000_000_00,
    cost_bps=15,
    periods_per_year=252.0,
    risk_free=0.0,
    stop_cfg={"trailing_stop_pct": 0.05},
)
# result["returns"], result["equity_curve"], result["metrics"],
# result["holdings"], result["symbol_returns"], result["stop_events"]

GIL is released during computation for maximum throughput.

Clean aliases (no py_ prefix) are exported for new integrations: backtest_weights, capabilities, garch_ewma_forecast, inverse_cvar_weights, inverse_cdar_weights, and other optimizer helpers.

Capability Probing Pattern

Downstream Python applications can probe nanobook capabilities before choosing a Rust-backed fast path or a local fallback:

import nanobook

def has_nanobook_feature(name: str) -> bool:
    caps = set(nanobook.py_capabilities()) if hasattr(nanobook, "py_capabilities") else set()
    if name in caps:
        return True

    symbol_map = {
        "backtest_stops": "py_backtest_weights",
        "garch_ewma_forecast": "py_garch_ewma_forecast",
        "optimize_min_variance": "py_optimize_min_variance",
        "optimize_max_sharpe": "py_optimize_max_sharpe",
        "optimize_risk_parity": "py_optimize_risk_parity",
        "inverse_cvar_weights": "py_inverse_cvar_weights",
        "inverse_cdar_weights": "py_inverse_cdar_weights",
        "backtest_holdings": "py_backtest_weights",
    }
    sym = symbol_map.get(name)
    return bool(sym and hasattr(nanobook, sym))

Broker Abstraction

Crate: nanobook-broker

Generic trait over brokerages with concrete adapters for IBKR and Binance.

Broker Trait

pub trait Broker {
    fn connect(&mut self) -> Result<(), BrokerError>;
    fn disconnect(&mut self) -> Result<(), BrokerError>;
    fn positions(&self) -> Result<Vec<Position>, BrokerError>;
    fn account(&self) -> Result<Account, BrokerError>;
    fn submit_order(&self, order: &BrokerOrder) -> Result<OrderId, BrokerError>;
    fn order_status(&self, id: OrderId) -> Result<BrokerOrderStatus, BrokerError>;
    fn cancel_order(&self, id: OrderId) -> Result<(), BrokerError>;
    fn quote(&self, symbol: &Symbol) -> Result<Quote, BrokerError>;
}

Key Types

pub struct Position {
    pub symbol: Symbol,
    pub quantity: i64,             // Positive = long, negative = short
    pub avg_cost_cents: i64,
    pub market_value_cents: i64,
    pub unrealized_pnl_cents: i64,
}

pub struct Account {
    pub equity_cents: i64,
    pub buying_power_cents: i64,
    pub cash_cents: i64,
    pub gross_position_value_cents: i64,
}

pub struct BrokerOrder {
    pub symbol: Symbol,
    pub side: BrokerSide,          // Buy or Sell
    pub quantity: u64,
    pub order_type: BrokerOrderType,  // Market or Limit(Price)
}

pub struct Quote {
    pub symbol: Symbol,
    pub bid_cents: i64,
    pub ask_cents: i64,
    pub last_cents: i64,
    pub volume: u64,
}

IBKR Adapter

Feature: ibkr

Connects to TWS/Gateway via the ibapi crate (blocking API).

let mut broker = IbkrBroker::new("127.0.0.1", 4002, 1);  // 4002 = paper, 4001 = live
broker.connect()?;
let positions = broker.positions()?;
let quote = broker.quote(&Symbol::new("AAPL"))?;

Binance Adapter

Feature: binance

REST API via reqwest::blocking. Converts nanobook symbols (e.g., "BTC") to Binance pairs (e.g., "BTCUSDT").

let mut broker = BinanceBroker::new(api_key, secret_key, true);  // testnet
broker.connect()?;

Python

broker = nanobook.IbkrBroker("127.0.0.1", 4002, client_id=1)
broker.connect()
positions = broker.positions()   # List[Dict] with symbol, quantity, avg_cost_cents, ...
oid = broker.submit_order("AAPL", "buy", 100, order_type="limit", limit_price_cents=185_00)
quote = broker.quote("AAPL")     # Dict with bid_cents, ask_cents, last_cents, volume

broker = nanobook.BinanceBroker(api_key, secret_key, testnet=True, quote_asset="USDT")

Risk Engine

Crate: nanobook-risk

Pre-trade risk validation for single orders and rebalance batches.

RiskConfig

pub struct RiskConfig {
    pub max_position_pct: f64,       // Max single position as fraction of equity (default 0.25)
    pub max_order_value_cents: i64,  // Max single order value
    pub max_batch_value_cents: i64,  // Max rebalance batch value
    pub max_leverage: f64,           // Max gross exposure / equity (default 1.5)
    pub max_drawdown_pct: f64,       // Circuit breaker threshold (default 0.20)
    pub allow_short: bool,           // Allow short positions (default true)
    pub max_short_pct: f64,          // Max short exposure fraction (default 0.30)
    pub min_trade_usd: f64,
    pub max_trade_usd: f64,          // Max single trade USD (default 100,000)
}

Notes:

  • max_drawdown_pct is validated at engine construction and preserved in config, but not yet used in execution-time checks.

Single Order Check

let engine = RiskEngine::new(RiskConfig::default()).expect("valid risk config");
let report = engine.check_order(
    &Symbol::new("AAPL"),
    BrokerSide::Buy,
    100,              // quantity
    185_00,           // price in cents
    &account,
    &current_positions,
);

if report.has_failures() {
    // Order violates risk limits — position concentration, short selling, etc.
}

Batch Check

Validates a full rebalance against position limits, leverage, and short exposure:

let report = engine.check_batch(
    &orders,              // &[(Symbol, BrokerSide, u64, i64)]
    &account,
    &current_positions,
    &target_weights,      // &[(Symbol, f64)]
);

RiskReport

pub struct RiskReport {
    pub checks: Vec<RiskCheck>,
}

pub struct RiskCheck {
    pub name: &'static str,
    pub status: RiskStatus,  // Pass | Warn | Fail
    pub detail: String,
}

impl RiskReport {
    pub fn has_failures(&self) -> bool;
    pub fn has_warnings(&self) -> bool;
}

Python

risk = nanobook.RiskEngine(max_position_pct=0.25, max_leverage=1.5)

# Single order
checks = risk.check_order("AAPL", "buy", 100, 185_00,
                          equity_cents=1_000_000_00,
                          positions=[("AAPL", 200)])

# Batch (full rebalance)
checks = risk.check_batch(
    orders=[("AAPL", "buy", 100, 185_00), ("MSFT", "sell", 50, 370_00)],
    equity_cents=1_000_000_00,
    positions=[("AAPL", 200), ("MSFT", 100)],
    target_weights=[("AAPL", 0.6), ("MSFT", 0.2)],
)
# Each check: {"name": "...", "status": "Pass|Warn|Fail", "detail": "..."}

Rebalancer CLI

Crate: nanobook-rebalancer

CLI tool that bridges target weights to IBKR execution with risk checks, rate limiting, and audit trail.

Pipeline

  1. Read target weights from target.json (output of your optimizer)
  2. Connect to IBKR Gateway for live positions, prices, account data
  3. Compute CURRENT → TARGET diff (share quantities, limit prices)
  4. Run pre-trade risk checks (position limits, leverage, short exposure)
  5. Show plan, confirm (or --force for automation)
  6. Execute limit orders with rate limiting and timeout-based cancellation
  7. Reconcile and log to JSONL audit trail

Commands

rebalancer status                     # Check IBKR connection
rebalancer positions                  # Show current positions
rebalancer run target.json            # Plan → confirm → execute
rebalancer run target.json --dry-run  # Plan only
rebalancer run target.json --force    # Skip confirmation (cron/automation)
rebalancer reconcile target.json      # Compare actual vs target
rebalancer recover target.json       # Recover from crash using audit log

Operations & Recovery

The rebalancer includes crash recovery via audit log reconstruction. After a process crash or TWS restart, use rebalancer recover to reconstruct state and determine the appropriate recovery action (Restart, Resume, ManualReview, or Rollback).

target.json

{
  "timestamp": "2026-02-08T15:30:00Z",
  "targets": [
    { "symbol": "AAPL", "weight": 0.40 },
    { "symbol": "MSFT", "weight": 0.30 },
    { "symbol": "SPY",  "weight": -0.10 },
    { "symbol": "QQQ",  "weight": 0.20 }
  ],
  "constraints": {
    "max_position_pct": 0.40,
    "max_leverage": 1.5
  }
}

Positive weights are long, negative are short. Symbols absent from the target but present in the account get closed. See rebalancer/config.toml.example for the full configuration reference.


Python Bindings

Install: pip install nanobook or cd python && maturin develop --release

Exchange

ex = nanobook.Exchange()
result = ex.submit_limit("buy", 10050, 100, "gtc")
result = ex.submit_market("sell", 50)
ex.cancel(result.order_id)
bid, ask = ex.best_bid_ask()
snap = ex.depth(10)

Stop Orders

ex.submit_stop_market("sell", 9500, 100)
ex.submit_stop_limit("buy", 10500, 10600, 100, "gtc")
ex.submit_trailing_stop_market("sell", 9500, 100, "percentage", 0.05)

Portfolio

portfolio = nanobook.Portfolio(1_000_000_00, nanobook.CostModel(commission_bps=10))
portfolio.rebalance_simple([("AAPL", 0.6)], [("AAPL", 150_00)])
portfolio.record_return([("AAPL", 155_00)])
metrics = portfolio.compute_metrics(252.0, 0.0)

Strategy Callback

result = nanobook.run_backtest(
    strategy=lambda bar, prices, portfolio: [("AAPL", 0.5), ("GOOG", 0.5)],
    price_series=[{"AAPL": 150_00, "GOOG": 280_00}] * 252,
    initial_cash=1_000_000_00,
    cost_model=nanobook.CostModel.zero(),
)

ITCH Parser

events = nanobook.parse_itch("data/sample.itch")

Book Analytics

Imbalance

let snap = exchange.depth(10);
if let Some(imb) = snap.imbalance() {
    // [-1.0, 1.0]: positive = buy pressure
    println!("Imbalance: {imb:.4}");
}

Weighted Midpoint

if let Some(wmid) = snap.weighted_mid() {
    println!("Weighted mid: {wmid:.2}");
}

VWAP

if let Some(vwap) = Trade::vwap(exchange.trades()) {
    println!("VWAP: {vwap}");
}

Persistence & Serde

Persistence

Feature flag: persistence (includes serde and event-log)

// Exchange — JSON Lines event sourcing
exchange.save(Path::new("orders.jsonl")).unwrap();
let loaded = Exchange::load(Path::new("orders.jsonl")).unwrap();

// Portfolio — JSON
portfolio.save_json(Path::new("portfolio.json")).unwrap();
let loaded = Portfolio::load_json(Path::new("portfolio.json")).unwrap();

Serde

Feature flag: serde

All public types derive Serialize/Deserialize: Price, OrderId, TradeId, Symbol, Side, TimeInForce, OrderStatus, Order, Trade, Event, SubmitResult, CancelResult, ModifyResult, BookSnapshot, LevelSnapshot, StopOrder, Position, CostModel, and more.


CLI Reference

Interactive REPL for the order book:

cargo run --bin lob
Command Example
buy <price> <qty> [ioc|fok] buy 100.50 100
sell <price> <qty> [ioc|fok] sell 101.00 50 ioc
market <buy|sell> <qty> market buy 200
stop <buy|sell> <price> <qty> stop buy 105.00 100
cancel <order_id> cancel 3
book / trades Show book or trade history
save <path> / load <path> Persistence (requires feature)

Performance

Benchmarks

Single-threaded (AMD Ryzen / Intel Core):

Operation Latency Throughput Complexity
Submit (no match) ~155 ns ~6.4M ops/sec O(log P)
Submit (with match) ~197 ns ~5M ops/sec O(log P + M)
BBO query ~1.1 ns ~900M ops/sec O(1)
Cancel (tombstone, deep queue) ~385 ns ~2.6M ops/sec O(1)
L2 snapshot (10 levels) ~255 ns ~4M ops/sec O(D)

Where P = price levels, M = orders matched, D = depth. Numbers are from benches/v0.10-comparison.md on macOS arm64; expect ±10-20 % across hardware and build flags.

Time Breakdown (Submit, No Match)

submit_limit() ~155 ns:
├── FxHashMap insert     ~30 ns   order storage
├── BTreeMap insert      ~30 ns   price level (O(log P))
├── VecDeque push         ~5 ns   FIFO queue
├── Event recording      ~10 ns   (optional, for replay)
├── STP branch           ~20 ns   `owner` field + policy read (Off path)
└── Overhead             ~60 ns   struct creation, dispatch, etc.

Optimizations

  1. O(1) cancel — Tombstone-based, 350x faster than linear scan
  2. FxHash — Non-cryptographic hash for OrderId lookups (+25% vs std HashMap)
  3. Cached BBO — Best bid/ask cached for O(1) access
  4. Optional event logging — disable event-log feature for max throughput

Rust vs Numba

Single-threaded throughput is roughly equivalent (both compile to LLVM IR). Where Rust wins: zero cold-start (vs Numba's ~300 ms JIT), true parallelism via Rayon with no GIL contention, and deterministic memory without GC pauses.


Where nanobook Fits

nanobook is not trying to replace a full trading platform. It is the execution kernel you can put under a Python strategy when you want deterministic accounting, matching, risk checks, and a cautious path to broker execution.

If you need... Use...
Python signal research with vectorized factor tooling pandas, Polars, scipy, vectorbt, Riskfolio-Lib
A broad venue/connector layer CCXT, Hummingbot, or a dedicated broker stack
A full platform with calendars, operator workflows, and many venues NautilusTrader or LEAN
A compact Rust execution layer around target weights nanobook
A standalone order-book crate only A narrower LOB library may be enough

nanobook's measured LOB hot path is still fast (~155 ns submit/no-match on the v0.10 benchmark run), but the reason to use the project is the combination: LOB, portfolio accounting, metrics, risk, Python bindings, broker adapters, and a rebalancer in one small workspace. Benchmark on your own hardware before making latency-sensitive decisions.


Design Constraints

Engineering decisions that keep the system simple and fast:

Constraint Rationale
Single-threaded Deterministic by design — same inputs always produce same outputs
In-process No networking overhead; wrap externally if needed
Execution scope, not compliance STP policies are supported; regulatory workflows and circuit breakers are out of scope
No complex orders No iceberg or pegged orders
Integer prices Fixed-point arithmetic avoids floating-point rounding
Statistics in Python Spearman/IC/t-stat belong in scipy/Polars — proven, mature

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

nanobook-0.16.1.tar.gz (2.0 MB view details)

Uploaded Source

Built Distributions

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

nanobook-0.16.1-cp314-cp314-win_amd64.whl (1.0 MB view details)

Uploaded CPython 3.14Windows x86-64

nanobook-0.16.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ x86-64

nanobook-0.16.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.4 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ ARM64

nanobook-0.16.1-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (2.3 MB view details)

Uploaded CPython 3.14macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

nanobook-0.16.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

nanobook-0.16.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.4 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ ARM64

nanobook-0.16.1-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (2.3 MB view details)

Uploaded CPython 3.13macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

nanobook-0.16.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

nanobook-0.16.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.4 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ ARM64

nanobook-0.16.1-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (2.3 MB view details)

Uploaded CPython 3.12macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

nanobook-0.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

nanobook-0.16.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.4 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ ARM64

nanobook-0.16.1-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (2.3 MB view details)

Uploaded CPython 3.11macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

File details

Details for the file nanobook-0.16.1.tar.gz.

File metadata

  • Download URL: nanobook-0.16.1.tar.gz
  • Upload date:
  • Size: 2.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for nanobook-0.16.1.tar.gz
Algorithm Hash digest
SHA256 8c8370c85eb49eac5d6c80c93a115fa5ec0c7222d89c7f805dd075bde69c6f8f
MD5 bb065ddda0d613b2ae4dfa903d480350
BLAKE2b-256 b36b22354327422cac3d01a04da193bdcd0edefe7de4c4b2a74aed578f2d2dbd

See more details on using hashes here.

Provenance

The following attestation bundles were made for nanobook-0.16.1.tar.gz:

Publisher: wheels.yml on ricardofrantz/nanobook

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

File details

Details for the file nanobook-0.16.1-cp314-cp314-win_amd64.whl.

File metadata

  • Download URL: nanobook-0.16.1-cp314-cp314-win_amd64.whl
  • Upload date:
  • Size: 1.0 MB
  • Tags: CPython 3.14, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for nanobook-0.16.1-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 9d5e8deb06be39fd8093e1a9303a7b3e5d3456053f9058c72f6ff25409d153cb
MD5 45e248f53994fa27ee305a97dfb8cc1f
BLAKE2b-256 dc9fe589c77e9535c14cefaac6bc5d0ed4a97ce755745035022ae20ccb4cf8bf

See more details on using hashes here.

Provenance

The following attestation bundles were made for nanobook-0.16.1-cp314-cp314-win_amd64.whl:

Publisher: wheels.yml on ricardofrantz/nanobook

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

File details

Details for the file nanobook-0.16.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for nanobook-0.16.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c9743d0ef2fdb3916b3676980896343de16399e7f8276da4f6f9a42f8cbf9ea4
MD5 b5fd2edb66f233e0ea373c63490a7e2c
BLAKE2b-256 ec8e5f33237db5faadc40a4481758532bf9101e77e7c95339bc20591fb10eebc

See more details on using hashes here.

Provenance

The following attestation bundles were made for nanobook-0.16.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: wheels.yml on ricardofrantz/nanobook

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

File details

Details for the file nanobook-0.16.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for nanobook-0.16.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 ef4c70913c447ad0259787e702eca5a781a143bb13e7cb6c5e6fc1c81ed55621
MD5 95980fbcd8f95187c9dba39db3a05c29
BLAKE2b-256 81ae8ccc5cafd1b0624e7e7cf14fe0b6e75175be8a13e43bed0c7b727f0af711

See more details on using hashes here.

Provenance

The following attestation bundles were made for nanobook-0.16.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: wheels.yml on ricardofrantz/nanobook

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

File details

Details for the file nanobook-0.16.1-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.

File metadata

File hashes

Hashes for nanobook-0.16.1-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 62ba63fb3ecd961eb9d819b59b73831ce5939855db27816fd863cbf4e50a53fa
MD5 9e4434f0e4cb883d617fb7b29883ba36
BLAKE2b-256 98d70fd0f7a89474ece064889cc44b4f8abfb7f8c8aed3ad2d20efd66d0c5008

See more details on using hashes here.

Provenance

The following attestation bundles were made for nanobook-0.16.1-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl:

Publisher: wheels.yml on ricardofrantz/nanobook

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

File details

Details for the file nanobook-0.16.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for nanobook-0.16.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 e7f4d311a48e94d369f57ec71b26bf150698c2272554f07c82baee013e7f2300
MD5 751304b574501bcdc33ede0a42d9e67a
BLAKE2b-256 67c170050faff38dbfe9fbc72b8bf63fbbb6f5a96669d8b4eb7da0be117b9ccb

See more details on using hashes here.

Provenance

The following attestation bundles were made for nanobook-0.16.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: wheels.yml on ricardofrantz/nanobook

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

File details

Details for the file nanobook-0.16.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for nanobook-0.16.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 c4fb595d4666598b038f25dbd688bfba3372f7420dd444f26558a4cfd2061e71
MD5 4933b68da40190885833c08bb42b0742
BLAKE2b-256 8d5491831d69d700fc0422aa4a8391f3f120136906d2b25675140f601726a429

See more details on using hashes here.

Provenance

The following attestation bundles were made for nanobook-0.16.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: wheels.yml on ricardofrantz/nanobook

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

File details

Details for the file nanobook-0.16.1-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.

File metadata

File hashes

Hashes for nanobook-0.16.1-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 e63f75ad6c0371354d7b59f9d15f6821a7ea0c00397d1b578ae3a231c8ebde40
MD5 a9142639bf4ce615c6093653d8612fab
BLAKE2b-256 94baf06d09601b6c1d1eb77af6f7571a3382457c9983eeb3cdb672c88322d78a

See more details on using hashes here.

Provenance

The following attestation bundles were made for nanobook-0.16.1-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl:

Publisher: wheels.yml on ricardofrantz/nanobook

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

File details

Details for the file nanobook-0.16.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for nanobook-0.16.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9db53ec684c3fb5d7d85be3b6ac94f7c0cd16dc1fab62c4d075113756af4e8f8
MD5 f56db743601735117042ff2d93601b76
BLAKE2b-256 6c8394744ed9863066ecf59629468226842574e7ae2208beb11aca3907391387

See more details on using hashes here.

Provenance

The following attestation bundles were made for nanobook-0.16.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: wheels.yml on ricardofrantz/nanobook

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

File details

Details for the file nanobook-0.16.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for nanobook-0.16.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 bdb200b5e1b08bf87eaecb874c461ea99577e3d25619d49080dc5f82e762895b
MD5 f9106926b3e3900da2e49f1a48f70e0d
BLAKE2b-256 fdce6c3c304d4a92ce3a11548a0c423925aa1311c42ff54622951dbaa811a505

See more details on using hashes here.

Provenance

The following attestation bundles were made for nanobook-0.16.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: wheels.yml on ricardofrantz/nanobook

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

File details

Details for the file nanobook-0.16.1-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.

File metadata

File hashes

Hashes for nanobook-0.16.1-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 33ade36a36ec077b6fdc40113b99c377b7807438ebf5d21b7c1932f48e71ecb6
MD5 f2aa35d47ce047edbd2ae418f2e4c65b
BLAKE2b-256 20dbc9cfcb3f9a42fc6ab2efe366ef1c48b3bb9460b4518ce44b8829f02cbdd2

See more details on using hashes here.

Provenance

The following attestation bundles were made for nanobook-0.16.1-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl:

Publisher: wheels.yml on ricardofrantz/nanobook

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

File details

Details for the file nanobook-0.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for nanobook-0.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9957c7ad9e7cb476a7d9d09d6ee700e2cb36b9b34c7c21259ed6728e8f96066c
MD5 236c6a869e78fe3b1c992208e40db544
BLAKE2b-256 6020a46526e374c5977a99186d8e25125f250ab9bc907bde34cc0c058bf87f0d

See more details on using hashes here.

Provenance

The following attestation bundles were made for nanobook-0.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: wheels.yml on ricardofrantz/nanobook

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

File details

Details for the file nanobook-0.16.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for nanobook-0.16.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 1075b0081e873d38cf671f6d9ea667a8c4009cd7909cc66ececababb8f7b2943
MD5 c7ddc52a86eaea6b84a4f6e1a0dcec9b
BLAKE2b-256 715191addb3c04f290f517033ff78b565b7efb37eae64c449b58ba5ad2e78f5a

See more details on using hashes here.

Provenance

The following attestation bundles were made for nanobook-0.16.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: wheels.yml on ricardofrantz/nanobook

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

File details

Details for the file nanobook-0.16.1-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.

File metadata

File hashes

Hashes for nanobook-0.16.1-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 ed2a9d7b112a2b22aad75a6da64e215a305289065887ce9d81d5fd39e9f31fc5
MD5 5199124aa3405cac0a22f5584a0f0ef7
BLAKE2b-256 9db1893257b53e2693c00355458ee43c9d137ef994feeb4c34424f75eaaff70f

See more details on using hashes here.

Provenance

The following attestation bundles were made for nanobook-0.16.1-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl:

Publisher: wheels.yml on ricardofrantz/nanobook

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