Skip to content

TWAP - Time-Weighted Average Price Execution

TL;DR

  • TWAP splits a large order into smaller slices executed at regular time intervals, reducing market impact
  • How it works: You specify a total quantity, duration, and interval. The system calculates interval_count = duration / interval and interval_quantity = quantity / interval_count, then places a market order each interval
  • Slippage protection enforces a maximum price deviation per slice: either percent-based (0.01%--9.99%) or tick-size-based (1--10,000 ticks from the best price). If slippage is exceeded, the entire strategy cancels
  • Randomization mode adds up to +/-20% variance to each slice quantity, making your execution pattern harder to detect. The final interval is adjusted to hit the exact total
  • Auto-cancellation triggers on slippage exceeded, insufficient funds/margin, insufficient liquidity, liquidation risk, and other error conditions
  • Supported on both spot and perpetual markets with optional reduce-only and auto-borrow/auto-lend modifiers
  • Use case: You want to buy or sell a large position over minutes or hours without moving the market against yourself

1. What Is TWAP and Why Use It?

Time-Weighted Average Price (TWAP) is an execution algorithm that breaks a large order into equal-sized slices and executes them at fixed time intervals. The goal is to achieve an average execution price close to the market's time-weighted average over the execution window.

The Problem: Market Impact

When you place a single large market order, you "walk the book" -- consuming liquidity at progressively worse prices. A 100 SOL market buy might look like this:

Single Market Order: Buy 100 SOL

Order Book Asks:
  $150.00 (20 SOL)  ← filled
  $150.05 (30 SOL)  ← filled
  $150.15 (25 SOL)  ← filled
  $150.40 (25 SOL)  ← filled

Result: 100 SOL filled, average price $150.14
Slippage from best ask: $0.14 per SOL = 0.093%
Total extra cost: $14.00

That 0.09% might seem small, but on a $1M order it is $930 of slippage. Worse, other participants see the price spike and front-run you, pushing costs even higher.

The TWAP Solution

Instead of one large order, TWAP spreads execution over time:

TWAP: Buy 100 SOL over 10 minutes, 1-minute intervals

Minute  1: Buy 10 SOL at market  → filled @ $150.01
Minute  2: Buy 10 SOL at market  → filled @ $149.98
Minute  3: Buy 10 SOL at market  → filled @ $150.05
Minute  4: Buy 10 SOL at market  → filled @ $150.02
Minute  5: Buy 10 SOL at market  → filled @ $149.95
Minute  6: Buy 10 SOL at market  → filled @ $150.08
Minute  7: Buy 10 SOL at market  → filled @ $150.00
Minute  8: Buy 10 SOL at market  → filled @ $150.03
Minute  9: Buy 10 SOL at market  → filled @ $149.97
Minute 10: Buy 10 SOL at market  → filled @ $150.01

Average price: $150.01

Each 10 SOL slice barely moves the book. The order book has time to replenish liquidity between slices. Your average price reflects the true market price over the window, not a one-time liquidity hole.

When TWAP Makes Sense

SituationUse TWAP?Why
Large order relative to book depthYesSplits impact across time
Position exit over hoursYesAvoids signaling a dump
Small order, deep bookNoSingle market order is fine
Time-sensitive exit (liquidation risk)NoNeed immediate execution
Volatile market, unclear directionMaybeTWAP gives you average price, but market may trend against you

2. How Backpack's TWAP Works

Backpack implements TWAP as a scheduled strategy -- a server-side algorithm that runs in the exchange's execution engine. You submit the strategy once, and the system manages slicing, scheduling, and order placement automatically.

Architecture Overview

┌─────────────────────────────────────────────────────────┐
│                     Your API Request                     │
│   POST /api/v1/strategy  (quantity, duration, interval)  │
└──────────────────────────┬──────────────────────────────┘


