Stops & Icebergs Sub-Chart Indicator
What is it?
This add-on identifies the executions of Stop Orders and the evolution of Iceberg Orders. Its main features are:
- 100% accurate detection of:
- Iceberg orders execution
- Stop orders execution
- The true size of the aggressor order (e.g. "trade reconstruction"). This includes the entire size of partially executed limit orders. The limit price of such orders also becomes known.
- Ability to apply order size filter on any of the above
- Instant computation and display of each update. Not once per minute or second, but whenever it happens
- Computes and displays the results from the moment of instrument subscription, not from the moment of enabling the add-on
- Processes millions of market data events per second on a regular laptop. This allows to re-compute the indicator instantly whenever user changes the settings
- (An upcoming feature currently in development) Ability to create custom indicator lines with a couple of lines written in JavaScript. This short script has access to all the data including Stops and Icebergs info. The built-in lines (Stops and Icebergs) are also implemented as short JavaScript code and can be used as examples.
Installation
Technical details: download the add-on's jar file either from the download section in your marketplace dashboard or using the direct link. In Bookmap click Settings → Addons → Add, and add the jar file.
For more details, see MBO Bundle Installation Guide.
Background
Exchanges process orders in atomic manner which means strictly according to the order of their arrival to the exchange (unless it applies artificial speed bumps). Orders that can't be immediately executed (e.g., due to their limit price) become resting (or working) orders and form the order book. A new order can be matched against one or more or none of the resting orders. Because only the newly arrived (or newly replaced) order may initiate a trade, we call it the aggressor order, and its counterparties -- passive orders.
The trade object
A trade can be represented by a single aggressor order with a list of affected by it passive orders. Here are examples of such objects in JSON form:
{
"timestamp": 1553517589009337101,
"orderId": "645557118818",
"isBuy": true,
"isStop": false,
"orderSize": 7,
"passiveOrdersList": [
{
"orderId": "645557118724",
"price": 11234,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6222141269
},
{
"orderId": "645557118725",
"price": 11234,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6222061501
},
{
"orderId": "645557118733",
"price": 11234,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 5291476329
},
{
"orderId": "645557118734",
"price": 11234,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 5291466590
},
{
"orderId": "645557118735",
"price": 11234,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 5291403982
},
{
"orderId": "645557118740",
"price": 11234,
"tradeSize": 2,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 2,
"remainedSize": 4,
"lifeTime": 5283330257
}
]
},
{
"timestamp": 1553517571175695053,
"orderId": "645557115281",
"isBuy": true,
"isStop": true,
"orderSize": 4,
"passiveOrdersList": [
{
"orderId": "645557113818",
"price": 11234,
"tradeSize": 2,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 2,
"remainedSize": 0,
"lifeTime": 260762777483
},
{
"orderId": "645557113822",
"price": 11234,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 260762748266
},
{
"orderId": "645557113831",
"price": 11234,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 260758484854
}
]
},
{
"timestamp": 1553516837968759321,
"orderId": "645557101905",
"isBuy": true,
"isStop": false,
"orderSize": 64,
"passiveOrdersList": [
{
"orderId": "645557101746",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6684971251
},
{
"orderId": "645557101747",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6684972179
},
{
"orderId": "645557101751",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6683991775
},
{
"orderId": "645557101753",
"price": 11227,
"tradeSize": 4,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 4,
"remainedSize": 0,
"lifeTime": 6683947717
},
{
"orderId": "645557101754",
"price": 11227,
"tradeSize": 3,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 3,
"remainedSize": 0,
"lifeTime": 6683426442
},
{
"orderId": "645557101765",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6681909924
},
{
"orderId": "645557101775",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6680682795
},
{
"orderId": "645557090167",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": true,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 58938807765
},
{
"orderId": "645557101788",
"price": 11227,
"tradeSize": 2,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 2,
"remainedSize": 0,
"lifeTime": 6677298222
},
{
"orderId": "645557101789",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6663871233
},
{
"orderId": "645557101790",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6663831348
},
{
"orderId": "645557101791",
"price": 11227,
"tradeSize": 2,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 2,
"remainedSize": 0,
"lifeTime": 6664338246
},
{
"orderId": "645557101792",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6664322014
},
{
"orderId": "645557101793",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6664290941
},
{
"orderId": "645557101794",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6663946826
},
{
"orderId": "645557101795",
"price": 11227,
"tradeSize": 2,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 2,
"remainedSize": 0,
"lifeTime": 6663919928
},
{
"orderId": "645557101797",
"price": 11227,
"tradeSize": 4,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 4,
"remainedSize": 0,
"lifeTime": 6663880508
},
{
"orderId": "645557101805",
"price": 11227,
"tradeSize": 3,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 3,
"remainedSize": 0,
"lifeTime": 6659504863
},
{
"orderId": "645557101806",
"price": 11227,
"tradeSize": 8,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 8,
"remainedSize": 0,
"lifeTime": 6659418603
},
{
"orderId": "645557101809",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6658736401
},
{
"orderId": "645557101810",
"price": 11227,
"tradeSize": 2,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 2,
"remainedSize": 0,
"lifeTime": 6658707183
},
{
"orderId": "645557101811",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6658664981
},
{
"orderId": "645557101812",
"price": 11227,
"tradeSize": 2,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 2,
"remainedSize": 0,
"lifeTime": 6657991127
},
{
"orderId": "645557101813",
"price": 11227,
"tradeSize": 2,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 2,
"remainedSize": 0,
"lifeTime": 6657969330
},
{
"orderId": "645557101814",
"price": 11227,
"tradeSize": 2,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 2,
"remainedSize": 0,
"lifeTime": 6658602372
},
{
"orderId": "645557101815",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6658582431
},
{
"orderId": "645557101816",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6658561098
},
{
"orderId": "645557101817",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6659428806
},
{
"orderId": "645557101821",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6658584286
},
{
"orderId": "645557101822",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 6658570372
},
{
"orderId": "645557101484",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": true,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 24737767907
},
{
"orderId": "645557101684",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": true,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 9745074560
},
{
"orderId": "645557097906",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": true,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 58952449016
},
{
"orderId": "645557101319",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": true,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 32968388233
},
{
"orderId": "645557101211",
"price": 11227,
"tradeSize": 3,
"isNativeIceberg": true,
"isCustomIceberg": false,
"totalTradedSize": 3,
"remainedSize": 0,
"lifeTime": 38806541808
},
{
"orderId": "645557101511",
"price": 11227,
"tradeSize": 2,
"isNativeIceberg": true,
"isCustomIceberg": false,
"totalTradedSize": 2,
"remainedSize": 0,
"lifeTime": 22761214588
},
{
"orderId": "645557101891",
"price": 11227,
"tradeSize": 1,
"isNativeIceberg": false,
"isCustomIceberg": false,
"totalTradedSize": 1,
"remainedSize": 0,
"lifeTime": 808857398
}
]
},
When a new trade occurs the add-on creates such an object and computes some of its properties that are not directly included in the market data, e.g. Iceberg, Stop, the size of the aggressor order, etc. Then it's used to update the values of displayed lines.
The order size filter
Notice that the orders size filter refers to the order size, not the trade size. This is because traders are typically interested to track the larger orders and because the actual order size of all participating orders can be larger than their traded size in a particular transaction. This happens when a Stop-Limit order is only partially executed, when a limit order (especially iceberg order) was already executed earlier.
To summarize, after the trade object is computed, it is used to update the two cumulative-volume-delta (CVD) lines on the chart as following:
Stop orders CVD | Iceberg orders CVD | |
---|---|---|
Affected by | Aggressive orders where isStop is true | Passive orders where isIceberg is true |
Value | The sum of tradeSize of passive orders list | Its own tradeSize field |
Sign | Positive if isBuy is true | Positive if isBuy is false |
Order size filter applies on | orderSize of the aggressor order | totalTradedSize + remainedSize of Iceberg orders |
Accumulation mode
Each event represents the traded volume of that event. The sign of the resulting value is negative for Sell orders and positive for Buy orders. It wouldn't be possible to digest visually every data event. Therefore the indicator line represents some sort of accumulation of past events until the current moment. For convenience, there are several accumulation methods, here are the details:
Accumulation type | The time parameter T means | Accounted time interval | Indicator's value |
---|---|---|---|
SUM | N/A | From data start | Regular sum |
EXPONENTIAL | T - the decay rate (half-life) | From data start | Sum, gradually decaying by 50% every T |
RESET (every T) | T - tells how frequently to reset, e.g. every 1 minute | From last reset point | Regular sum |
SLIDING | T - the width of the sliding window | From T time ago | Regular sum |
SAME_SIDE_SUM | N/A | Accumulates Buy volume until any Sell volume, and vice versa | Regular sum |
Voice and Text alerts
Types of alert triggers
Currently there are 2 types of triggers:
- A burst of Iceberg orders executions
- A burst of Stop orders executions
Both are triggered when the volume traded by corresponding orders is greater or equal V
within time interval T
where V and T are configurable parameters.
Methods of reporting the alerts
Currently there are two methods to receive alerts: as text messages in File->Alerts window, and as a voice synthesized from a text message. Future versions may custom include non-voice sounds. The content (or format) of the message is configurable simply by editing corresponding fields. Variable properties of the alert can be placed anywhere in the message using keywords surrounded by ${}
, for instance:
Stop orders traded ${size} contracts at ${price} within ${time} milliseconds
When an alert is triggered, these variables will be replaced by actual values. The following keywords are supported:
${type}
- the type of the trigger, e.g.Stop
, orIceberg
${symbol}
- Full instrument's name such as ESU0${exchange}
- the exchange, e.g. ES${sym}
- 2 first letters of${symbol}
${size}
- the traded volume which triggered the alert${side}
- eitherBuy
orSell
. Note that the if the event is triggered by Stop order(s) trading against Iceberg(s) orders, theside
of these orders is opposite to each other${time}
- the time interval in milliseconds during which it occurred. If it's caused by a single aggressive order, thistime
is zero${price}
- at which price the${size}
is traded. If there are multiple prices, the${price}
represents VWAP (volume weighted average price)${multi}
- The system aggregates the alerts as long as the audio system is busy (e.g. pronouncing the previous alert). Then multiple alerts are aggregated and reported as a single alert. The${multi}
keyword acts as a separator between the message used for a single alert and the message used for an aggregated alert. If this keyword is absent, the entire message is used regardless of whether the alert is aggregated or not.${N}
- Represents the number of aggregated alerts (appears as1
for a single alert)
Examples:
${type} ${side} alert at ${sym}: ${size} contracts
${type} ${side} alert at ${symbol}.${exchange} (${sym}): ${size} contracts at ${price} within ${time} ms${multi}Miltiple (${N}) ${type} ${side} alerts at ${symbol}.${exchange} (${sym}): ${size} contracts at ${price} within ${time} ms
${sym} ${type} alert: ${side} ${size} in ${time} millis${multi}${sym} ${type} multi alert: ${side} ${size} in ${time} millis by ${N} triggers
${sym} ${type} alert: ${side} ${size}
- a short alert for voice messages${sym} ${type} alert: ${side} ${size}${multi}Multi {sym} ${type} alert: ${side} ${size} by ${N} triggers
- if you want to know which alerts consist of multiple alerts
For voice alerts it's recommended to use very short and simple pattern. For example, ${sym} ${type} alert: ${side} ${size}
will sound like ES Stop alert: Buy 50
. This will reduce time it takes the robot to pronounce it.
Alerts vs Indicator
The latest version allows to align alerts with indicator values by selecting "Apply threshold on indicator..." checkbox.
If not selected, the two are not supposed to be comparable. A simple analogy: when a fire alarm is triggered, it doesn't tell what will be the maximum temperature during the fire. For that it would need to either delay the alert (not acceptable) or to know the future (not possible).
Due to the above, the indicator's values may reach higher magnitude. From the other hand, the indicator accumulates Buy and Sell volume with opposite sign, therefore in theory (because it rarely happens) a consequent Buy Stop 500 and Sell Stop 500 will not change the indicator, but will trigger two alerts.
Note: If orders size filter is enabled, it's similarly used by the indicator and the alerts system
Important Notes
Data Aggregation
The latest version of Bookmap includes some performance optimizations.
When the application is under heavy load and new events happen faster than Bookmap can process, an aggregation mechanism turns on.
In this mode, Bookmap aggregates several individual events into one, improving performance at the cost of losing accuracy.
This allows Bookmap to operate faster, avoiding freezes and delays in data processing, but may affect indicators that rely on data microstructure accuracy. SI On-Chart and SI Sub-Chart are examples of those indicators.
When the automatic aggregation mechanism turns on, SI indicators may become unpredictable (lose detections, show fake detections, etc.)
Therefore, if you are using SI indicators and need accurate data, you can disable automatic aggregation to ensure you get reliable data.
But we do not recommend doing so, as Bookmap may not run smoothly during volatile market conditions. This means you’ll be unable to perform real-time actions like closing positions or moving orders.
To disable automatic aggregation go to Settings > Performance > Automatic aggregation and set Event queue size threshold to Never.
Again, DO NOT DISABLE AUTOMATIC AGGREGATION if you need to perform real-time actions and execute trades.
If you’re not trading and you’re happy that Bookmap may occasionally slow down under heavy load, you can change the default parameters to increase the SI detection accuracy. Set the events queue slider to 20000 and delay to 5 seconds.
When the aggregation mechanism is enabled for the first time during a Bookmap session, the SI Sub-Chart add-on will display the following warning:
Note: With aggregation enabled, the SI Sub-Chart add-on is still operational, but it cannot get the required information from parts of the data which were aggregated, so some detections may be missing.
Missing MBO data
Sometimes the MBO data feed may disconnect, for example a bad internet connection or problem with the data provider. In this case, the add-on will warn you with the following notification:
The add-on will continue to work as usual as soon as the MBO connection is restored.
Note: CME does not provide MBO data for implied orders. Read more about implied orders here.
Stops & Icebergs Sub-Chart Indicator FAQ
Why do I see different Stops & Icebergs values between different PCs?
This could be due to one of the following reasons:
Data Aggregation - It's the performance optimization feature. It allows Bookmap to operate faster, avoiding freezes and delays in data processing, but may affect indicators that rely on data microstructure accuracy. SI On-Chart and SI Sub-Chart are examples of those indicators. Read more here. Aggregation can be applied differently on different PCs, so detection will be different too.
Resets - There is always some difference between event timestamps on different PCs, +/- 20ms. It's enough to have different detections, on one PC a reset may be applied before a reset on another.
Different Stops & Icebergs add-on versions - We improved the SI On-Chart and SI Sub-Chart multiple times, improved the detections accuracy and the add-on performance. The detections may be different because of this.
Why do I see different values between SI On-Chart and SI Sub-Chart?
First, make sure you use the SI On-Chart and SI Sub-Chart latest version.
Also, note that the volume calculation logic is different in Sub-Chart and On-Chart Icebergs Indicators. For a more reliable comparison, configure indicators in the same way:
- Disable filtering for SI Sub-Chart and set the ‘Accumulate as’ parameter to SUM.
- Set threshold for SI On-Chart to 0 and select individual icebergs events only.
- Now it is time to zoom in and compare the volumes. Note that the engine works differently, and SI Sub-Chart does not include some detection events.
Why don't I see any icebergs on a specific instrument on CME?
CME does not allow using native iceberg orders on some instruments.
List of known CME instruments without icebergs:
Direct download links
- Latest : download
Versions changelog
3.1.0
Published on 25-Sep-2020.
- TBA
3.0 (alpha/experimental)
Published on 12-Aug-2020.
- Added a new accumulation method: Sliding window
- (Experimental feature) Voice and Text alerts
- Minor changes in user interface (making it more compact)
- Other minor improvements
2.8 (beta/production)
- minor bug fixes
- performance improvements
- update notification system
2.2
Published on 11-June-2020.
- Fix: a false alarm about non-MBO data
- Fix: Default color button
- Improvement: updates notification mechanism (see status in the settings panel)
- Fix: crash when inheriting chart settings from another chart