Skip to content
Get Started

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).

g++ -std=c++17 -O2 algos.cpp -I nanocondaroot/include -L nanocondaroot/lib -lnanoconda -o algos
running algos
Usage: ./algos -e exchange -s symbol1,symbol2,... -u username -p password -a account [-c cpu]

./algos -e XCME -s <symbol1>,<symbol2> -u <username> -p <password> -a <account> -c <cpu>

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.

g++ -std=c++17 -O2 -fPIC -shared algos.cpp -I nanocondaroot/include -L nanocondaroot/lib -lnanoconda -o algos.so
nanoconda-cli -a pluginloader -i algos.so -- plugin -e XCME -s <symbol1>,<symbol2> -u <username> -p <password> -a <account>
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

  1. A quote is filled (fully or partly).
  2. All quotes on that side are cancelled.
  3. 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).
  4. 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:

  1. 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).
  2. 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 (log RISK ... 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

  1. 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).
  2. The quote follows the other leg's market, within the slop tolerance.
  3. 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 / HEDGED lines.
  4. 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.