Skip to content

Flow API reference · v1.0.0

HiveQ Flow API Reference

Author the strategy on your machine. HiveQ runs the strategy on a managed engine, sources the data, simulates market microstructure, and returns a full performance report.

Install the Python SDK

bash
pip install hiveq-sdk
On this page

Overview

HiveQ Flow is a thin client: it captures and deploys your strategy, then the platform runs the engine, fetches the data, and returns results. You write the what (your trading logic); the platform handles the how — data, execution, analytics, and scale. You can't pull market data locally — the engine has it.

Why HiveQ

  • A simulator built to mirror production. Orders clear against real market microstructure — tick-level data, exchange session windows, primary-exchange auctions, per-asset fee models, slippage, and tick-size rounding.
  • Research → paper trading, same strategy. Move an eligible completed backtest into paper trading from the platform. Broker-neutral live trading is planned and is not part of this preview.
  • Every run tracked & versioned. Strategy code and config are captured per run, so any backtest is reproducible — inspect the exact code behind a result and build from it.
  • Execution models available for testing. Use POV, TWAP, and auction instructions in supported simulation workflows.
  • Multi-asset, multi-strategy. Equities, futures (continuous contracts with automatic rollover), and options down to 0DTE — together in one backtest, with TCA and PDF tearsheets out of the box.

The model in one minute

  • One class, callback methods. Implement only the events you care about — on_start, on_bar, on_order, and more.
  • Subscribe in on_start. Register your data there so it's ready before the run begins.
  • Fills arrive in on_order — there is no separate fill callback; check order.is_filled.
  • Time is U.S. Eastern. ctx.now() and every timestamp are already in market time (ET) — no timezone math.

Install & Sign-in

bash
pip install hiveq-sdk

Sign-in is fully automatic. The first time you run a backtest, a browser opens for you to sign in (or sign up); the run waits while you do, then continues — and every later run reuses your access with no prompt. There is no "set up your key first" step, nothing to copy, nothing to configure.

Quickstart

A complete strategy: subscribe in on_start, react in on_bar, place orders through ctx, then deploy with run_backtest and read the report.

python
import hiveq.flow as hf
  from hiveq.flow import StrategyConfig
  from hiveq.flow.config import AssetType
  from hiveq.flow.logger import logger as _get_logger

  logger = _get_logger()   # module-level — REQUIRED in every strategy

  class BuyAndHold:
      def __init__(self):
          self.bought = False

      def on_start(self, ctx, event):
          ctx.subscribe_bars(ctx.strategy_config.symbols,
                             asset_type=AssetType.EQUITY, interval='1m')
          logger.info(f"[START] subscribed 1m bars for {ctx.strategy_config.symbols}")

      def on_bar(self, ctx, event):
          bar = event.data()                       # -> SigmaBar
          logger.debug(f"[BAR] {bar.symbol} {bar.time} close={bar.close:.2f} bought={self.bought}")
          if not self.bought and ctx.is_flat(bar.symbol):
              logger.info(f"[ENTRY] buying 100 {bar.symbol} at {bar.close:.2f}")
              ctx.buy_order(bar.symbol, quantity=100)
              self.bought = True

      def on_order(self, ctx, event):              # fills come HERE, not on_order_filled
          order = event.data()                     # -> SigmaOrder
          logger.info(f"[ORDER] {order.symbol} status={order.status} filled={order.is_filled}")
          if order.is_filled:
              fill = order.last_fill               # -> SigmaFill

  # run_backtest returns a Run HANDLE, not a report directly.
  run = hf.run_backtest(
      strategy_configs=[StrategyConfig(name='BuyAndHold', type='BuyAndHold')],
      symbols=['AAPL'],
      start_date='2025-08-01',
      end_date='2025-08-31',
      # declare the data source; the schema also sets the fill model (bars vs ticks)
      data_configs=[{'type': 'hiveq_historical', 'dataset': 'HIVEQ_US_EQ',
                     'schema': ['bars_1m']}],
  )

  print(f"run {run.run_id} task {run.task_id}")    # returns immediately (silent=True is the default)
  run.wait(progress=False)                         # block quietly until terminal — no live progress bar
  report = run.report()                            # -> PerformanceReport (the deliverable)
  print(report.return_stats.to_string())