┌─────────────────────────────────────────────────────────┐
│                   Validation Layer                        │
│   - Parameter bounds check                               │
│   - Interval divides duration evenly                     │
│   - Slippage tolerance valid                             │
│   - Account has sufficient funds/margin                  │
└──────────────────────────┬──────────────────────────────┘


┌─────────────────────────────────────────────────────────┐
│                   Strategy Crank                         │
│   Runs every 500ms, checks all active strategies         │
│                                                          │
│   For each strategy:                                     │
│     1. Is it time for the next slice?                    │
│     2. Calculate slice quantity (with randomization?)     │
│     3. Place market order with slippage tolerance         │
│     4. Record fill, advance to next interval             │
│     5. If final interval → execute remaining quantity     │
└──────────────────────────┬──────────────────────────────┘


┌─────────────────────────────────────────────────────────┐
│                   Matching Engine                         │
│   Market order fills against the order book              │
│   Slippage tolerance enforced as a limit price           │
└─────────────────────────────────────────────────────────┘

The Execution Crank

The strategy crank is a background process that polls every 500 milliseconds. On each tick, it checks all active TWAP strategies and determines if any are due for their next slice. This means your interval timing has up to 500ms of jitter -- an order scheduled at t=60s might execute at t=60.0s to t=60.5s. This jitter is negligible for the minute-scale intervals TWAP typically uses.


3. Parameters

When creating a TWAP strategy, you provide the following parameters:

Required Parameters

ParameterTypeDescription
symbolstringTrading pair (e.g., SOL_USDC, BTC_USDC_PERP)
sidestringBid (buy) or Ask (sell)
quantitydecimalTotal quantity to execute in base asset units
durationintegerTotal execution window in seconds
intervalintegerTime between slices in seconds
slippageToleranceobjectMaximum allowed price deviation per slice

Slippage Tolerance (one of two formats)

Percent-based:

json
{
  "slippageTolerance": {
    "percent": "0.50"
  }
}

Allowed range: 0.01% to 9.99%. Each slice's market order is capped at a price that is percent% worse than the best available price at the time of execution.

Tick-size-based:

json
{
  "slippageTolerance": {
    "ticks": 5
  }
}

Allowed range: 1 to 10,000 ticks. Each slice's market order is capped at the best price plus (or minus, for sells) the specified number of tick increments for that market.

Optional Parameters

ParameterTypeDefaultDescription
randomizedIntervalQuantitybooleanfalseEnable +/-20% randomization on slice quantities
reduceOnlybooleanfalseOnly reduce an existing position (perp markets)
autoBorrowbooleanfalseBorrow assets if needed (spot, requires margin)
autoLendbooleanfalseLend proceeds automatically

4. The Math: Interval Slicing

TWAP divides your order into evenly sized slices using straightforward arithmetic.

Core Formulas

interval_count    = duration / interval
interval_quantity = quantity / interval_count

Constraint: duration must be evenly divisible by interval. If duration = 600s and interval = 90s, the request is rejected because 600 / 90 = 6.67 (not a whole number).

Worked Example

Parameters:
  quantity  = 100 SOL
  duration  = 600 seconds (10 minutes)
  interval  = 60 seconds  (1 minute)

Calculation:
  interval_count    = 600 / 60 = 10
  interval_quantity = 100 / 10 = 10 SOL

Execution Plan:
  Slice  1 at t=0:00   → Market buy 10 SOL
  Slice  2 at t=1:00   → Market buy 10 SOL
  Slice  3 at t=2:00   → Market buy 10 SOL
  Slice  4 at t=3:00   → Market buy 10 SOL
  Slice  5 at t=4:00   → Market buy 10 SOL
  Slice  6 at t=5:00   → Market buy 10 SOL
  Slice  7 at t=6:00   → Market buy 10 SOL
  Slice  8 at t=7:00   → Market buy 10 SOL
  Slice  9 at t=8:00   → Market buy 10 SOL
  Slice 10 at t=9:00   → Market buy 10 SOL
                          ─────────────────
  Total:                  100 SOL over 10 minutes

