Algo Framework: Market Maker, Spreader and Smart Orders
The Nanoconda package includes a ready-to-use algo framework built on the Algo Control API and the Order Entry API. One program runs any number of algos on one trading session and controls them from the Algo Window of the Real-Time GUI:
| Algo type | Algo Window view | What it does |
|---|---|---|
| MM - Market Maker | View 1 | Keeps a ladder of buy and sell quotes around the best bid / best ask of one instrument, with optional adverse-selection protection (pull after fill, book imbalance, sweep, queue depletion, pull on request limit). |
| SPRD - Spreader | View 2 | Trades a two-leg spread at a target spread price: quotes one or both legs and hedges the other leg when filled. |
| SMART - Smart Orders | View 3 | The order types CME does not offer: market/limit-if-touched and trailing stops held by the program, and OCO and bracket orders that link exchange orders (their stops are native CME stops). Thousands per instrument. |
All three share the same framework: per-algo position and P&L, per-algo message pacing, flatten, logging and the same GUI controls. The source is short and meant to be read and extended.
Note
The algos are reference implementations of common trading tools, not profitable strategies. Test every configuration on the simulator before trading live.
Files
All files are in src/algos/ of the package.
| File | Contents |
|---|---|
algos.cpp |
The program: entry points (main, init_nanoconda_plugin, plugin_stop), the list of algo types, and the three Algo Window types MarketMakerAlgo, SpreaderAlgo and SmartEntry (inputs, buttons, report columns). |
framework.h |
The Algo Window host (Host, built on HostCore: Algo Window, flatten, smart orders) and the Algo base class. |
hostcore.h |
The application core shared with marketmaker.cpp and NanoSpreader: session, market data (top of book, 10 book levels and trades) and order callbacks, instruments, clip size, the order map and the handling of order acks, rejects, cancels and fills. |
ordercore.h |
Orders: order slots, send/replace/cancel, message pacing, acks, rejects and fills (duplicate, missed and late fills, orders without a response), the order map (the program's own orders), the instrument's market (best bid/ask and 10 book levels), position and P&L. |
marketmaker.h |
Market maker logic: quote prices, skew, min edge, sticky ticks, levels, stop / max loss, the quote ladder and the adverse-selection protection (pull after fill, imbalance, sweep, queue depletion, pull on request limit, keep closing quotes). |
spreader.h |
Spread logic for 1 to 4 legs: leg prices, lean, slop, hedging and exit. |
smartorders.h |
The smart order engine, usable from any algo: MIT, LIT and trailing stops held by the program, native CME stops, OCO and bracket links. |
Makefile |
Builds algos (native) and algos.wasm (WebAssembly plugin). |
../NanoSpreader/ |
The NanoSpreader application (NanoSpreader); a separate program, not part of algos. |
ordercore.h, hostcore.h, marketmaker.h and spreader.h hold the trading logic and are shared: the algos program, the sample
marketmaker.cpp and NanoSpreader all use them, each with its own small layer that connects them to its screen.
Building and Starting
The program needs the Nanoconda development libraries (see Quick Start Guide).
algos.cpp also exports init_nanoconda_plugin and plugin_stop, so it can be built as a plugin and started by
nanoconda-cli -a pluginloader. Session arguments (-e, -s, -u, -p, -a, -c, -l) are given to the
loader; see WebAssembly Plugins - Building & Running for the full argument list.
| Argument | Description |
|---|---|
-e |
Exchange. |
-s |
Comma-separated symbols. Subscribe every instrument any algo will use, including the second leg of a spread. |
-u / -p |
Username / password. |
-a |
Trading account. |
-c |
CPU to pin to (optional). |
Every order, fill, reject and state change is written to algos.log. Each line starts with the instrument and the algo
line number, e.g. ESZ6 #3 FILL ....
Unusual exchange responses are logged and handled: DUP ACK / DUP FILL (repeated, ignored), GAP FILL (a fill
report was missed; the missing quantity is applied at the exact average price), LATE FILL (a fill for an order the
line no longer tracks; added to the line's position), STUCK (no response to an order for 10 seconds).
Warning
MIT, LIT and trailing stops that have not triggered yet exist only in the running program and are lost when it stops. While the program is not running, OCO and bracket links do not work: a fill of one leg does not cancel or reduce the other. Cancel or flatten before stopping, and see Stopping the Program.
The Algo Window
Open the Algo Window in the GUI and pick the view of the algo type you want to launch. Select an instrument, fill in the inputs on the left and press Submit. Each view shows only the lines of its own algo type.
| View | Algo type | What Submit does |
|---|---|---|
| View 1 | MM | First Submit for an instrument starts a market maker; Submit again updates its parameters. |
| View 2 | SPRD | Each Submit starts a new spreader line. Several spreaders can run on the same instrument. |
| View 3 | SMART | Each Submit adds one smart order to the instrument's Smart Orders line. |
Report Columns
| Column | Description |
|---|---|
| Symbol | Instrument (for a spreader: leg 1). |
| Type | MM, SMART or SPRD. |
| Status | RUNNING, DISABLD, FLATTEN, DONE, ERROR; while the session is not tradable a running line shows SESS DN, BLOCKED (algos blocked by the risk desk) or NO PERM. |
| Info | Why a line is not trading or what it is doing (see Info Codes). |
| Buy Px / Sell Px | Market maker: best working quotes. Spreader: target spread price on its own side. |
| Position | Position from this line's own fills, shown as +3/5 (position / Max Position) when a limit applies. |
| PnL | Realized + unrealized P&L of this line in account currency. |
| Mkt Bid / Mkt Ask | Current market: the instrument's best bid / ask, or for a spreader the spread's market (bid = what the spread can be sold at now, ask = what it can be bought at now). 0 while there is no two-sided market. |
Header Fields and Buttons
| Field / Button | Description |
|---|---|
| Market Maker / Smart Orders / Spreader | First header field of each view: the algo type of the view. |
| Session PnL | P&L of the whole trading session. |
| Orders / Replaces / Cancels / Fills | Message and fill counters of the program. |
| Rejects / Risk Rejects / Last Reject | Exchange rejects, pre-trade risk rejects and the last reject code. |
| Disable All | Disables every market maker and spreader. Smart Orders lines are not affected, so protective stops stay in place. |
Line Buttons
| Button | Description |
|---|---|
| Start | Start (or restart) a disabled line. A spreader that is DONE cannot be restarted; submit a new one. |
| Disable | Stop the line. What happens to its orders and position depends on the algo type (see each algo below). |
| Remove | Remove a stopped line from the report. Refused (Info WORKING) while the line still has working orders or smart orders. |
| + - ^ v | Market maker only, see GUI Controls. |
| E + - | Spreader only, see GUI Controls. Exit (E) sits before Remove. |
Info Codes
| Info | Meaning | What to do |
|---|---|---|
BADCFG |
Inputs refused at Submit: out of range, quantity above the account's clip size, missing second instrument, etc. The log line SUBMIT ... shows all values. A spreader line refused at Submit shows no prices and stays in BADCFG. |
Fix the inputs and Submit again. |
NO MKT / MD GAP |
No two-sided market, or market data gap / snapshot recovery. Quoting pauses automatically. | None; resumes when the market is back. |
NO MKT2 |
Spreader: no two-sided market on leg 2. | Check that leg 2 is subscribed (see Building and Starting). |
NO TICK |
Instrument tick size is unknown. | Check the instrument subscription. |
OPER |
Line was disabled by the operator and flattened. | - |
EXT CXL |
One of the line's orders was cancelled outside the algo (e.g. from Live Orders); the line stopped. | Press Start to resume. |
STOP LS / MAXLOSS |
Market maker stop loss or max loss reached; position flattened. | Review, then Submit with new limits. |
FLATERR |
Flatten could not complete within 5 seconds. | Check the position and working orders manually. |
LATE FILL |
A fill arrived after a Market Maker line had stopped; the line flattens the new position. | - |
WORKING |
Remove refused, the line still has orders. | Disable first and wait. |
HEDGING / STOPPING |
Spreader is hedging a filled leg / finishing hedges after Disable. | - |
EXITING / EXITED |
Spreader is closing its position at market after Exit / position closed. | - |
n SO / REFUSED |
Smart Orders line: number of open smart orders / last Submit was refused. | See the log line SUBMIT ... refused. |
CANCEL |
Smart Orders line disabled; all its smart orders were cancelled. | Submit or Start to use it again. |
Common Behavior
Pre-Trade Risk and Clip Size
Every order goes through the Pre-Trade Risk System. The algos also check the account's clip size
at Submit: a quantity that could never pass the clip size (e.g. Quote Qty, spread quantity x leg ratio, or a smart
order quantity) is refused with BADCFG instead of being rejected over and over. Flatten splits market orders by the
clip size.
Message Pacing - Max Msgs/Sec
Every algo line has its own Max Msgs/Sec input (new orders and replaces per second, 0 = no limit). The budget is
per line: if two algos run in one program, split the account's throttle between them, e.g. 50% each, and keep the
total below the server throttle.
- Protective orders (hedges, stops, flatten) may use the full budget; quoting uses at most 80% of it.
- If the server throttle is hit (
REQUEST_LIMIT), the whole program stops sending new orders and replaces for 1 second. Cancels are still sent. Market makers with Pull On Request Limit also cancel their quotes, see Pull On Request Limit. - A market maker quote that cannot be moved within the budget and would now be priced better than the new top price is
cancelled and re-quoted after 2 seconds (log
PACE).
Disable, Disable All and Flatten
| Algo type | Disable | Disable All |
|---|---|---|
| Market Maker | Cancels quotes, then flattens its own position with market orders split by clip size. | Same as Disable. |
| Spreader | Stops quoting but finishes any open hedge, so it never leaves one leg unhedged; then DONE. |
Same as Disable. |
| Smart Orders | Cancels all smart orders of the line. | Not affected. |
Flatten closes only the line's own position, never the whole account.
Session, Algo Block and Market Data
- While the session is down or algos are blocked by the risk desk, algos send nothing; Status shows
SESS DN/BLOCKED. Triggered smart orders are retried every 2 seconds until the block is lifted. - During a market data gap or snapshot recovery algos stop quoting (Info
MD GAP) and resume after recovery. - Algos react when the best bid / ask price or size changes, and at least every 100 ms while book data is arriving. The market maker's Queue Depletion protection also uses changes of the deeper book levels (10 levels).
- Market trades are used by the market maker's Sweep and Queue Depletion protections. Trades without an aggressor side, and trades during a market data gap, are ignored.
Orders Not Placed by the Algos
The program keeps the order number of every order it sends and only reacts to those. Orders entered manually, from other programs or from a previous run are ignored and never cancelled or flattened by the algos.
Stopping the Program
On exit (Ctrl-C) the standalone program cancels its own working orders, including the exchange orders of smart orders (native stops of OCO and bracket orders too). When started by
pluginloader as a native plugin, shutdown is handled by the library and the algos do not cancel their orders. In both
cases nothing is flattened and smart orders held by the program (MIT, LIT, trailing stops) are discarded. Press Disable / Disable All first if you want to end flat. Positions are tracked per
line from fills seen by the running program, so a restarted program starts every line at position 0.
Market Maker
For each instrument the market maker keeps a ladder of buy and sell quotes around the best bid / best ask and moves them as the market changes. One line per instrument; Submit again updates its parameters.
Inputs
Inputs in the order the Algo Window shows them. The protection inputs (from Pull Pause ms) are off by default.
| Input | Default | Range | Description |
|---|---|---|---|
| Quote Qty | 1 | 1-1000 | Size of each quote. Must not exceed the clip size. |
| Sides | Both | Buy / Sell / Both | Quote buys only, sells only or both. |
| Ticks Away | 0 | 0-100 | Distance of the best quotes from the best bid / ask (0 = join). |
| Max Position | 5 | 1-10000 | Position limit for the line, including working orders. |
| Max Loss (0=off) | 0 | 0-100000000 | Flattens and disables (MAXLOSS) when the line's P&L reaches -Max Loss (account currency). |
| Reprice | On | Off / On | On follows the market; Off leaves resting quotes in place and steps further away after each fill. |
| Skew Ticks/Fill (0=off) | 0 | 0-100 | Shifts both sides away from the inventory by N ticks per filled quote. |
| Min Edge Ticks (0=off) | 0 | 0-1000 | The closing side is never priced worse than average price +/- N ticks. While a position is open the closing side always follows to this price, even with Sticky Ticks or Reprice Off. |
| Stop Ticks (0=off) | 0 | 0-10000 | Flattens and disables (STOP LS) when the market is N ticks against the average price. |
| Levels / Level Step Ticks | 1 / 1 | 1-5 / 1-100 | Number of quotes per side and the distance between them. |
| Sticky Ticks (0=off) | 0 | 0-100 | Ladder waits until it is more than N ticks behind before following the market. |
| Max Msgs/Sec (0=off) | 0 | 0-1024 | Message budget of this line, see Message Pacing. |
| Pull Pause ms | 500 | 0-60000 | How long a side stays cancelled after Pull After Fill, a Sweep or a Queue Depletion. |
| Keep Closing Quotes | On | Off / On | See Keep Closing Quotes. |
| Pull After Fill | Off | Off / On | See Pull After Fill. |
| Pull On Request Limit | Off | Off / On | See Pull On Request Limit. |
| Imbalance % (0=off) | 0 | 0-50 | See Book Imbalance. |
| Sweep Lots (0=off) | 0 | 0-100000 | See Sweep. |
| Sweep Window ms | 100 | 0-60000 | See Sweep. |
| Depl Rate % (0=off) | 0 | 0-10000 | See Queue Depletion. |
| Depletion ETA ms | 300 | 0-60000 | See Queue Depletion. |
GUI Controls
| Button | Description |
|---|---|
| + / - | Widen / narrow the quotes by 1 tick. Narrow moves both sides in even if Sticky Ticks is holding them; widen leaves quotes that are already wider. |
| ^ / v | Shift both sides 1 tick up (towards buying) / down (towards selling). Up moves the bid up and down moves the ask down even if Sticky Ticks is holding them. |
| Disable | Cancel quotes and flatten the position. |
After a fill the market maker waits for the next book update before quoting again on that side.
Adverse-Selection Protection
| Protection | On when | Cancels | Back |
|---|---|---|---|
| Pull After Fill | Pull After Fill On | the filled side | after Pull Pause ms without the price moving against the fill |
| Book Imbalance | Imbalance % > 0 | the thin side | when the side is no longer thin |
| Sweep | Sweep Lots > 0 | the swept side | after Pull Pause ms |
| Queue Depletion | Depl Rate % > 0 | the side whose queue is consumed | after Pull Pause ms without a new depletion |
| Pull On Request Limit | Pull On Request Limit On | both sides | after the 1-second send pause |
All protections:
- cancel the quotes of the side; they never replace them to another price;
- quote the side again with new orders when they end;
- leave the position and the other side unchanged (except Pull On Request Limit, which cancels both sides);
- keep orders that close the position when Keep Closing Quotes is On.
While a side is cancelled the line stays RUNNING and the side shows 0 in Buy Px / Sell Px. Cancelled quotes
appear as CANCEL lines in the log; the settings are logged at Submit (SUBMIT pause ...). A pause can end up to about
100 ms later than set when the market is quiet.
Pull After Fill
- A quote is filled (fully or partly).
- All quotes on that side are cancelled.
- The side stays out for Pull Pause ms. The pause starts again each time the side's best market price moves further against the fill (best bid lower after a buy fill, best ask higher after a sell fill).
- The side quotes again with new orders.
Example, Pull Pause 500: bought 1 at 100. The buy quotes at 99 and 98 are cancelled. 10 ms later the bid drops to 99; the pause now ends 500 ms after that. The buy side quotes 99/98/97 at the first book update after the pause.
Book Imbalance
- Share of a side = its best price size / (best bid size + best ask size).
- The side is cancelled while its share is below Imbalance %.
- It quotes again when its share is back at Imbalance % + 10.
Example, Imbalance 30: at bid 2 / ask 18 lots (10%) the bids are cancelled; at bid 7 / ask 13 (35%) they stay cancelled; at bid 9 / ask 11 (45%) they are quoted again.
Sweep
- Sellers hitting bids count against the buy side; buyers lifting offers count against the sell side. All trades of the instrument count, at any price, including fills of your own quotes.
- Counting starts at the first such trade and lasts Sweep Window ms. When the count reaches Sweep Lots within the window, the side is cancelled for Pull Pause ms. A new sweep during the pause starts it again.
- The side is cancelled on the trade itself, before the book update.
- Sweep Window ms
0: only a single trade of Sweep Lots or more triggers.
Example, Sweep Lots 10, Sweep Window 100, Pull Pause 500: sells of 4, 4 and 3 lots within 20 ms cancel the bids for 500 ms. Sells of 6 lots and, 150 ms later, another 6 lots do not trigger.
Queue Depletion
Queue ahead of the side's top quote at price P:
- the book size at prices better than P (bids above P for the buy side, offers below P for the sell side), within 10 book levels, plus
- the size that was at P when the quote joined P, reduced by trades at P and never more than the size at P without your own order. Orders that join P later are not counted.
While the side has no quote, the price where its top quote would be is used.
Consumption = lots leaving the queue ahead: trades at or better than P (counted when the trade arrives) and book size decreases (cancels, levels removed). A trade is counted once, also when the book update for it arrives later.
Trigger: both must be true:
- The consumption speed over about the last 200 ms is at least Depl Rate % of the speed over about the last 30 s (200 = twice the normal speed).
- At that speed the queue ahead is gone within Depletion ETA ms.
The side is cancelled for Pull Pause ms, extended while the trigger is still true. The protection is not active in the first 5 seconds after the line starts.
Example, Depl Rate 300, Depletion ETA 300, Pull Pause 500: bid at 99 (Ticks Away 1), queue ahead 69 lots (40 at 100, 29 at 99), normally a few lots per second. Sellers hit 35 lots at 100 within 5 ms: about 180 lots/s, 34 lots left, gone in about 190 ms, so the bid is cancelled. 600 ms later, with a calm market, the bid is quoted again.
| Setting | Depl Rate % | Depletion ETA ms | Result |
|---|---|---|---|
| Aggressive | 150 | 500 | Cancels early and often; more cancels and lost queue position. |
| Moderate | 200 | 300 | Cancels on clear bursts close to the quote. |
| Relaxed | 600 | 150 | Cancels only on extreme bursts right in front of the quote. |
Lower Depl Rate % or higher Depletion ETA ms cancels earlier and more often.
Pull On Request Limit
- When the server refuses an order or replace with
REQUEST_LIMIT(logRISK ... rejected: REQUEST_LIMIT), every market maker line of the program with Pull On Request Limit On cancels all its quotes, both sides. - The line whose request was refused cancels at once; the other lines at their next market data update.
- The lines quote again with new orders when the 1-second send pause ends.
- Flatten orders are not cancelled. Max Msgs/Sec pacing does not trigger it.
Keep Closing Quotes
When a protection cancels the side that closes the open position (the sell side when long, the buy side when short) and Keep Closing Quotes is On:
- the side's orders are kept, best price first, while their remaining size fits within the position;
- the first order that does not fit and all orders behind it are cancelled;
- no new orders and no price changes on that side until the protection ends.
When the line is flat the whole side is cancelled. The side that adds to the position is always cancelled. Off: the side is always cancelled completely.
Example: long 2, sells at 101, 102 and 103 (1 lot each), the request limit is hit: bids cancelled, offers at 101 and 102 kept, offer at 103 cancelled.
Spreader
The spreader trades a two-leg spread, like the autospreaders of common trading front ends. Pick leg 1 as the
Algo Window instrument and leg 2 as the second instrument of the Algo Window input (sent to the algo as
symbolId2 in the input header). Both legs must be subscribed and use the same price format.
Spread price = Leg 1 Price Mult x leg 1 price - Leg 2 Price Mult x leg 2 price.
Buying the spread buys leg 1 and sells leg 2; selling the spread does the opposite. The quantity of each leg is Spread Qty x the leg's Qty Ratio.
How It Trades
- The quoting leg rests a limit order at the price that gives the target spread against the current best price of the other leg (the price you would hedge at).
- The quote follows the other leg's market, within the slop tolerance.
- When the quote fills, the other leg is hedged immediately with a limit order at the market plus Payup Ticks.
The hedge follows the market if it moves away, until filled. With a ratio above 1 the other leg is hedged in
proportion to the lots already filled (whole lots), not only after a full spread. A hedge larger than the leg's clip
size is sent in clip-size orders. A hedge that would trade against your own resting order on the same instrument is
held; the spreader cancels its own blocking order first. The log shows
HEDGE/HEDGEDlines. - When every leg is filled the line ends
DONE FILLED.
With Quote Legs = Both both legs quote at the same time; whichever fills first is hedged on the other leg and the other quote is turned into the hedge.
Inputs
| Input | Description |
|---|---|
| Side | Drop-down: Buy or Sell the spread. |
| Spread Qty | Number of spreads. Spread Qty x each leg ratio must not exceed that leg's clip size. |
| Spread Price | Target spread price, in the price format of the legs (may be negative). |
| Leg 1 / Leg 2 Qty Ratio | Lots of each leg per spread, e.g. 1 and 2 for a 1:2 spread. |
| Leg 1 / Leg 2 Price Mult | Multipliers in the spread price formula, e.g. contract point values for an inter-commodity spread. |
| Quote Legs | Drop-down: which legs rest quotes - Leg 1, Leg 2 or Both. |
| Payup Ticks | How many ticks through the market a hedge order is priced, to fill quickly. |
| Inside Slop Ticks | A quote that would move N ticks or less towards the market is left where it is. |
| Outside Slop Ticks | A quote that would move N ticks or less away from the market is left where it is. Saves messages and queue position. |
| Min Lean (spreads) | Quote only while the other leg's best quantity covers at least N spreads (N x its ratio), so the hedge can fill. |
| Max Msgs/Sec (0=off) | Message budget of this line, see Message Pacing. |
Examples
| Spread | Leg 1 / Leg 2 | Ratio | Price Mult | Spread Price |
|---|---|---|---|---|
| Calendar spread | front month / next month | 1 : 1 | 1 : 1 | front - next |
| 1:2 spread | instrument A / instrument B | 1 : 2 | 1 : 2 | A - 2 x B |
| Inter-commodity, in currency | A / B | 1 : 1 | point value A : point value B | value of A - value of B |
GUI Controls
| Button | Description |
|---|---|
| + / - | Move the spread price up / down by one spread tick (the smaller of Leg 1 Mult x leg 1 tick and Leg 2 Mult x leg 2 tick). The quote reprices immediately. |
| Disable | Stop quoting, finish open hedges (Info STOPPING), then DONE CANCELED. The position stays open. |
| Exit (shown as E) | Close this spreader's position: stop quoting, cancel its working orders (including a hedge), then send market orders on both legs for exactly the lots this spreader filled, split by clip size (Info EXITING), then DONE EXITED. Works on a finished (DONE FILLED) line too. |
The Position column shows completed spreads (positive = long the spread), and PnL values both legs at the price
they could be closed at. Mkt Bid / Mkt Ask show where the spread trades now
(bid = Leg 1 Mult x leg 1 bid - Leg 2 Mult x leg 2 ask, ask = Leg 1 Mult x leg 1 ask - Leg 2 Mult x leg 2 bid), so you can
compare them with the target in Buy Px / Sell Px. While one leg is filled and the hedge is working, Info shows HEDGING.
Smart Orders
Smart Orders add the order types CME Globex does not offer. Plain stops and stop-limits are native CME orders: place them from the DOM or your order entry.
| Order part | Where it is held |
|---|---|
| Stops and stop-limits of OCO and bracket orders | At CME, as native stop (STP, stop with protection) and stop-limit (SLMT) orders, sent at once. |
| MIT, LIT, trailing stops | In the program. Nothing is sent until the order triggers. |
| OCO and bracket links | In the program. When one leg fills, the program reduces or cancels the other; a bracket's exits are placed when its entry fills. |
- MIT, LIT and trailing stops trigger on the best bid / ask: buy orders on the ask, sell orders on the bid. Native stops are triggered by CME.
- Every exchange order of a smart order has its own order number.
- A smart order whose exchange order is refused 3 times in a row by the exchange or pre-trade risk ends as rejected. While the session is down or algos are blocked it retries every 2 seconds.
- Native stops go through pre-trade risk when they are sent. MIT, LIT and trailing stops go through it when they trigger.
Launching from the Algo Window
Use View 3: select the instrument, fill in the inputs and press Submit. Each Submit adds one smart order to the instrument's Smart Orders line.
| Order Type | Name | Inputs used | Behavior |
|---|---|---|---|
| MIT | Market if Touched | Side, Qty, Price | Market order when the market touches Price from the other side (buy: ask <= Price, sell: bid >= Price). |
| LIT | Limit if Touched | Side, Qty, Price, Price 2 | Limit order at Price 2 when the market touches Price. |
| Trail | Trailing Stop | Side, Qty, Trail Ticks | Stop that follows the best price by Trail Ticks (a sell stop follows the highest bid); market order when reached. |
| Trail Limit | Trailing Stop Limit | Side, Qty, Trail Ticks, Limit Offset Ticks | Trailing stop that sends a limit order Limit Offset Ticks beyond the stop price. |
| OCO Lmt/Stop | OCO Limit + Stop | Side, Qty, Price, Price 2 | Exit pair on one side, both sent to CME at once: limit at Price, native stop at Price 2. A partial fill of one reduces the other; a full fill cancels it. |
| OCO Buy/Sell | OCO Buy Stop / Sell Stop | Qty, Price, Price 2 | Breakout pair of native stops: buy stop at Price, sell stop at Price 2. A fill of one reduces or cancels the other. |
| Bracket | Bracket | Side, Qty, Price, Target Ticks, Stop Ticks or Trail Ticks | Entry limit at Price (0 = market). Each entry fill adds a take-profit limit Target Ticks from the fill price and a native stop Stop Ticks from it (a trailing stop if Trail Ticks > 0). Target and stop are an OCO pair. |
A Submit is refused (Info REFUSED) when, for example, a price is not on the tick grid, the quantity exceeds the clip
size, or a stop / touch price is already reached at Submit.
Note
Both orders of an OCO pair rest at CME at the same time. If the market trades through both before the first fill is seen and the other order is cancelled, both can fill.
Bracket Lifecycle
| Event | What happens |
|---|---|
| Entry partly filled | Target and stop are placed for the filled quantity and grow with every further entry fill. |
| Target or stop partly filled | The other exit is reduced by the same quantity. |
| Target or stop fills, or a trailing stop triggers | The rest of the entry is cancelled, and the other exit is cancelled or reduced. |
| Entry cancelled before any fill | Target and stop are cancelled. |
| Entry cancelled after a partial fill | Target and stop stay for the filled quantity. |
Cancelling Smart Orders
- Orders resting at the exchange (limits, native stops, bracket targets and stops, triggered limit orders) can be cancelled from Live Orders: this cancels the smart order and its OCO partner.
- The market order of a triggered MIT or trailing stop is sent again if it disappears.
- Disable on the Smart Orders line cancels all of its smart orders and their orders at the exchange.
- Disable All does not touch Smart Orders lines.
Limits
| Limit | Value |
|---|---|
| Smart orders per program | 65,536 |
| Instruments with MIT / LIT / trailing smart orders | 64 |
| Retries after exchange / risk rejects | 3 in a row |
Smart Orders from Your Own Algo (C++)
Any algo can use the smart order engine through host->_smart. Orders belong to the algo that places them: their fills
count in its position and P&L, they use its message budget, and they are cancelled when the algo stops.
SmartOrders& so = host->_smart;
long long tick = mkt->tickSize;
so.place(this, mkt, { SmartType::TRAIL, 'S', 2, 0, 0, 6 * tick }, now);
so.placeOco(this, mkt, { SmartType::LIMIT, 'S', 2, 0, targetPx, 0 },
{ SmartType::STOP, 'S', 2, stopPx, 0, 0 }, false, now);
so.placeBracket(this, mkt, { SmartType::LIMIT, 'B', 2, 0, entryPx, 0 },
{ SmartType::LIMIT, 'S', 0, 0, 8 * tick, 0 },
{ SmartType::STOP, 'S', 0, 4 * tick, 0, 0 }, LegPrices::FROM_FILL, false, now);
| Call | Description |
|---|---|
place(owner, market, spec, now) |
One smart order. Returns its id, or 0 if refused. STOP / STOP_LIMIT are sent to CME at once as native stops; MIT, LIT, TRAIL, TRAIL_LIMIT are held by the program until they trigger; MARKET / LIMIT are sent at once. |
placeOco(owner, market, a, b, cancelOnFill, now) |
Two orders where one cancels the other. Quantities may differ. cancelOnFill = false reduces the other order on a partial fill, true cancels it. Returns the id of a. |
placeBracket(owner, market, entry, a, b, prices, cancelOnFill, now) |
Entry plus two exit orders (opposite side, any type except market) linked as OCO. prices = LegPrices::FROM_FILL: exit prices are distances from the entry fill price (profit side for limit / touch orders, loss side for stops). LegPrices::ABSOLUTE: exit prices are prices. Exit quantities follow the entry fills. Returns the entry id. |
cancelOwner(owner, now) |
Cancel all smart orders of an algo (done for you when the algo stops). |
SmartSpec fields: type, side ('B'/'S'), qty, trigger (stop / touch price), limit (limit price; for
TRAIL_LIMIT the distance beyond the stop), trail (trailing distance). STOP / STOP_LIMIT legs of placeOco and
placeBracket are sent to CME as native stops when the leg becomes active.
All prices are in the instrument's price units and must be on the tick grid. Each smart order's life (open, triggered,
fills, final state) is written to the log.
Tip
Place smart orders from inside your algo's callbacks (maintain, onFill, onButton). Orders placed there are
sent at the end of the same callback.
Writing a New Algo Type
An algo type is a class derived from Algo plus one line in the ALGO_TYPES table, both in algos.cpp
(name, Algo Window view, one line per instrument or not, schema function, create function). Put the trading rules in
their own header, as marketmaker.h and spreader.h do, so other programs can reuse them.
| Method | Purpose |
|---|---|
schema(interfaceschema*, hidemask) |
Declare the type's inputs and line buttons for its view. |
setParams(datainput*) |
Read and validate inputs at Submit; return false to refuse (BADCFG). |
maintain(now) |
Called on market data and order events while RUNNING: place, move and cancel orders. |
onFill(slot, px, qty), onBook, onButton |
Optional event hooks. onFill receives the filled quantity and price after duplicate and missed fill reports are sorted out. |
ownsPosition, maxPosition, disable, keepOnDisableAll |
Optional: position ownership, limit, Disable behavior. |
Orders are sent through order slots (send, cancel, work, from OrderSender in ordercore.h) so the framework
tracks state, pacing, rejects and fills for you; the line's position and P&L are in position, avgPrice and pnl()
(Position). See MarketMakerAlgo and SpreaderAlgo in algos.cpp for complete examples.