Strategy Contract

A strategy is a plain Python class with per-event callback methods, each with the signature (self, ctx, event). Define only the handlers you need.

python
class MyStrategy:
      def __init__(self): ...               # per-strategy state
      def on_start(self, ctx, event): ...   # subscribe here
      def on_bar(self, ctx, event): ...     # event.data() -> SigmaBar
      def on_order(self, ctx, event): ...   # fills/rejects/cancels -> SigmaOrder
      def on_position(self, ctx, event):... # event.data() -> SigmaPosition
      def on_timer(self, ctx, event): ...   # event.data() -> TimerEventData
      def on_rollover(self, ctx, event):... # futures contract roll

Recognized callbacks

on_start, on_stop, on_bar, on_trade, on_quote, on_snap, on_order, on_position, on_timer, on_custom_data, on_index_price (alias on_index), on_rollover, on_imbalance, on_executor, on_security_event. Unknown method names are ignored. on_imbalance delivers an ImbalanceData from the auction imbalance feed — it needs the early_imbalance schema in data_configs; on_executor (EXECUTOR_EVENT) and on_security_event (SECURITY_EVENT) carry opaque payloads.

Required strategy instrumentation

Every strategy must create the HiveQ logger at module level and instrument every callback and decision branch. Use logger.debug(...) for per-bar state and condition checks; use logger.info(...) for signals, orders, and fills. The default engine level is WARNING, so healthy runs remain quiet even though the diagnostic context is already in the strategy.

python
from hiveq.flow.logger import logger as _get_logger
  logger = _get_logger()   # module level — never logging.getLogger(__name__)

  # Required coverage:
  # on_start -> subscriptions/config (INFO)
  # on_bar -> time, price, state, every condition outcome (DEBUG)
  # order placement + on_order -> side, quantity, reason, status/fill (INFO)

Order lifecycle contract (FIX-style: status ≠ events)

order.status is the order's state; events are the history. Terminal statuses (FILLED / CANCELED / REJECTED) are sticky — later request-level events never change them. The canonical race: you cancel a resting order but a fill lands while the cancel is in flight → you receive ORDER_FILLED first (the fill is never lost), then ORDER_CANCEL_REJECTED ("too late to cancel"). order.status reads FILLED on both.

  • Act on fills from the ORDER_FILLED event, using the cumulative filled_qty/leaves_qty (idempotent).
  • Treat ORDER_CANCEL_REJECTED / ORDER_MODIFY_REJECTED as informational no-ops when order.is_filled — do not count them toward reject/error limits.
  • ORDER_REJECTED is reserved for the order itself being rejected (entry rejects); it never fires for cancel/replace request rejections.
  • An order canceled after a partial fill ends CANCELED with filled_qty > 0.
  • Never infer disposition from the last event — use order.status / filled_qty.

Context API — ctx

Everything you do at runtime goes through ctx (a SigmaContext): subscribe to data, place & manage orders, query positions, read the clock, and run managed executors.

Subscriptions (call in on_start)

python
ctx.subscribe_bars(symbols, asset_type=AssetType.EQUITY, interval='1m')
  ctx.subscribe_trades(symbols)     # tick prints  (asset_type defaults to EQUITY)
  ctx.subscribe_quotes(symbols)     # bid/ask      (asset_type defaults to EQUITY)
  ctx.subscribe_option_snaps('SPY', expiration_type='0dte')  # '0dte' | 'YYYY-MM-DD' | datetime

  # futures: by symbol string, or the root= / contract= / continuous= selectors
  ctx.subscribe_futures_bars(symbols=['ES.c.0'], interval='1m')
  ctx.subscribe_futures_trades(symbols=['ES.c.0'])

  # custom / quant signals — data_id must match the 'id' in data_configs
  ctx.subscribe_data(data_id='mysignals')   # -> on_custom_data

