Aperiodic
Metrics
MarketsLive
DocsPricing
Get the data

Integration

Aperiodic bars and metrics in a NautilusTrader backtest

NautilusTrader builds bars from a pandas DataFrame with its BarDataWrangler. This snippet pulls a month of Binance BTCUSDT perp OHLCV and order flow from Aperiodic with no API key, stamps each bar at its close as Nautilus expects, and runs a backtest whose strategy reads the share of taker volume that was buying.

Tested with nautilus_trader 1.231.0 and aperiodic 4.3.1, on November 5, 2026. The code runs as written against the free preview, with no API key.

Install

pip install "aperiodic[polars]" pandas nautilus_trader

The code

# pip install "aperiodic[polars]" pandas nautilus_trader
from datetime import date

import aperiodic
import pandas as pd
from nautilus_trader.backtest.engine import BacktestEngine, BacktestEngineConfig
from nautilus_trader.config import LoggingConfig
from nautilus_trader.model.currencies import USDT
from nautilus_trader.model.data import Bar, BarType
from nautilus_trader.model.enums import AccountType, OmsType, OrderSide
from nautilus_trader.model.identifiers import Venue
from nautilus_trader.model.objects import Money
from nautilus_trader.persistence.wranglers import BarDataWrangler
from nautilus_trader.test_kit.providers import TestInstrumentProvider
from nautilus_trader.trading.strategy import Strategy

window = dict(
    timestamp="exchange", interval="5m", exchange="binance-futures",
    symbol="perpetual-BTC-USDT:USDT", start_date=date(2025, 5, 1),
    end_date=date(2025, 5, 31), preview=True, output="pandas",
    show_progress=False,
)
ohlcv = aperiodic.get_ohlcv(**window).set_index("time")
flow = aperiodic.get_metrics(metric="flow", **window).set_index("time")
# Aperiodic stamps a bar at its open; Nautilus expects its close
ohlcv.index = ohlcv.index.tz_localize("UTC") + pd.Timedelta(minutes=5)
buy_share = flow["taker_buy_volume"] / (
    flow["taker_buy_volume"] + flow["taker_sell_volume"]
)

instrument = TestInstrumentProvider.btcusdt_perp_binance()
bar_type = BarType.from_str(f"{instrument.id}-5-MINUTE-LAST-EXTERNAL")
bars = BarDataWrangler(bar_type, instrument).process(
    ohlcv[["open", "high", "low", "close", "volume"]]
)
# The metric, keyed by the same nanosecond timestamp the wrangler gives each bar
signal = dict(zip((bar.ts_event for bar in bars), buy_share.to_numpy()))


class BuyShareStrategy(Strategy):
    def __init__(self):
        super().__init__()
        self.held = 0

    def on_start(self):
        self.subscribe_bars(bar_type)

    def on_bar(self, bar: Bar):
        flat = self.portfolio.is_flat(instrument.id)
        if flat and signal.get(bar.ts_event, 0) > 0.7:
            order = self.order_factory.market(
                instrument.id, OrderSide.BUY, instrument.make_qty(0.01)
            )
            self.submit_order(order)
            self.held = 0
        elif not flat:
            self.held += 1
            if self.held >= 6:  # 30 minutes
                self.close_all_positions(instrument.id)


engine = BacktestEngine(
    BacktestEngineConfig(logging=LoggingConfig(log_level="ERROR"))
)
engine.add_venue(
    venue=Venue("BINANCE"),
    oms_type=OmsType.NETTING,
    account_type=AccountType.MARGIN,
    base_currency=None,
    starting_balances=[Money(10_000, USDT)],
)
engine.add_instrument(instrument)
engine.add_data(bars)
engine.add_strategy(BuyShareStrategy())
engine.run()
print(len(bars), "bars,", len(engine.cache.orders()), "orders")

What it prints: 8928 bars, 640 orders.

How the data fits NautilusTrader

Shift the bars to their close

Aperiodic stamps a bar at its open, and Nautilus treats a bar’s timestamp as the moment it closed. Without the 5-minute shift in the snippet, each bar would arrive in the backtest five minutes before it finished.

The instrument is from Nautilus’s test kit

TestInstrumentProvider.btcusdt_perp_binance() is a ready-made definition for examples. For real work, define the instrument with the venue’s own tick size, lot size and fees.

Exchange time or arrival time

timestamp="exchange" builds every bar on the venue’s clock. timestamp="true" builds it on when each event reached our collectors closest to the exchange, so a bar holds only what a live strategy could have seen by its close. That is the clock to backtest on if you plan to trade live. The preview is exchange time only; local time comes with a plan.

