---
title: "Queue Position Modeling"
description: "Limit order queue position estimation, fill probability, and expected fill time for prediction market order books."
icon: "list-ol"
---

<Warning>
  **Ultra Feature.** Requires an Ultra subscription. [Get started at api.mathematicalcompany.com](https://api.mathematicalcompany.com)
</Warning>

<Tip>
  **What is this?** When you place a limit order, you join a queue. The queue model estimates your probability of getting filled by tracking how many orders are ahead of you and how fast orders arrive, cancel, and fill. Use it to decide whether to stay in the queue or cross the spread, and to set realistic fill expectations for your limit orders.
</Tip>

# Queue Position Modeling

Horizon provides a queue position model for estimating fill probabilities and expected fill times for limit orders in prediction market order books. The model tracks your position in the queue, accounts for order arrivals, cancellations, and executions ahead of you, and provides real-time probability estimates. All computation runs in Rust.

<CardGroup cols={2}>
  <Card title="Queue Tracking" icon="list-ol">
    Track your position in the limit order book queue with order arrival and cancellation updates.
  </Card>
  <Card title="Fill Probability" icon="percent">
    Estimate the probability of your order being filled within a time horizon.
  </Card>
  <Card title="Expected Fill Time" icon="clock">
    Compute the expected time until your order reaches the front of the queue and gets filled.
  </Card>
  <Card title="Pipeline Integration" icon="diagram-project">
    `hz.queue_tracker()` provides live queue analytics within `hz.run()`.
  </Card>
</CardGroup>

---

## Why Queue Position Matters

In prediction markets with limit order books, fill probability depends critically on your position in the queue. Market makers who post limit orders need to know:

1. **Fill probability**: Will this order execute before I need to cancel it?
2. **Expected fill time**: How long will I wait? Is it worth the spread?
3. **Queue dynamics**: Are cancellations ahead of me improving my position, or are new arrivals pushing me back?

The queue model answers these questions by combining Poisson arrival/cancellation processes with your observed queue position.

<Note>
  Queue position modeling is most valuable on markets with deep order books and significant queue depth. On thin markets where you are at or near the front of the queue, the model reduces to simple arrival-rate estimation.
</Note>

---

## API

### hz.QueueModel

Create a queue position model for a specific price level.

```python
import horizon as hz

model = hz.QueueModel(
    initial_queue=500.0,     # total queue size at your price level
    orders_ahead=200.0,      # contracts ahead of you in the queue
)
print(f"Queue position: {model.queue_position()}")
print(f"Position ratio: {model.queue_position() / 500.0:.2%}")
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `initial_queue` | `float` | Total queue depth at the price level (positive) |
| `orders_ahead` | `float` | Volume ahead of your order in the queue (non-negative, must not exceed initial_queue) |

### QueueModel Methods

#### update_book(total_queue, orders_ahead)

Update the model with a new book snapshot. Call this each time the order book changes at your price level.

```python
import horizon as hz

model = hz.QueueModel(initial_queue=500.0, orders_ahead=200.0)

# Book update: some orders ahead cancelled, new orders arrived behind
model.update_book(total_queue=480.0, orders_ahead=150.0)
print(f"Updated position: {model.queue_position()}")
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `total_queue` | `float` | New total queue depth (positive) |
| `orders_ahead` | `float` | New volume ahead of your order (non-negative) |

#### fill_probability(time_horizon)

Estimate the probability of your order being filled within a given time horizon, based on observed arrival and cancellation rates.

```python
import horizon as hz

model = hz.QueueModel(initial_queue=500.0, orders_ahead=200.0)

# After several book updates, estimate fill probability
prob = model.fill_probability(time_horizon=60.0)  # 60 seconds
print(f"Fill probability (60s): {prob:.2%}")
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `time_horizon` | `float` | Time horizon in seconds (positive) |

Returns a `FillProbResult`.

#### expected_fill_time()

Compute the expected time until your order is filled, based on the current arrival rate and queue position.

```python
eft = model.expected_fill_time()
print(f"Expected fill time: {eft:.1f} seconds")
```

Returns `float`: expected fill time in seconds. Returns `float('inf')` if the arrival rate is zero or the queue is stalled.

#### arrival_rate()

Return the estimated order arrival rate (fills per second) at your price level, computed from observed book updates.

```python
rate = model.arrival_rate()
print(f"Arrival rate: {rate:.4f} fills/sec")
```

Returns `float`.

#### cancel_rate()

Return the estimated cancellation rate (cancels per second) ahead of your position.

```python
rate = model.cancel_rate()
print(f"Cancel rate: {rate:.4f} cancels/sec")
```

Returns `float`.

#### queue_position()

Return your current position in the queue (volume ahead of you).

```python
pos = model.queue_position()
print(f"Orders ahead: {pos:.0f}")
```

Returns `float`.

### FillProbResult Type

Returned by `fill_probability()`.

| Field | Type | Description |
|-------|------|-------------|
| `probability` | `float` | Estimated fill probability in [0, 1] |
| `expected_fills` | `float` | Expected number of fills at this price level in the time horizon |
| `queue_position` | `float` | Current queue position (orders ahead) |
| `arrival_rate` | `float` | Estimated arrival rate used in the calculation |
| `cancel_rate` | `float` | Estimated cancellation rate used in the calculation |

---

## Standalone Fill Probability

### hz.queue_fill_prob

One-shot fill probability calculation without maintaining a stateful model.

```python
import horizon as hz

result = hz.queue_fill_prob(
    queue_ahead=200.0,
    arrival_rate=5.0,       # fills per second
    cancel_rate=1.0,        # cancels per second (ahead of you)
    time_horizon=60.0,      # seconds
)
print(f"Fill probability: {result.probability:.2%}")
print(f"Expected fills: {result.expected_fills:.1f}")
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `queue_ahead` | `float` | Volume ahead of your order (non-negative) |
| `arrival_rate` | `float` | Fill arrival rate at this price level (positive) |
| `cancel_rate` | `float` | Cancellation rate ahead of you (non-negative) |
| `time_horizon` | `float` | Time horizon in seconds (positive) |

Returns a `FillProbResult`.

<Note>
  The model uses a Poisson process for fill arrivals and an independent Poisson process for cancellations. The effective queue depletion rate is `arrival_rate + cancel_rate`, and the probability of reaching the front of the queue is computed via the CDF of the Poisson distribution.
</Note>

---

## Pipeline Integration

### hz.queue_tracker

Pipeline function that maintains queue position models for all active orders and injects analytics into `ctx.params["queue"]`.

```python
import horizon as hz

def queue_aware_strategy(ctx):
    queue = ctx.params.get("queue")
    if queue is None:
        return []

    mid = ctx.feed.price
    spread = 0.02

    # Check fill probability for existing orders
    for order_id, q in queue.get("orders", {}).items():
        prob = q["fill_probability_60s"]
        if prob < 0.1:
            # Very unlikely to fill, consider canceling and re-posting
            print(f"Order {order_id}: fill prob {prob:.1%}, consider re-posting")

    # Only post new orders if expected fill time is reasonable
    avg_eft = queue.get("avg_expected_fill_time", float("inf"))
    if avg_eft > 300:  # more than 5 minutes expected wait
        spread *= 0.5  # tighten spread to improve queue position

    return [
        hz.quote(ctx, hz.Side.Yes, hz.OrderSide.Buy, mid - spread, 10),
        hz.quote(ctx, hz.Side.Yes, hz.OrderSide.Sell, mid + spread, 10),
    ]

hz.run(
    name="queue-aware-mm",
    markets=["0xcondition..."],
    pipeline=[
        hz.queue_tracker(),
        queue_aware_strategy,
    ],
    interval=1.0,
)
```

The `ctx.params["queue"]` dict contains:

| Key | Type | Description |
|-----|------|-------------|
| `orders` | `dict[str, dict]` | Per-order queue analytics keyed by order ID |
| `avg_expected_fill_time` | `float` | Average expected fill time across all active orders |
| `total_queue_ahead` | `float` | Sum of queue depth ahead across all active orders |
| `best_fill_prob` | `float` | Highest fill probability (60s) among active orders |

Each order dict in `orders` contains:

| Key | Type | Description |
|-----|------|-------------|
| `queue_position` | `float` | Volume ahead of this order |
| `fill_probability_60s` | `float` | Fill probability over 60 seconds |
| `expected_fill_time` | `float` | Expected time to fill in seconds |
| `arrival_rate` | `float` | Estimated fill arrival rate |

---

## Mathematical Background

<AccordionGroup>
  <Accordion title="Poisson Queue Model">
    The model assumes fills arrive at the price level according to a Poisson process with rate mu, and cancellations ahead of you occur with rate delta. The effective queue depletion rate is lambda = mu + delta.

    Your order fills when the cumulative depletion exceeds your queue position Q. The probability of this in time T is:

    `P(fill) = P(Poisson(lambda * T) >= Q)`

    This is computed via the regularized incomplete gamma function for numerical stability.
  </Accordion>
  <Accordion title="Rate Estimation">
    Arrival and cancellation rates are estimated from observed book updates using exponentially weighted moving averages. This adapts to changing market conditions while filtering out noise from individual book updates.

    The model requires at least 2 book updates with non-zero time deltas to produce meaningful rate estimates. Before that, `fill_probability()` returns conservative estimates.
  </Accordion>
  <Accordion title="Limitations">
    The Poisson assumption treats arrivals as independent and memoryless. In practice, order flow exhibits clustering (modeled separately by ACD duration models). The queue model provides a first-order approximation that is most accurate over medium time horizons (30-300 seconds) and less reliable for very short or very long horizons.
  </Accordion>
</AccordionGroup>

<Warning>
  Queue position estimates are only as accurate as the book data fed to `update_book()`. On markets with infrequent book snapshots, the arrival and cancellation rate estimates may be noisy. Increase the update frequency or use larger time horizons for more stable estimates.
</Warning>