Order placement

python
ctx.buy_order(symbol, quantity, order_type=OrderType.LIMIT, limit_price=px)
  ctx.sell_order(symbol, quantity)         # exit long
  ctx.short_order(symbol, quantity)        # open short

  # sizing helpers (off the current net position)
  ctx.close_position(symbol)               # flatten one symbol (no-op if flat)
  ctx.order_to_target(symbol, 100)         # signed target: +long / -short / 0
  ctx.flatten_all()                        # close every position in this strategy

Order management & queries

python
ctx.cancel_order(order_id)
  ctx.modify_order(order_id, limit_price=..., stop_price=...)
  ctx.cancel_all_orders(symbol)

  ctx.net_position(symbol)   # signed float (+long / -short / 0)
  ctx.is_flat(symbol)        # bool
  ctx.has_open_order(symbol) # bool
  ctx.now()                  # ET datetime   (time is ALWAYS U.S. Eastern)
  ctx.set_timer('poll', timedelta(minutes=1))   # fires on_timer

Executors — managed order working (POV / TWAP / VWAP / AUCTION)

An executor is a server-side algo that owns a target's full lifecycle — slicing the parent quantity, repricing, replacing/cancelling, and aggregating fills. Reach for one when execution quality matters (large sliced orders, live order-chasing, auction routing); for a simple one-shot market order, a direct buy_order is simpler.

python
params = ctx.build_executor_params(
      symbol='AAPL', quantity=1000, side='BUY',
      executor_type='POV', participate_pct=10,   # work at 10% of volume
  )
  handle = ctx.add_executor(params)              # start it (None if it failed)
  ctx.executor_state(handle)                     # "PARTIALLY_FILLED" | "FILLED" | ...

  # re-target IN PLACE — never add a second executor for the same target:
  eid = str(handle.executorID)
  ctx.replace_executor_params_by_id(eid, new_params)

Events & Payloads

Each callback receives an event; call event.data() for the payload. The concrete type depends on event.type:

python
event.type        # EventType  (branch on this)
  event.data()      # payload object (type depends on event.type)
  event.time        # ET datetime
  event.ts_event    # int nanoseconds

Payload types

  • SigmaBar — symbol, open, high, low, close, volume, interval, time
  • SigmaOrder — status, filled_qty, avg_px, is_filled, last_fill, commission
  • SigmaFill — last_qty, last_px, commission, liquidity_side (via order.last_fill)
  • SigmaPosition — quantity, avg_price, realized_pnl, unrealized_pnl, total_pnl
  • SigmaTradeTick / SigmaQuoteTick — tick prints & bid/ask
  • SigmaSnapData — options snapshot (strike, option_type, bid_px, ask_px)
  • SigmaCustomData — custom/CSV rows; read columns with column_data(name) (values are strings — cast yourself; quant signals arrive as a signal_json column)
  • Rollover — continuous_symbol, prev_contract, current_contract
  • ImbalanceData — auction imbalance record (NYSE/Arca/Nasdaq): symbol, side ('B'/'S'), imbalance (shares), paired_shares, ref_price?, near_price?, far_price?, clearing_price? (NYSE), cont_book_clearing_price?, closing_only_clearing_price?, market_imbalance? (Arca), cross_type? ('O'/'C', Nasdaq), transaction_type?, exchange?, ts_event, ts_init, time?/time_utc? — venue-specific fields are None when the venue doesn't publish them

Results & Reports

run_backtest(...) returns a Run handle — your single accessor for status and results, local or remote.