The first slice executes immediately when the strategy starts (t=0). The last slice executes at duration - interval (t=9:00 in this example), so the entire execution completes within the specified duration window.

Another Example: Short Duration, Tight Intervals

Parameters:
  quantity  = 5 BTC
  duration  = 120 seconds (2 minutes)
  interval  = 30 seconds

Calculation:
  interval_count    = 120 / 30 = 4
  interval_quantity = 5 / 4 = 1.25 BTC

Execution Plan:
  Slice 1 at t=0:00  → Market sell 1.25 BTC
  Slice 2 at t=0:30  → Market sell 1.25 BTC
  Slice 3 at t=1:00  → Market sell 1.25 BTC
  Slice 4 at t=1:30  → Market sell 1.25 BTC
                        ─────────────────────
  Total:                5 BTC over 2 minutes

5. Randomization Mode

By default, every slice is exactly interval_quantity. This creates a predictable, detectable pattern: the same quantity hitting the market at the same interval. Sophisticated participants can detect this and front-run your remaining slices.

How Randomization Works

When randomizedIntervalQuantity is enabled, each slice quantity is randomly adjusted by up to +/-20% from the base interval_quantity:

randomized_quantity = interval_quantity * (1 + random(-0.20, +0.20))

Worked Example with Randomization

Parameters:
  quantity = 100 SOL, duration = 600s, interval = 60s
  randomizedIntervalQuantity = true

  interval_quantity = 10 SOL
  Randomization range: 8.0 SOL to 12.0 SOL per slice

Possible Execution:
  Slice  1: 10.0 SOL  (first slice, no randomization)
  Slice  2: 11.4 SOL  (+14%)
  Slice  3:  8.3 SOL  (-17%)
  Slice  4: 11.9 SOL  (+19%)
  Slice  5:  9.1 SOL  ( -9%)
  Slice  6: 10.8 SOL  ( +8%)
  Slice  7:  8.6 SOL  (-14%)
  Slice  8: 11.2 SOL  (+12%)
  Slice  9:  9.5 SOL  ( -5%)
  ──────────────────────────
  Subtotal: 90.8 SOL  (after 9 slices)

  Slice 10:  9.2 SOL  ← Exact remainder to hit 100 SOL total
  ──────────────────────────
  Total:    100.0 SOL  ✓

The Final Interval Rule

The final slice always executes the exact remaining quantity, regardless of randomization. This guarantees that you get your full requested quantity. If randomized slices happened to run slightly above or below the expected cumulative total, the last slice compensates.

Why Randomize?

Without randomization:                With randomization:

Volume                                Volume
  │                                     │
  │ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██       │    ██       ██
  │ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██       │ ██ ██    ██ ██ ██    ██
  │ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██       │ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
  └──────────────────────────────       └──────────────────────────────
    1  2  3  4  5  6  7  8  9  10         1  2  3  4  5  6  7  8  9  10
    Interval                              Interval

  Pattern: Obvious                      Pattern: Harder to detect

Randomization makes your TWAP less vulnerable to front-running by other participants who monitor for repetitive execution patterns.


6. Slippage Protection

Each slice in a TWAP strategy is a market order, but market orders can fill at arbitrarily bad prices if the book is thin. Slippage tolerance acts as a safety net: it converts each market order into a limit order at the worst acceptable price.

Percent-Based Slippage

For a buy order with percent: 0.50 (0.50% tolerance):

best_ask = $150.00
max_buy_price = $150.00 * (1 + 0.0050) = $150.75

The slice's market order becomes: Limit BUY at $150.75
  → Fills at $150.00-$150.75 (whatever is available)
  → If the book is empty below $150.75, partial fill or no fill

For a sell order with percent: 0.50:

best_bid = $150.00
min_sell_price = $150.00 * (1 - 0.0050) = $149.25

The slice's market order becomes: Limit SELL at $149.25
  → Fills at $149.25-$150.00

