In 2009 Desjardins commissioned Nexa to build the Conditional orders feature into their desktop DDPlus platform. Conditional orders were a major addition to our feature set.
Simple orders are used for buying & selling a single stock for a specific quantity and price. Conditional orders are actually collections of simple orders which can be set up so that the behavior of one order in the group can influence another order. Some of the behaviors that can trigger actions in other orders include an order being executed, or a particular stock price reaching a threshold. Some of the resulting actions that can be configured are sending an order to the exchange or canceling other orders in the group.
This project was a multi-team effort and my contribution spanned the following areas:
C++ Code Sample OrderCacheManager class (PDF)
3 categories of conditional orders were defined:
For detailed definitions of Conditional orders see Investopedia.
The conditional order required us to define a new order type in our system which was a recursively nested tree structure. This structure could contain n orders nodes and where each order node could branch out to child decedents. A descendent could be an entirely new conditional order or a simple order.
The type of conditional order that best illustrates the nested structure is the Trade-triggers-order (TTO) type. At the topmost layer, a TTO has one simple order, which branches out to a Trade-cancels-order (TCO) conditional order. TCOs contain up to 3 simple orders. The strategy behind this type of conditional order is as follows: In the beginning, the topmost singleton order is sent to the market, while the TCO orders are held back until the triggering condition. The execution of primary singleton order triggers the 3 singleton orders in the TCO to go to market. When the first of those 3 singleton orders execute, the remaining 2 singletons in the TCO will be canceled.
I was responsible for creating the real-time display and the user interaction for conditional orders on the DDPlus order panels. I displayed the conditional order structure as nested folders because I needed to show these orders in a consistent manner with legacy style orders (see screenshot above). I wrote the functionality to be able to add, modify and delete child orders as context menu actions on the orders panel. I also wrote a client side order management & caching mechanism that served 3 goals:
1) To cleanly separate out the storage of order data from the orders panel view.
2) Lookup mechanism to find a conditional order or child order's data when it's being manipulated by the user on the order panel.
3) Reconstruct conditional orders when they are received as singleton orders.
In 2012 OTC Markets Group (formerly known as 'Pink Sheets') completely redesigned their quote dissemination service. It migrated away from using a FIX-based legacy protocol to a new binary protocol. The motivation for this transition was to be able to transport more data at faster speeds, an overall trend in financial services. Nexa's trading system already had feed handler for OTC data, but the drastic protocol change required a completely new implementation. I wrote a custom data feed handler in Java to convert the real-time binary data received into Nexa's custom quote message formats. The result was a seamless protocol transition that was transparent to our customers. Customers who used our trading terminal to look up OTC listed securities would see the same data display. The feed handler was designed to run continuously throughout the day and was robust enough to recover from hardware & network outages with minimal impact. It ran in production Linux environment and periodically reported performance statistics including the number of messages processed, average, minimum and maximum latency. The project took 4 months of analysis, development, testing, and deployment.
My design document for the feed handler (PDF)
Java code sample of parsing code from my OTC markets data feed handler (PDF)
Original protocol specification provided by OTC Markets Group (PDF)
Market data is the oil that fuels our trading platform. The AxisPro trading platform allows users to lookup real-time quote information directly in the trading box as shown below. The information in the quote, like bid and ask prices, help the trader make informed decisions about the order they want to place. Quote information is presented in a uniform way regardless of the stock exchange the symbol is listed on. In order to provide this consistency, we have to process market data streams from different stock exchanges, like NYSE & NASDAQ and translate their data into a common message format before a quote can be disseminated throughout our system. The challenge in listening to these different data streams is that each stock exchange disseminates data differently. Some send data using standardized protocols while others define custom protocols. Additionally, these protocols are constantly changing, driven by industry compliance rules and financial regulations.
The FIX protocol is a legacy, standardized protocol in the financial sector. It's a text-based, TCP based protocol. Each message is transmitted as a list of key-value pairs.
For example a quote message for the stock IBM could look like this in FIX:
[55 = IBM | 132 = 130.26 | 133 = 132.27]
Would translate to:
symbol = IBM, Bid-Price = 130.26, Ask-Price = 132.27
The keys for a symbol, bid price, and ask price are transmitted as predefined numeric identifiers in FIX.
In contrast, the new protocol transmits data in binary where the fields of a message are arranged in a specific order and each is defined to take up a specific amount of space. Binary data is transmitted as binary 1s and 0s, and can only be decoded by knowing the message definitions, not by looking for a key.
Basic Quote Message anatomy for OTC quotes:
Two characteristics about the protocol made the feed handler implementation challenging:
1) The data provided by OTC for a quote was partitioned in a way where the bid and ask side could be provided in separate messages. Essentially they could send half a quote. Also, quotes were sent without the stock symbol inside them. The rest of Nexa's system always expects complete quotes. This required my implementation of the feed handler to save the state of half quotes, and look them up when a counterpart quote half was received. Additionally, since OTC quotes provided a symbol identifier, instead of an actual symbol, this information had to be looked up as well. These information retrieval and saving steps had to be continuously done while processing OTC's live data stream while introducing as little latency as possible. It is common for stock exchanges to send quote messages that can be processed atomically, without needing to look up referential information. OTC's design choice made the protocol data transmission very streamlined but increased the work the feed handler was doing. This created a performance hit that I had to manage by using lookup tables and reading and writing information to disk only when absolutely necessary.
2) The other challenge to this feed handler was handling the lossy nature of UDP data. The UDP protocol does not guarantee delivery of all data packets. The trade-off is that data received over UDP is much faster than TCP, but can lose data. We had a high bandwidth connection between our data center and OTC to keep data loss at a minimum. But when it did happen at high congestion time periods like market open, we had to be able to handle it by requesting the missing messages from OTC. The OTC markets made available a separate TCP based re-transmission service for retrieving lost messages. We detected data loss by comparing the sequence number provided in every message with the previous. When there was a sequence gap this meant data loss had occurred. Performing a re-transmission request was an expensive operation because it paused our data processing of live data and introduced latency in the end user's data displays. During a re-transmission request, the feed handler had to stop publishing quote messages and instead started buffering data received from OTC to disk. I held back publishing new data until I could retrieve the missing messages. At the end of gap fill process I would read and publish the saved data . Pages 15 and 16 of my design document illustrate the re-transmission process conveyed through activity diagrams. The document also goes into detail with the different types of gap recovery mechanisms since we had to use different ones depending on the size of the gap.
In 2010 the Options Clearing Corporation (OCC) and other options industry leaders mandated an industry-wide change in the symbology used to represent option contract symbols, the plan was called the Options Symbology Initiative (OSI). Option contracts are financial instruments that can be bought and sold like stocks but they come with the added dimension of granting the buyer the right, but not the obligation, to buy or sell an underlying stock asset. Additionally the option contract holder is granted the privilege to buy at a specific price and time in the future.
The legacy symbology was a 5 character coded symbol which required the user map letter based codes back to predefined dates and prices in order to know how it worked.
Expiration Date
The 4th character in legacy symbology represented an option's expiration date. The expiration was the date the option holder would be able to buy the underlying stock in the future.
Strike Price
The 5th character in legacy symbology represented an option's strike price. The strike was the price the option holder would be able to buy the underlying stock at.
The new OSI format expanded the length of the options symbol to 21 characters and made the symbol completely self-describing. The new symbology was lengthier than the retired version, but the trade-off was that it became easier to derive the expiration date and strike price since the user didn't need to memorize a table or lookup this information.
My role on the project included planning and implementing changes in AxisPro front-end application, backend servers and protocol changes between client and server. Some of the usability challenges I addressed in the GUI included making it easy for users to type in option symbol with autocomplete. Also since the new options format created flexibility in how options were displayed back to the user, I created a customization feature that allowed the user to change the option display format on demand.
The initiative provided guidance for how financial firms and systems should communicate options symbols to each other, but it didn't mandate the exact display of options symbols to end customers. For example, we could apply a simplification on the OSI symbology to remove preceding & trailing zeros, and add in a decimal point in the strike price. Since we had this flexibility we offered our customers 3 display formats of OSI symbology in the user-facing parts of our software.
I implemented customization controls in AxisPro that would translate on demand between different display formats of the symbology. Below are the 3 types of OSI symbology display formats we offered to customers.
The OSI conversion project took approximately 6 months and was a company-wide effort. All interfaces between servers and client applications used for transmitting option data had to be modified. During the initial deployment phase, we prepared code switches that could be configured by the operations team to enable and disable OSI support. Full backwards compatibility was required for a certain period after the go live date.
In 2015 I worked on a project to improve the loading of option chains in AxisPro's option box. An option chain is a list of option contracts associated with an underlying stock symbol. Each option chains contain references to hundreds of individual option symbols. Due to the growth of the options market over the last few years, the loading of options chains into AxisPro's option box became such an expensive operation that it was affecting the performance of the entire application. The option chain box displays the live prices for each option symbol. And the performance bottleneck was primarily due to the number of live market data subscription required for each symbol in the chain. See my previous project for a description of Options
In addition to the option prices in each row, we also displayed 5 option Greek values - Delta, Gamma, Vega, Theta, and Ro. These Greek values are a measure of the sensitivity of an option's price to different factors and are used as indicators of risk or opportunity to traders. The greek values do not come from any exchange, instead, they are calculated in real time with each price update of an option.
In order to maintain a responsive application, a different approach was needed to the way the option box loaded, subscribed to, and calculated data. I coded my improvements in C++ using the QT library. My changes resulted in allowing users to trade options efficiently. Additionally, my changes allowed customers to analyze large option chains from the most popular stocks without affecting application performance.
Up to 4 option boxes are available in an AxisPro layout, allowing the user to lookup 4 different chains. Traders can browse and search for options by specifying an underlying stock symbol in an option box. In the screenshot below, the top left entry field shows the selected stock symbol 'AAPL'. During the loading of an option chain Nexa's market data system retrieves the list of associated options for the given underlying, at the same time the client subscribes to market data on each option.
Over the last few years, the options market has grown in popularity and option chains have also grown in size. Some popular stocks like MSFT, GOOG, AAPL have option chains of over 1000 option symbols each. Prior to this increase in popularity, option chains sizes were typically on the order of hundreds. Since each option symbol has its own bid price, ask price and last price which change in real-time, the size of these chains is significant because of the cumulative amount of data being received. Additionally, the greek values are recalculated upon each option price update.
The problem we experienced with the old way of loading the option chain was that everything happened at once. The key to improving performance was to lazy load some data and throttle market data subscriptions to let the CPU catch up on drawing different parts of the display. I delayed or slowed down the loading of data on parts of the display which were not visible yet. At the same time keeping the visible parts of the option chain updating and responsive to user action.
The new loading behavior can be described in 4 stages:
Stage 1
Load the option chain list first without subscribing to any data or doing any Greeks calculations. During this time the remaining columns were empty.
Stage 2
Once the full option chain list was loaded, then market data subscriptions were initiated for the first 1/3 of the options in the list. When the option detected that the first third of market data subscriptions have started then data subscriptions will be initiated for the next third, and so on.
Stage 3
This part optimized the workload surrounding the calculation of the Greek values. Overall greek values were being recalculated more often than needed. Instead of recalculating the 5 greek values upon each new price update, I user a timer mechanisms to perform the recalculations periodically.
Stage 4
This part optimized how the Level 2 Montage quote tab subscribed to data. A level 2 quote is a more data-intensive quote and thus only one is allowed per option box. It is triggered by selecting an individual option in the chain. The key to optimizing this part of the loading was to only allow the Level 2 quote to initiate after all Level 1 quotes were complete and after a round of Greeks calculations was complete. Since just clicking on a row triggers the application to load a Level 2 quote subscription, users who were click-happy posed a problem in the original implementation. Frequently changing L2 subscriptions on different option symbols could impact performance. I addressed this issue by recognizing the last row clicked on within the last second.
In 2015 our customer Desjardins Bank commissioned a Mac OS compatible version of our Windows desktop trading platform AxisPro. A number of their customers had been asking for a Mac version of the software, but Desjardins was not able to invest the resources to do a rewrite. As an alternative, I proposed a solution that used an open source framework called Wine that allows Windows application to run on Mac. Within 3 months I delivered a fully functioning prototype branded 'DCotes'.
As the sole person working on this project, I accomplished the following:
AppleScript code for DCotes Update Program (PDF)
Using the open source Wine framework was the quickest way to deliver what Desjardins wanted without spending a lot of development effort. Wine is a compatibility framework that basically contains the most essential parts of the Windows subsystem. Any Windows executable files running on a Mac are intercepted by the framework where it translates Windows OS calls from the source Windows application to equivalent calls in Mac OS. This approach is not emulation and results in performance that is almost equivalent to the original version in Windows. In fact, in our performance tests with real-time market data, we could not detect any difference between the software running on the two operating systems.
While we had confidence AxisPro could run using Wine on Mac OS there were still some hurdles to overcome. The Wine framework is typically a separate install, but we needed to provide the user with only one distributable file they could download from us. Having the user install a separate application to run ours was not acceptable. I found another open source tool 'WineBottler' which takes a Windows application and packages the Wine framework into one Mac application.
An important aspect of any desktop application is the ability to update it when a new release is available. I created a companion script called 'DCotesUpdate', using AppleScript. It was responsible for checking if a new version was available from Nexa and installing it if the user wanted. The separate update script was needed because our standard update method did not work with Wine.
There were also some usability and functionality issues we encountered with AxisPro running on Mac OS that we could not ignore. These problems had to do with how left mouse clicks were recognized and with the ability to undock windows from the main application area. I solved this problem by writing custom C++ code to intercept these actions and modify the application's behavior to work properly on Mac OS.