python
run.report()          # -> PerformanceReport
  run.positions()       # positions over time   (DataFrame)
  run.orders()          # complete order history (DataFrame)
  run.trades()          # executed trades        (DataFrame)
  run.fills()           # executed order fills   (DataFrame)
  run.daily_returns()   # daily P&L              (DataFrame)
  run.tearsheet()                      # -> '<run>.pdf' in the cwd (PDF, the default)
  run.tearsheet(output='report.html')  # explicit HTML file (format from the extension)

  # silent=True is the DEFAULT — run_backtest deploys and returns the Run immediately:
  run = hf.run_backtest(...)
  run.wait(progress=False)                          # block quietly until terminal (no tqdm bar)
  report = run.report()
  # reattach later from any machine (results outlive your Python process):
  report = hf.get_run(run.run_id).wait(progress=False).report()

PerformanceReport

python
report = run.report()
  print(report.return_stats.to_string())   # Sharpe, Sortino, vol, drawdown, win rate

  stats = report.summary_stats()           # dict: Sharpe, CAGR, Max Drawdown, ...
  html = report.create_tearsheet()         # inline HTML string (Jupyter/Marimo) — to save a file use run.tearsheet()

Function Registry

A versioned store of reusable Python callables that live on the platform. Write a function once, push_function it (with its requirements and a semver version), then fetch and run it from any script or machine by name and version.

python
import hiveq.flow as hf

  def zscore(series, window=20):
      """Rolling z-score."""
      import numpy as np
      return (series[-1] - np.mean(series[-window:])) / np.std(series[-window:])

  # register once...
  hf.push_function(zscore, version="1.0.0", requirements=["numpy"])

  # ...then load it back and run it on the platform from anywhere:
  fn = hf.load_function("zscore", version="1.0.0")
  hf.run_function(fn, [1, 2, 3, 4, 5], window=3, requirements=["numpy"])  # -> value

Markets & Examples

Equities, futures (incl. continuous contracts with automatic rollover), options, and your own custom data feeds. Each is demonstrated by a complete, runnable example in the SDK's examples/ directory.

Equities
intraday_momentum_equity.py
SMA crossover, per-symbol state, EOD-flat
Futures
futures_continuous_rollover.py
continuous ES.c.0, enable_auto_rollover, on_rollover
Options (0DTE)
options_0dte_iron_condor.py
subscribe_option_snaps, multi-leg structure
Custom data
custom_data.py
bring-your-own CSV feed → on_custom_data
Orders & brackets
bracket_stop_take_profit.py
stop+target children, OCO emulation
Executors
executor_pov_sliced.py
POV executor, re-target in place
Pairs / stat-arb
pairs_stat_arb.py
rolling z-score spread, short_order
Scheduling
timers_scheduling.py
set_timer + ctx.now() ET checks
python
# Futures: subscribe to a continuous contract; rollover is automatic.
  class Breakout:
      def on_start(self, ctx, event):
          ctx.subscribe_futures_bars(symbols=['ES.c.0'], interval='1m')
      def on_rollover(self, ctx, event):
          roll = event.data()   # Rollover: prev_contract -> current_contract

  run = hf.run_backtest(
      strategy_configs=[StrategyConfig(name='Breakout', type='Breakout')],
      symbols=['ES.c.0'],
      start_date='2024-01-01', end_date='2024-03-01',
      data_configs=[{'type': 'hiveq_historical', 'dataset': 'HIVEQ_US_FUT',
                     'schema': ['bars_1m']}],
      backtest_config=BacktestConfig(enable_auto_rollover=True),
  )

Enums & Config

Imports cheat-sheet

python
import hiveq.flow as hf
  from hiveq.flow import StrategyConfig, BacktestConfig, EngineConfig, AssetType, get_run
  from hiveq.flow.config import EventType, EventLogType, OMSType
  from hiveq.flow.logger import logger as _get_logger
  from hiveq.flow.trading_types import OrderType, OrderSide, OrderStatus, MarketCenter
  from hiveq.flow.trading.price_utils import adjust_tick_size, get_min_tick