Valid range: 0.01% to 9.99%. Values outside this range are rejected at submission time.

Tick-Size-Based Slippage

Tick-based slippage uses the market's minimum price increment (tick size) instead of a percentage.

For a buy order on SOL_USDC (tick size = $0.01) with ticks: 5:

best_ask = $150.00
max_buy_price = $150.00 + (5 * $0.01) = $150.05

The slice's market order becomes: Limit BUY at $150.05

For a sell order with ticks: 5:

best_bid = $150.00
min_sell_price = $150.00 - (5 * $0.01) = $149.95

The slice's market order becomes: Limit SELL at $149.95

Valid range: 1 to 10,000 ticks.

Comparison: Percent vs Tick-Size

AspectPercent-BasedTick-Size-Based
Scales with priceYes (0.5% of $100 = $0.50; 0.5% of $100,000 = $500)No (5 ticks always = 5 * tick_size)
Best forAssets at varying price levelsPrecise control on a single market
Intuition"I accept up to X% worse""I accept up to N price levels worse"
Risk on volatile assetsScales proportionallyFixed absolute limit

What Happens When Slippage Is Exceeded

If a slice cannot fill within the slippage tolerance, the entire TWAP strategy is cancelled -- not just the one slice. This is a deliberate safety design: if market conditions have deteriorated enough that a single slice cannot execute within tolerance, continuing to place more slices is likely to result in poor fills.

Slice 5 of 10: Buy 10 SOL
  best_ask = $155.00  (market moved sharply)
  tolerance = 0.50%
  max_price = $155.78

  Order book asks: $156.00 (all liquidity above tolerance)
  → Slice fails: SlippageToleranceExceeded
  → Entire strategy cancelled
  → Slices 6-10 will NOT execute
  → You have 40 SOL filled from slices 1-4

7. Auto-Cancellation Reasons

A TWAP strategy can be cancelled by the user at any time, but the system will also automatically cancel the strategy if it encounters conditions that make continued execution unsafe or impossible.

Cancellation Reasons

ReasonDescriptionWhat to Do
SlippageToleranceExceededA slice could not fill within your specified toleranceWiden tolerance or wait for calmer conditions
InsufficientFundsAccount lacks the balance to fund the next sliceDeposit more funds or reduce remaining quantity
InsufficientMarginNext slice would breach margin requirements (perp)Add collateral or reduce position size
InsufficientLiquidityOrder book is empty or too thin for the sliceWait for deeper liquidity
LiquidationAccount is at risk of or undergoing liquidationAddress margin health immediately
UserCancelledYou manually cancelled the strategy via API or UIN/A

Partial Completion

When a strategy is auto-cancelled, all slices that already filled remain filled. Cancellation stops future slices but does not reverse past executions. Your resulting position reflects however many slices completed successfully.

Example: 10-slice TWAP, cancelled after slice 6

  Slices 1-6: Filled (60 SOL purchased)
  Slices 7-10: Not executed

  Your position: 60 SOL (not 0, not 100)
  Strategy status: Cancelled (reason: SlippageToleranceExceeded)

8. Practical Examples

Example 1: Large Spot Buy

You want to accumulate 500 SOL without spiking the price.

Strategy:
  symbol:    SOL_USDC
  side:      Bid (buy)
  quantity:  500 SOL
  duration:  1800 seconds (30 minutes)
  interval:  180 seconds  (3 minutes)
  slippageTolerance: { percent: "1.00" }
  randomizedIntervalQuantity: true

Calculation:
  interval_count    = 1800 / 180 = 10
  interval_quantity = 500 / 10 = 50 SOL per slice

Execution (randomized):
  t=0:00   Buy ~50 SOL (first slice, exact)
  t=3:00   Buy ~42 SOL
  t=6:00   Buy ~58 SOL
  t=9:00   Buy ~47 SOL
  ...
  t=27:00  Buy [remainder] SOL  ← exact amount to total 500

