TWAP Orders
Time-Weighted Average Price (TWAP) orders split a large parent order into smaller suborders executed at regular intervals, minimizing market impact for institutional-size trades.
Parameters
| Parameter | Default | Description |
|---|---|---|
total_size | Required | Total quantity to execute |
duration_secs | Required | Total execution window in seconds |
suborder_interval_secs | 30 seconds | Time between each suborder |
max_slippage_bps | 300 (3%) | Maximum allowed slippage per suborder |
max_catchup_multiplier | 3x | Maximum multiplier for catch-up suborders |
reduce_only | false | If true, suborders only reduce existing positions |
How It Works
Suborder Generation
The TWAP engine ticks at each suborder_interval_secs boundary and generates a suborder sized to match the expected cumulative fill rate:
normal_suborder_size = total_size * suborder_interval / durationExample: A 30,000-unit order over 300 seconds (5 minutes) with 30-second intervals:
normal_suborder = 30,000 * 30 / 300 = 3,000 units per suborder
total_suborders = 300 / 30 = 10 subordersCatch-Up Logic
If a suborder fails to fill (due to slippage limits or insufficient liquidity), the TWAP engine tracks the deficit between expected and actual fills. On the next tick, it attempts to catch up:
deficit = expected_cumulative_fill - actual_dispatched_size
suborder_size = min(deficit, max_catchup_multiplier * normal_suborder_size, remaining_size)With a 3x catch-up multiplier and a normal suborder of 3,000 units, a single catch-up suborder can be up to 9,000 units.
Example sequence:
| Time | Slots Elapsed | Target | Dispatched | Deficit | Suborder Size |
|---|---|---|---|---|---|
| t+0s | 1 | 3,000 | 0 | 3,000 | 3,000 |
| t+30s | 2 | 6,000 | 3,000 | 3,000 | 3,000 |
| t+120s | 5 (skipped 2) | 15,000 | 6,000 | 9,000 | 9,000 (capped at 3x) |
Slippage Protection
Each suborder is submitted with a price limit derived from the max_slippage_bps parameter:
- For buy suborders:
limit_price = reference_price * (1 + max_slippage_bps / 10,000) - For sell suborders:
limit_price = reference_price * (1 - max_slippage_bps / 10,000)
If the market price exceeds the slippage limit, the suborder is skipped and the deficit accumulates for the next catch-up attempt.
TWAP Lifecycle
States
| Status | Description |
|---|---|
| Active | TWAP is running and generating suborders |
| Complete | All size has been dispatched (remaining_size = 0) |
| Cancelled | User cancelled the TWAP before completion |
Creation
A TWAP order is created with validation:
total_sizemust be greater than 0duration_secsmust be greater than 0 and at least equal tosuborder_interval_secsmax_slippage_bpsmust be greater than 0
Cancellation
Only the owner can cancel an active TWAP. Cancellation:
- Stops all future suborder generation
- Does not affect previously dispatched (and potentially filled) suborders
- Cannot be undone — cancelled TWAPs cannot be restarted
Completion
A TWAP completes automatically when remaining_size reaches 0. The status transitions to Complete and no further suborders are generated.
Use Cases
- Large position entry/exit: Spread a $10M position across 30 minutes to minimize slippage
- Algorithmic execution: Automate execution without constant manual intervention
- Benchmark tracking: Execute at a time-weighted average price for compliance or portfolio rebalancing
Multiple Concurrent TWAPs
Users can have multiple active TWAP orders simultaneously across different markets. Each TWAP operates independently with its own timer, catch-up state, and completion tracking.