Key enums

  • AssetType: EQUITY · OPTIONS · FUTURES · CRYPTO · INDEX
  • OrderType: MARKET · LIMIT · STOP · STOP_LIMIT · MOO · MOC · LOO · LOC
  • OrderSide: BUY · SELL · OrderStatus: PENDING · SUBMITTED · ACCEPTED · REJECTED · CANCELED · FILLED · PARTIALLY_FILLED

BacktestConfig (key fields)

python
BacktestConfig(
      initial_capital=1_000_000.0,
      commission=0.001,
      equity_fee=0.0011,        # per share
      futures_fee=0.5,          # per contract
      session_start=None,       # asset default: equity 04:00, futures 18:00 ET
      session_end=None,         # asset default: equity 18:30, futures 17:00 ET
      enable_auto_rollover=False,
      auto_flatten_at_close=False,  # force-close non-option positions at session close
      enable_tca=False,
  )

Pitfalls & Patterns

HiveQ Flow is deliberately lean on authoring conveniences — these are the things that are easy to get wrong, and the idioms to handle them.

  • No built-in indicators or history buffer — keep your own collections.deque window and compute with numpy/pandas.
  • No native brackets/OCO — place protective child orders on fill in on_order and cancel siblings yourself.
  • No percent-of-equity sizing — size in fixed quantity (or off ctx.portfolio().equity and a price you track).
  • Timestamps ts_event/ts_init are nanoseconds — use .time / ctx.now() for datetimes.
  • Set symbols/start_date/end_date in one place (top-level args OR BacktestConfig), not both.
  • On a continuous-futures subscription, bar.symbol is the resolved outright contract (e.g. ESZ5), never the ES.c.0 string you subscribed with — so if bar.symbol != 'ES.c.0' silently drops every bar. Key off the root, or place orders on bar.symbol directly.
  • End-of-day flatten is opt-in, not automatic — set BacktestConfig(auto_flatten_at_close=True) to force-close non-option positions at session close (options settle automatically regardless).

Bracket / stop-loss + take-profit

python
def on_order(self, ctx, event):
      o = event.data()
      if o.is_filled and o.symbol == self.entry_symbol and not self.protected:
          entry = o.avg_px
          ctx.sell_order(o.symbol, quantity=o.filled_qty,
                         order_type=OrderType.STOP,  stop_price=entry * 0.98)
          ctx.sell_order(o.symbol, quantity=o.filled_qty,
                         order_type=OrderType.LIMIT, limit_price=entry * 1.04)
          self.protected = True
      # when one leg fills, cancel_all_orders(symbol) to emulate OCO

Ready to test your strategy?

Write the strategy. Run the backtest. Inspect the full result.

Revisions

  • 2026-07-23v1.0.0Synced to hiveq_sdk main at d4acc3b: added run.fills(), consistent remote report backfilling for positions/orders/trades/fills, and the 04:00–18:30 ET equity-session default required for closing-cross fills.
  • 2026-07-21v0.3.7Synced to the published 0.3.7 contract: mandatory HiveQ logger instrumentation, explicit data_configs, quiet run.wait(progress=False), report-first output, diagnostic-only log retrieval, and zero-trade run validation.
  • 2026-07-16v0.3.6Re-synced to the consolidated docs/llms.txt: added on_imbalance / ImbalanceData, the FIX-style order-lifecycle contract (status vs events, cancel/replace race), silent-by-default run_backtest (run.wait(progress=False) → run.report()), and clarified there is no subscribe_futures_quotes.
  • 2026-07-08v0.3.6Synced to SDK 0.3.6 — auto-flatten-at-close option, continuous-futures bar.symbol pitfall, and clarified tearsheet file vs. inline API.
  • 2026-07-07v0.3.5Synced to SDK 0.3.5 — automatic browser sign-in (no manual API key) and tearsheet exports by file extension.
  • 2026-06-10v0.3.4Product overview added; AssetType re-exported from hiveq.flow.config.
  • 2026-06-09v0.3.4First published API reference.