Each slice:
  - Checks best ask price
  - Sets limit price = best_ask * 1.01
  - Fills up to that price
  - If cannot fill → strategy cancels

Example 2: Perp Position Exit with Reduce-Only

You are long 20 BTC on the perpetual market and want to unwind over an hour without signaling a large sell.

Strategy:
  symbol:    BTC_USDC_PERP
  side:      Ask (sell)
  quantity:  20 BTC
  duration:  3600 seconds (1 hour)
  interval:  300 seconds  (5 minutes)
  slippageTolerance: { ticks: 10 }
  reduceOnly: true

Calculation:
  interval_count    = 3600 / 300 = 12
  interval_quantity = 20 / 12 = 1.667 BTC per slice

Key behavior:
  - reduceOnly ensures the strategy can only close your long, never flip short
  - If your position is closed early (e.g., by a separate order), the strategy
    will cancel because reduce-only has nothing to reduce
  - tick-based slippage: each sell can go up to 10 ticks below best bid

Example 3: Quick Execution with Tight Slippage

You want to sell 1,000 USDC worth of a token quickly but still split it up.

Strategy:
  symbol:    TOKEN_USDC
  side:      Ask (sell)
  quantity:  10,000 TOKEN
  duration:  60 seconds (1 minute)
  interval:  10 seconds
  slippageTolerance: { percent: "0.10" }

Calculation:
  interval_count    = 60 / 10 = 6
  interval_quantity = 10,000 / 6 = 1,666.67 TOKEN per slice

Note: With tight 0.10% tolerance on a 10-second interval, any sudden spread
widening will cancel the strategy. This configuration favors liquid markets.

9. TWAP vs Regular Orders: When to Use Each

Decision Framework

Order Size vs Book Depth:

  Order < 5% of top-of-book depth
  └─ Single market or limit order is fine

  Order = 5-20% of top-of-book depth
  └─ Consider TWAP if you can wait
  └─ Limit order works if you're patient

  Order > 20% of top-of-book depth
  └─ TWAP strongly recommended
  └─ Single market order will suffer significant slippage

Comparison Table

FactorMarket OrderLimit OrderTWAP
SpeedInstantUncertainGradual (minutes to hours)
Price certaintyNoneExact priceAverage over time window
Market impactHigh for large ordersNone (passive)Low (spread across time)
Execution guaranteeHighLowModerate (can be cancelled)
ComplexityNoneNoneMust choose duration, interval, tolerance
Best forSmall/urgent ordersPrice-sensitive entriesLarge orders in size
RiskSlippageNever fillsPartial fill if cancelled; market trends against you

When NOT to Use TWAP

  • Emergency exits: If you are being liquidated or need to exit now, a market order is faster and simpler.
  • Illiquid markets: If the order book is consistently thin, TWAP slices will each struggle with slippage. A single limit order at your target price may be more effective.
  • Trending markets: TWAP gives you the average price. If the market is trending strongly against you (rising when you are buying), you will get progressively worse fills. A single immediate execution could be cheaper.
  • Very small orders: If your order is small relative to available liquidity, the overhead of a TWAP strategy is unnecessary.

10. Spot and Perpetual Market Support

TWAP works on both spot and perpetual futures markets on Backpack, with slightly different behaviors and options for each.

Spot Markets

On spot markets, TWAP places actual buy or sell orders for the underlying asset:

  • Buying: Each slice purchases base asset (e.g., SOL) using quote asset (e.g., USDC). You need sufficient quote balance or auto-borrow enabled.
  • Selling: Each slice sells base asset for quote asset. You need sufficient base balance.
  • autoBorrow: If enabled, the system borrows the needed asset from the lending pool if your balance is insufficient for a slice. Interest accrues on borrowed amounts. See Borrow & Lend for details.
  • autoLend: If enabled, proceeds from sell slices are automatically lent to the lending pool to earn interest.

Perpetual Markets