Metrics join on time

Every dataset shares the same time column for a given symbol, interval and timestamp choice, so OHLCV, flow, funding or open interest join on the index without resampling.

The preview is one month of one coin

Without a key, every dataset previews the Binance BTCUSDT perpetual at 5 minutes for May 2025. With a free account’s key, drop preview=True and pass api_key= for every metric over 2025 on BTC, ETH, SOL and 10 RWA perps, on any venue, from 1 minute to 1 day. A plan opens every perp and every year.

Delisted coins are in the data

On a plan, the same call works for every perpetual on Binance, OKX and Hyperliquid, including the ones since delisted, so a cross-sectional backtest has no survivorship bias. Published bars are never recalculated, so it reads the same history next year.

Pull years at once

Set start_date and end_date years apart and the SDK downloads the parquet files in parallel, 10 at a time by default (max_concurrent). Prime and above have no API rate limits; Pro has high ones.

Beyond the preview

The snippet uses ohlcv and flow. Swap in any of the 220 metrics across 19 datasets (catalog). A free account gets all of them for 2025 on BTC, ETH, SOL and 10 RWA perps. For every perp and every year, funding, open interest, basis, slippage and price impact are on Pro, from $199 a month billed yearly, and L1 and L2 order book imbalance and liquidity are on Prime (pricing). The NautilusTrader documentation covers everything on its side.

Questions teams ask us

How do I load external bar data into NautilusTrader?
Build a pandas DataFrame with open, high, low, close and volume indexed by the bar’s close time, then pass it to BarDataWrangler(bar_type, instrument).process(). Aperiodic’s time column is the bar’s open, so add one interval first.
Can a NautilusTrader strategy read Aperiodic metrics?
Yes. The example keys the metric by each bar’s ts_event and looks it up in on_bar. Any Aperiodic dataset with the same symbol and interval joins the same way.

Run it before you pick a plan

Every dataset in the catalog has a preview slice you can download as parquet with no API key, plus full column documentation. The snippet above runs on it as written.

Browse the catalogSee pricingBook a call

Shown: minute lows of the 465 Binance perpetuals, 20:40–22:00 UTC on 10 Oct 2025, with BTC’s path traced · built with ohlcv 1m

Keep reading

  • Aperiodic in VectorBTCrypto order flow data in VectorBT
  • Aperiodic in BacktraderCrypto microstructure metrics as Backtrader lines
  • Order flowSigned volume split by trade size, with a toxicity score.
  • API docsEndpoints, parameters and the Python SDK.
Aperiodic

Built from hundreds of terabytes of raw data and distilled into point-in-time metrics you can pull as parquet files. Plus the raw trades, quotes and derivatives data behind them.

Use Cases
  • Improve your backtest
  • Find new alpha
  • Execute smarter
Indices
  • All indices
  • Aperiodic Cost Index
  • Aperiodic Depth Index
  • Aperiodic Impact Index
Metrics
  • Metrics library
  • Data Catalog
  • Free data
  • Live markets dashboard
  • Every perp, A–Z
  • Global Liquidity
  • Unusual activity
  • Order Flow
  • L1 & L2
  • Derivatives
  • RWA
  • Live funding rates
  • Raw Data
Developers
  • Docs
  • API Docs
  • MCP Server
  • Notebooks
  • Integrations
  • For AI Agents
  • Atlas Security Master
  • TParquet
  • Binance OI history API
  • OKX history APIs
  • Pre-flight
  • Changelog
  • Roadmap
  • llms.txt
Learn
  • Markets from First Principles
  • Replays
  • Microstructure Guide
  • Architecture
  • Research Blog
  • FAQ
Compare
  • All vendors
  • Pricing compared
  • vs. Tardis
  • vs. CoinGlass
  • vs. Kaiko
  • vs. Amberdata
  • vs. Crypto Lake
  • vs. Laevitas
  • vs. Coinalyze
  • vs. Binance public data
  • vs. Hyperliquid data
  • Binance archive
  • Hyperliquid data
Company
  • Team
  • Pricing
  • Contact
  • Book a call
  • Terms of Service
  • Privacy Policy
  • Licensing
  • SLA

© Copyright 2026 Aperiodic. All Rights Reserved.

Aperiodic Limited · Registered in Ireland · Company No. 815273 ·
136 Capel Street, Dublin D01 T2C9, Ireland