VWAP
Execute a parent order along a live multi-exchange volume trajectory.
VWAP
VWAP, or Volume-Weighted Average Price, executes a user-supplied side and amount according to expected and observed market volume. You choose what to buy or sell and the total duration. The strategy decides when to work the order and how large each child should be.
Market Lab executes VWAP orders on BULK. Volume can come from BULK, from one or more exchanges through MMT, or from both. Selected sources determine the desired trajectory; BULK's own volume and orderbook independently constrain every child placed on BULK.
VWAP can place real post-only limit and market orders. Preview the complete plan with
--dry-runbefore deploying it.
Preview a VWAP
mlab strategy run vwap BTC/USDT \
--venue bulk \
--side buy \
--margin 100 \
--leverage 10 \
--duration 3600 \
--volume-sources binancef@mmt,okxf@mmt,bulk \
--dry-runThe dry run fetches completed one-minute trajectory history and BULK execution-volume history, constructs the requested UTC execution window, estimates the required BULK participation rate, and submits nothing.
VWAP intentionally has no --interval. A fixed child interval would be TWAP with uneven child sizes. The VWAP worker reacts to volume, order-book changes, fills, trajectory drift, stale maker orders, and the remaining time.
Volume Sources
--volume-sources is a comma-separated list:
binancef@mmt,okxf@mmt,hyperliquid@mmt,bulkbinancef@mmtobtains Binance Futures volume through MMT.okxf@mmtobtains OKX Futures volume through MMT.bulkuses BULK's standalone market-data adapter.- A direct selector such as
binanceis accepted only after that standalone adapter and market snapshot exist.
When the flag is omitted, the volume source defaults to the execution venue's direct market-data source, currently bulk.
These selectors never change the execution venue or directly determine child size. Even when bulk is omitted, the worker always consumes BULK volume internally because BULK is where the orders must be filled.
The same underlying exchange cannot be selected twice through different providers. For example, binance@mmt,binance is rejected because it would double-count Binance volume.
Every selected exchange must contain the requested symbol in the installed market snapshot. Refresh snapshots before retrying a newly listed market:
mlab markets --exchange bulk --refresh
mlab markets --provider mmt --exchange binancef --refreshTrajectory Construction
Market Lab uses completed one-minute volume data from the previous seven days to construct the forecast. It:
- Converts every selected source to normalized base-asset volume.
- Aggregates MMT exchanges in one server-side volume query.
- Combines provider volume by UTC minute of day.
- Averages matching minutes across the historical days.
- Proportionally includes partial first and final minutes.
- Normalizes the execution window into a cumulative volume trajectory.
Historical minute bars are not used for live progress. Once the job starts, Market Lab subscribes to each selected exchange's trades feed and adds the absolute base-asset size of every trade at or after the exact startup timestamp. Buy and sell volume are added together; VWAP uses total traded volume, not directional CVD.
The execution venue's trades feed is consumed separately even when that venue is omitted from --volume-sources. This produces the independent participation capacity used to constrain children.
Live Target
The controller combines actual volume since startup with forecast volume remaining:
target size = parent size × actual volume / (actual volume + forecast remaining)Higher-than-expected live volume pulls execution forward. Lower volume slows it down. The target reaches the complete parent size at the deadline.
If a live source disconnects, the job records strategy.market_data.degraded and substitutes forecast progress instead of treating the missing venue as zero volume.
Execution-Venue Capacity
The aggregated target is a pacing signal, not permission to consume the BULK book. Market Lab maintains a separate cumulative participation ledger from BULK volume observed after the job starts:
trajectory deficit = max(0, trajectory target - filled - working)
available BULK capacity = max(
0,
cumulative participation credit - filled - working
)New BULK volume creates credit once. Repeated one-second controller decisions do not recreate the allowance. Existing fills and the remaining quantity of the working maker order reserve that credit.
The required starting participation rate is derived from the parent size and forecast BULK volume. Urgency can raise the rate when the strategy falls behind or the remaining BULK volume becomes insufficient, but it can never exceed the hard 10% participation cap.
Passive maker sizing may use up to one minute of forward BULK forecast volume so the strategy can rest an order before the next trade occurs. Taker sizing uses only credit earned from actual BULK volume.
The dry-run plan reports forecast trajectory volume, forecast BULK volume, required and maximum participation, forecast capacity, expected shortfall, and feasibility. An infeasible dry run still prints the estimate; live deployment is rejected until the amount is reduced or the duration is increased.
If the live BULK execution trade feed disconnects, the worker cancels its maker and pauses new children. A trajectory-source trade disconnection instead uses forecast trajectory progress.
Maker-First Execution
The controller maintains a target band around the VWAP trajectory:
- while near the trajectory, it maintains an ALO post-only order at the passive touch
- when ahead, it cancels the working maker order and waits
- when the touch changes, the amount changes materially, or the order becomes stale, it cancels and replaces its own order
- when below the lower trajectory bound, it cancels the maker and submits a participation- and depth-bounded market child to catch up
- urgency depends on the trajectory deficit, remaining quantity, remaining BULK forecast volume, and time left
- at the deadline, it cancels the working maker and handles only the remainder allowed by earned participation credit and guarded depth
Market children are limited by both the cumulative 10% BULK participation cap and displayed depth within 20 basis points of the current best price. If the complete deadline remainder cannot execute inside both guards, the job fails rather than silently consuming more BULK liquidity.
All submit and cancel requests are job-owned and idempotent inside mlabd. A VWAP worker cannot cancel an order created by another job or by the user.
Arguments
| Argument | Required | Meaning |
|---|---|---|
SYMBOL | Yes | Market Lab symbol such as BTC/USDT |
--venue | No | Execution venue; currently bulk |
--side | Yes | Parent side: buy or sell |
--size | One amount | Exact total base-asset size |
--margin | One amount | Quote collateral; multiplied by leverage before size flooring |
--duration | Yes | Execution window in seconds; minimum 60 |
--volume-sources | No | Comma-separated direct or exchange@mmt selectors |
--leverage | No | Leverage attached to every child; defaults to 1 |
--reduce-only | No | Marks every child as reduce-only |
--dry-run | No | Build and print the plan without creating a job |
--yes | No | Skip live terminal confirmation |
--output | No | terminal, json, or jsonl |
Set exactly one of --size or --margin.
Deploy and Monitor
Remove --dry-run to deploy the detached worker:
mlab strategy run vwap BTC/USDT \
--side buy \
--margin 100 \
--duration 3600 \
--volume-sources binancef@mmt,okxf@mmt,bulkThe CLI prints the job ID and returns control to the terminal. Monitor or stop it with the shared strategy commands:
mlab strategy jobs
mlab strategy status <JOB_ID>
mlab strategy logs <JOB_ID> --follow
mlab strategy stop <JOB_ID>Logs include the normalized plan, degraded-data notices, each maker or taker child, trajectory volume, BULK execution volume, active participation rate, participation credit, fill progress, venue order IDs, and a completion summary containing fill VWAP and arrival-price slippage.
Stopping cancels the strategy's current maker order and prevents further children. It does not reverse fills or close the resulting position.