On perpetual markets, TWAP opens or closes futures positions:

  • Buying (Bid): Each slice goes long or reduces a short position.
  • Selling (Ask): Each slice goes short or reduces a long position.
  • reduceOnly: When enabled, the strategy can only reduce an existing position. It will not open a new position or flip your side. If the position is fully closed before the strategy completes, the remaining slices are cancelled.
  • Margin: Each slice requires sufficient margin. If margin becomes insufficient mid-execution, the strategy auto-cancels.

Feature Matrix

FeatureSpotPerpetual
Buy / SellYesYes (Long / Short)
Slippage toleranceYesYes
RandomizationYesYes
Reduce-onlyNoYes
Auto-borrowYesNo
Auto-lendYesNo
Margin requirementsNo (balance-based)Yes
Funding rate impactNoYes (for longer durations)

11. API Reference

Create a TWAP Strategy

POST /api/v1/strategy

Request body:

json
{
  "symbol": "SOL_USDC",
  "side": "Bid",
  "quantity": "100",
  "duration": 600,
  "interval": 60,
  "slippageTolerance": {
    "percent": "0.50"
  },
  "randomizedIntervalQuantity": false,
  "reduceOnly": false,
  "autoBorrow": false,
  "autoLend": false
}

Get Strategy Status

GET /api/v1/strategy/:strategyId

Returns the current state of the strategy, including how many slices have executed, the quantity filled so far, and the current status (active, completed, or cancelled with reason).

Cancel a Strategy

DELETE /api/v1/strategy/:strategyId

Immediately stops the strategy. Slices already filled are not reversed. Remaining slices will not execute.


12. Risks and Edge Cases

TWAP is not an opinion on direction -- it gives you the average price over time. If the market moves strongly against you during execution, TWAP will dutifully fill at worse and worse prices:

Scenario: Buying 100 SOL over 10 minutes while SOL rallies

  Slice  1: Buy 10 @ $150.00
  Slice  2: Buy 10 @ $150.50
  Slice  3: Buy 10 @ $151.20
  ...
  Slice 10: Buy 10 @ $155.00

  Average: $152.50

  If you had bought all 100 at once: ~$150.20
  TWAP cost you an extra $2.30/SOL = $230 total

This is the fundamental trade-off: TWAP protects against impact but exposes you to drift. It works best in range-bound or mean-reverting markets.

Partial Fills and Cancellation

If the strategy cancels partway through, you are left with a partial position. Plan for this:

  • On perp markets, a partial long/short position still requires margin and is subject to liquidation.
  • On spot markets, you may hold a partial base asset position that you did not intend to hold indefinitely.

Thin Order Books

If the order book is consistently thin, many slices may fail slippage checks, leading to early cancellation. Check the order book depth for your target market before starting a TWAP. A good rule of thumb: each slice quantity should be less than the typical top-of-book depth on the side you are trading.

Crank Timing

The strategy crank runs every 500ms. For very short intervals (e.g., 10 seconds), the 500ms polling cycle introduces minimal jitter. For intervals of 1 second or less (not recommended), the jitter could be significant relative to the interval.


Summary

TWAP is Backpack's execution algorithm for splitting large orders into time-distributed slices. The key mechanics:

  1. You define the total quantity, execution window (duration), and slice frequency (interval)
  2. The system calculates interval_count = duration / interval and places one market order per interval
  3. Slippage tolerance protects each slice from filling at unacceptable prices (percent-based or tick-based)
  4. Randomization (optional) varies slice sizes by +/-20% to disguise your execution pattern
  5. Auto-cancellation halts the strategy if any slice encounters an error condition (slippage, funds, margin, liquidity, liquidation)
  6. Partial fills are kept -- cancellation stops future slices but does not reverse past ones

Use TWAP when your order is large relative to available liquidity and you can afford to execute over minutes or hours. Use regular market or limit orders when speed matters more than impact, or when your order is small enough that slippage is negligible.