Skip to content

Submit a native iceberg order

A native iceberg order is a venue primitive: trader sends a single order with a visible slice size and the total quantity. The exchange exposes only the visible slice on the book and auto-refreshes the next slice from the hidden remainder as the visible portion fills. Other participants see a sequence of small fills and level refills, not one big resting order.

flox ships IcebergExecutor for client-side slicing (each leg pays a round-trip latency). The simulator also supports the venue's native iceberg primitive, with no per-refresh latency unless you configure one.

When to use which

Scenario Pick
Venue offers iceberg natively (CME, Eurex) submit_iceberg
Client-controlled slicing on a venue without IcebergExecutor
Hybrid (some venues, some not, one strategy) submit_iceberg then fall back to executor algo on rejection

Native iceberg is preferred when available: the venue handles the refresh atomically, no client-side network round-trip per slice.

Configure

A worked example (Python):

"""Submit a native iceberg order and watch its hidden remainder drain."""
import flox_py as flox

exec = flox.SimulatedExecutor()

# Instant refresh is the default; set non-zero for venues with refresh delay.
exec.set_iceberg_refresh_latency(0)

# 10 BTC total, 2 BTC visible per slice.
exec.submit_iceberg(order_id=1, side="buy", price=100.0,
                     total_quantity=10.0, visible_quantity=2.0)

hidden = exec.iceberg_hidden_remaining_raw(1)
print(f"after submit: hidden remainder raw = {hidden}")
assert hidden > 0

# Cancel cleans up both visible and hidden portions in one call.
exec.cancel_order(1)
print(f"after cancel: hidden remainder = {exec.iceberg_hidden_remaining_raw(1)}")
import flox_py as flox

exec = flox.SimulatedExecutor()
# 1ms refresh delay (most venues are instant; leave at 0 for those).
exec.set_iceberg_refresh_latency(1_000_000)
exec.submit_iceberg(order_id=1, side="buy", price=50000.0,
                     total_quantity=20.0, visible_quantity=2.0)
import { SimulatedExecutor } from "flox";

const exec = new SimulatedExecutor();
exec.setIcebergRefreshLatency(1_000_000);
exec.submitIceberg(1, "buy", 50000.0, 20.0, 2.0);
const exec = new SimulatedExecutor();
exec.setIcebergRefreshLatency(1_000_000);
exec.submitIceberg(1, "buy", 50000.0, 20.0, 2.0);
from flox.backtest import SimulatedExecutor

exec = SimulatedExecutor()
exec.set_iceberg_refresh_latency(1_000_000)
exec.submit_iceberg(1, "buy", 50000.0, 20.0, 2.0)
FloxSimulatedExecutorHandle exec = flox_simulated_executor_create();
flox_simulated_executor_set_iceberg_refresh_latency(exec, 1000000);
flox_simulated_executor_submit_iceberg(exec, /*id=*/1, /*side=*/0,
                                       /*price=*/50000.0,
                                       /*total=*/20.0, /*visible=*/2.0,
                                       /*symbol=*/1);

Behaviour the simulator guarantees

  • Only visible_quantity is added to the book queue at submit.
  • When the visible tranche fully fills, the simulator atomically refreshes another slice of min(visible_quantity, hidden_remainder) unless a refresh latency is configured, in which case the next slice is exposed at fill_time + latency instead.
  • The refreshed slice goes to the back of the queue at that price level by default (override via set_iceberg_priority_mode).
  • Cancel cancels both the visible portion and the hidden remainder in one call.

Refresh variants

Real venues differ on two iceberg knobs that materially change the fill profile for queue-position strategies:

Knob Default Other modes Models
Size randomisation 0% (off) up to ±100% uniform per refresh Anti-detection ±10% on liquid spot
Refresh queue priority back retain CME options + some Eurex contracts
# Anti-detection: jitter each refreshed slice ±10% around visible.
exec.set_iceberg_size_randomisation_pct(0.10)
exec.set_iceberg_jitter_seed(42)  # reproducible draws

# CME-style: refreshed slice keeps the same queue position.
exec.set_iceberg_priority_mode("retain")
exec.setIcebergSizeRandomisationPct(0.10);
exec.setIcebergJitterSeed(42);
exec.setIcebergPriorityMode("retain");

Inspect remaining hidden quantity

For diagnostics, the executor exposes the raw fixed-point hidden remainder per order ID:

rem_raw = exec.iceberg_hidden_remaining_raw(order_id=1)
rem = rem_raw / 1e8  # Quantity is fixed-point with scale 1e-8
const remRaw = exec.icebergHiddenRemainingRaw(1);

The value drops by visible_quantity on each refresh and reaches 0 once the order is fully filled.

Notes

  • visible_quantity must be strictly less than total_quantity — otherwise the order behaves as a regular limit (no hidden state created).
  • Refresh latency is a single venue-wide setting, not per-order. Most venues are instant; some inject 0.5-2ms between refresh and next-slice exposure.
  • Self-trade prevention (T025) and rate-limit policy (T022) apply to native iceberg the same way they apply to limit orders.