Skip to main content

Horizon Execution Algorithms

Horizon ships with three execution algorithms for splitting large orders into smaller child orders: TWAP, VWAP, and Iceberg. All are implemented in pure Python, use engine.submit_order() internally, and do not participate in cancel-before-requote.
Execution algorithms are designed for situations where you need to fill a large order with minimal market impact. They manage their own child orders and should not be mixed with manual order management for the same market.

Overview

TWAP

Time-Weighted Average Price. Splits the order into equal slices submitted at regular intervals over a duration.

VWAP

Volume-Weighted Average Price. Slices the order proportionally based on a volume profile (historical or predicted).

Iceberg

Shows only a small visible portion of the full order. Automatically replenishes when the visible portion fills.

Base Class: ExecAlgo

All execution algorithms inherit from ExecAlgo and share a common interface.

Usage Pattern

Every algo follows the same lifecycle:
1

Create the algo with engine reference and parameters

2

Start with an OrderRequest

3

Call on_tick() each cycle

4

Check completion


TWAP (Time-Weighted Average Price)

Splits the total order into num_slices equal pieces and submits one slice at each interval over the specified duration.

Constructor

How It Works

  1. The total size is divided into num_slices equal parts.
  2. The interval between slices is duration_secs / num_slices.
  3. On each on_tick(), if enough time has elapsed since the last slice, a new child order is submitted at the current market price.
  4. The algo is complete when all slices have been submitted.

Full Example

Choose num_slices based on market liquidity. More slices means smaller individual orders but more time in the market. For thin prediction markets, 5-10 slices is usually sufficient.

VWAP (Volume-Weighted Average Price)

Splits the total order proportionally according to a volume profile. Heavier slices are placed during high-volume periods.

Constructor

How It Works

  1. The volume_profile is normalized so weights sum to 1.0.
  2. Each slice’s size is total_size * normalized_weight[i].
  3. Slices are submitted at regular intervals (duration_secs / len(volume_profile)).
  4. Heavier slices are placed during time windows with higher expected volume.

Full Example

You can derive volume_profile from historical trade data. Use hz.backtest() results or exchange trade history to build a realistic intraday volume curve.

Iceberg

Shows only a small portion (show_size) of the total order at any time. When the visible portion is filled, a new visible order is automatically submitted until the full size is complete.

Constructor

How It Works

  1. A child order of size min(show_size, remaining_size) is submitted.
  2. On each on_tick(), the algo checks if the current visible order has been filled.
  3. If filled, a new visible order is submitted with the next chunk.
  4. The algo is complete when the entire original size has been filled.

Full Example

The iceberg algo relies on fills being drained from the exchange. Make sure the engine’s fill polling is active. In hz.run(), this happens automatically. In manual loops, call engine.tick() or engine.drain_fills() before on_tick().

Using Algos in hz.run()

Execution algorithms work best when managed inside a pipeline function that has access to the engine.

Comparison

Use TWAP when you want to spread execution evenly over time and don’t have a strong opinion about volume patterns. Good for markets with consistent liquidity throughout the day.
Use VWAP when you have historical volume data and want to minimize market impact by trading more during high-volume periods. Best for markets with predictable volume patterns.
Use Iceberg when you want to hide the full size of your order from other participants. Best for markets where showing a large order would move the price against you.