SPREAD TRADER 3.0 Architect: Rohan S. Patil GENEVA TRADING 980 N Michigan Avenue Chicago, IL 60616 1 Index 1. Introduction Purpose of SpreadTrader and its functionality 2. Background Describes previous attempts 3. SpreadTrader 3.0 Architecture diagram and description of various components of the SpreadTrader 4. Spread Architecture diagram and description of various components of a Spread 5. External I/O User Inputs and system outputs 6. Screen shots Screen shots of various windows in SpreadTrader 2 7. SpreadTrader 3.0 versus SpreadTrader 2 A comparison 8. Basics of FIX FIX Architecture 9. Sample Code Demonstrates use of FIX engine to construct FIX messages 10. Lime Vs REDI How these third-party APIs work? 11. Conclusion Looking ahead at SpreadTrader 3.0 2 Introduction The purpose of developing the SpreadTrader is to trade multi-instrument equity spreads at rapid speeds. It is designed to provide higher quality execution while minimizing the execution risk. My intent is to enable the trader to trade multiple spreads simultaneously and to be able to execute spreads at right prices. I believe that this project will greatly reduce the execution risk resulting in increased profit and free the user to explore a lot many opportunities in today’s markets. It will directly affect the way trading is conducted in Maggiore Fund and the use of high end technology would give it an edge. SpreadTrader essentially is an electronic eye which continuously monitors the equity markets and computes the pre-defined spread prices. The execution algorithm is activated once certain conditions are met. Execution of initiating leg is started. The balancing legs are closely monitored for any adverse change in prices. Further execution depends on whether the right price can be achieved based on the price of balancing leg and the size available. If initiating leg is filled, balancing leg is activated. The whole process not only gets the correct price for the spread but also provides tremendous speed of execution. Please note that execution algorithms can be customized as per the user requirements. 3 Background Previous attempts of developing a similar system using other platforms are described below: 1. Fall 2008: SpreadTrader 1.0 Platform: Excel / VBA Third Party API: Redi Plus (GS) Although, scripting in VBA easier from a programming point of view, the speed of execution was limited. Also, lack of multi-threading capabilities hampered the systems ability to trade multiple spreads. Having said that, a basic SpreadTrader was built which could handle a 2-3 spreads with a total of 15-20 stocks. 2. Spring 2009: SpreadTrader 2.0 Platform: C#.NET Third Party API: Redi Plus (GS) .NET offered both speed of execution and multi-threading capabilities which lacked in the previous version. However, a new requirement of using Level 2 quotes was added to this SpreadTrader. Surprisingly, Redi provides L2 data through DDE links which are not supported in .NET. Additionally, speed with which SpreadTrader could send orders in .NET was restricted by Redi to 3-4 orders per second. 4 SpreadTrader 3.0 : Architecture and description of the components Spread Trader SPREAD FORM 1 CITRIUS® DYNAMIC DATA STORAGE SEND ORDERS (SYNC) ORDER OUT ORDER EXECUTION DATA SPREAD FORM n FIX ENGINE LIME SERVER 5 1. Dynamic Data Storage: This is essentially a data source which is rapidly updated by Citrius®. A sort algorithm is used to store the data in ascending (ask prices) and descending (bid prices) order. Stocks contained in this data are added and removed after a spread is added or removed by the user. Technically, this is a listener to the data providing API which is updated using RMI (remote method invocation). All the technicalities are take care of by their class libraries. SpreadTrader simply adds a listener method. (More on RMI: http://java.sun.com/javase/technologies/core/basic/rmi/whitepaper/index.jsp) Data acquired from Lime Servers using RMI. (Source: java.sun.com) 2. FIX Engine and FIX communication: For basic information on Financial Information eXchange (FIX), please refer this. FIX communication is essential for rapid execution. Orders are sent over the FIX server and status messages are received at great speeds. SpreadTrader uses FIX for these basic operations. A FIX engine is used to communicate with the LIME’s FIX server (Note: This is server is different from the Citrius® server which only provides data). Technically FIX engine provides the required support on session layer of the OSI model and it provides us with an interface at the Application layer. Later in this document I explore this interface in detail. Please note that although FIX protocol is standardized, the FIX API is not. Thus, although the functionality remains the same, syntax for different engines is different. We may use following free, open source FIX engine but there are other available engines which come at a cost. 6 QuickFIX/J: QuickFIX/J is a full featured messaging engine for the FIX protocol. It is a 100% Java open source implementation of the popular C++ QuickFIX engine. Essential features of this engine can be found here: http://www.quickfixj.org/. 2. (A) Order Execution Data: This stores the status messages of the orders sent in the market. This is a static data storage which is updated at real time speed by the FIX server. This is read by the spreads running at regular intervals for updates on the orders sent by the spreads. Each order has a unique id called “SecurityIDSource” which is an encoded string used to identify the spread that sent the order, long or short leg and the stock number. This greatly reduces the computational efforts to sort out these messages. SecurityIDSource is attached to the order when it is sent and it is basically “echoed” back through FIX. 2. (B) FIX Messenger: This messenger is used to construct the FIX messages. Please refer sample codes in appendix to know more about how a FIX message is constructed. 2. (B) Send-order sync: Synchronization of order-sending is achieved using this block of code. It would serialize the orders when multiple spreads are active and send orders at the same time. It is only a precaution against any thread-safety issues which “may” arise. 7 Spread : Architecture and description of the components Blocks using User settings DDS of SPREADTRADER DYNAMIC DATA STORAGE BID / ASK PRICES, SIZES CALCULATOR SPREAD PRICES ORDER EXECUTION MONITOR BALANCING LEG PRICE of BALANCING LEG INITIATOR START MONITORING BALANCING LEG EXECUTE INITIATING LEG BALANCE To SEND ORDER (SYNC) FIX MESSANGER CANCEL UPDATE INVENTORY DATA UPDATE SPREAD DATA ORDER EXECUTION AND INVENTORY DATA USER SETTINGS AND SPREAD DATA 8 1. Dynamic Data Storage: Similar to the DDS of the SpreadTrader as a whole, every Spread has its own data storage which is synchronously updated. It is a subset of the SpreadTrader’s DDS and it contains only those stocks which are part of the concerned spread. Every spread runs a separate thread to delegate the task of updating the data. This activity continues as long as the spread is open. 2. Calculator: A calculator, as the name suggests, calculates the spread price using four combinations of bid and ask prices of long and short legs of the spread. These combinations are Bid / Bid, Bid / Ask, Ask / Bid and Ask / Ask. Intermediate steps involve calculating long leg on Bid and Ask and short leg on Bid and Ask. Calculations are done for the sizes executable for each of these four combinations. Following is the list of variables calculated synchronously by the calculator: A. Spread Price a. Bid / Bid b. Bid / Ask c. Ask / Bid d. Ask / Ask C. Price of Long Leg a. Bid b. Ask E. Price of Short Leg a. Bid b. Ask B. Spread Size a. Bid / Bid b. Bid / Ask c. Ask / Bid d. Ask / Ask D. Size of Long Leg a. Bid b. Ask F. Size of Short Leg a. Bid b. Ask * (Except for sizes of long and short legs sizes every other variable is displayed in GUI) 3. Initiator: A set of conditions are created based on the user settings (slops, quantity desired, algo trading etc). These conditions are tested continually by the Initiator. When all the conditions are favorable, Initiator creates two signals: A. Send initiating orders: Details of the initiating orders are sent to the FIX messenger. B. Start Monitor Balancing Leg (MBL). 9 4. MBL: (Monitor Balancing Leg) This thread is started once the initiating orders are sent. The main purpose of MBL is to monitor the price of the balancing leg. If the price of the spread (with fixed price of initiating leg and floating price of balancing leg) falls out of the required range, MBL generates a signal to cancel the spread and balances the spreads if the initiating leg is partially filled. It also monitors the incoming messages from FIX server. After a certain percentage of the initiating leg is filled, balancing leg orders are sent to hedge our market exposure. MBL directly communicates with the FIX messenger to cancel orders or send new orders on the balancing side. 5. User settings and spread data Mandatory user settings with their default values are listed below: i. ii. SenderCompID is the required “pre-arranged” account name (Default:Geneva_Trade) Order Settings: Order types for initiating and balancing leg for long and short side (Default: Initiating leg : Limit Orders, Balancing leg: Market Orders) iii. iv. Quantity desired (Default: 1000) Inside and Outside slops (Default: ±3% of spreadPrice ± 10 cents for inside and outside respectively) v. vi. Liquidity constraint (Default: 0%) Maximum inventory (in case of algo trading). (Default: 5000) Additionally, certain optional settings can be added later on by the user. 6. Order execution data and inventory: This block stores the orders sent and is updated synchronously. 10 External I/O User Inputs: Single Trade: A single buy or sell trade would require the user to enter the following data: 1. Names of long and short symbols Stocks traded on any of the available exchanges can be traded using SpreadTrader. Validation of availability can be done. 2. Corresponding ratios A ratio is a positive integer or a fraction. 3. Inside and outside slops An inside slop is used an upper limit on the spread price when one is buying the spread. Similarly, outside slop is a lower limit on the spread price when the spread is being sold. While buying the spread, outside slop is not required and while selling the spread inside slop is not required. 4. Liquidity constraint It is a proper fraction which is used to determine whether the quantity available on the balancing side of the spread trader is sufficient to continue the trade. The quantity on the balancing leg is actually divided by the liquidity constraint to obtain a much higher quantity which is then compared with the required quantity on the balancing leg. Maximum Inventory: This input is used only when the algo trading options is selected. Algo trading is a continuing process of buys and sells at the prices defined by the inside and outside slops. Note that once the algo trading option is selected, both the inside and outside slops are required. Once the price is right SpreadTrader would start executing spread until the maximum inventory level is reached. 11 System Outputs: A well-designed GUI is used to display following results of the trades. 1. When the spread is getting executed the user is notified of the execution progress through a status bar. 2. Buying price and quantity, selling price and quantity along with the total inventory price and quantity are displayed. 3. Also, a detailed report of the orders executed is also recorded in a data grid. Screen Shots 1. Log in 12 2. New Spread: 3. Spread: 13 4. Execution: 5. Settings: 14 6. Order grid: 15 SpreadTrader 3.0 vs. SpreadTrader 2 1. Live data reception: Previously we used REDI Plus for L1 data reception. There were two issues which have been solved in this system. a. L2 data was available with DDE links which are quite slow. This is not the case with Citrius. It provides Level 2 data with tremendous speed in Java. b. ActiveX controls used in REDI give data updates whenever anything associated with the symbol changes. This results in unnecessary updates and waste of computational time. In Citrius, I can subscribe to the fields I want updates on and thus this problem is avoided. 2. Interfaces used: In REDI Plus, a single interface is used to receive data and to send orders. I believe they use a market /order router which results in asynchronous time-multiplexing on a single thread. Thus, it reduces speed. With Lime, I receive the data using Citrius API and sending orders and getting confirmations is done through the FIX interface. Thus, multiprocessing can be achieved; not to mention it’s much faster. 3. Order sending: Speed with which orders can be sent on REDI is restricted to 3-4 orders/ second. On the other hand, the FIX protocol can handle thousands of messages every second and supports basket orders which enables us to buy or sell an entire leg (with multiple stocks) with a single message. 4. Simulation environment: REDI Plus provides two exchange-traded dummy stocks which can be used for testing a program. But since these two stocks are quite illiquid they are useless to test the speed of execution. Lime provides a simulation environment wherein I can trade using fake money at real time speeds. 5. Clearing agency for both of them is GSEC. 16 Basics of FIX (Source: www.onixs.biz) The Engine provides the following services: manages a network connection manages the session layer (for the delivery of application messages) manages the application layer (defines business related data content) creates (outgoing) messages parses (incoming) messages validates messages persists messages (the ability to log data to a flat file) session recovery in accordance with the FIX state model 17 FIX message: Every FIX message consists of three parts. Headers and trailers are explained in the Basic information of FIX. Following is an example of a FIX message: 8=FIX.4.0\u00019=86\u000135=D\u000149=0\u000156=0\u000134=1\u000152=999909 0917:17:17\u000111=90001008\u000121=1\u000155=IBM\u000154=1\u000138=100\u000 140=1\u000159=0\u000110=191\u0001"; Basic building block of the message is a “tag = value” pair. Following table shows some of the tags usually used in an order message and their values: Tag ClOrdID Side TimeInForce OrderType Value 90001008 1 0 1 100 IBM OrderQty Symbol Unique identifier Buy Day Market Quantity Ticker Symbol In the message u0001 represents a Unicode character which serves as a separator in the tag=value format of FIX. e.g. 8 = FIX4.0 Tag 8 marks the beginning of every FIX message. Its value is the version of FIX being used. 9 = 86 Tag 9 follows tag 8. This contains the length of the FIX message; generated by the FIX engine. 38 = 100 Tag 38 contains the order quantity. 18 Sample Code Following code demonstrates the use of FIX engine. (I hope this helps to allay qualms about using FIX.) Note that following code is written with QuickFix/ J in mind. Different FIX engines have different syntaxes but same functionality. Every FIX message has a header which identifies the FIX message and a trailer which is used for error detection and possibly error correction. 1. Log in: FIX protocol is used to communicate with Lime’s server. First step in client –server communication is the Log in. Header: 8= “FIX4.2”•9 = “Body Length” • 35 = “A” • 49 = “GENEVA” • 56 = “LIME” • 34 = “1” • 50 = “”• 57 = “PASSWORD” • 52 = “Current Time” Body of Message: 98 = “0” • 108 = “15” • 553 = “JOHN” • 554 = “John’s Password” Trailer: 10 = “Modulo 256 checksum” 2. Log out: Header: 8= “FIX4.2”•9 = “Body Length” • 35 = “5” • 49 = “GENEVA” • 56 = “LIME” • 34 = “1” • 50 = “”• 57 = “PASSWORD” • 52 = “Current Time” Body of Message: Empty Trailer: 10 = “Modulo 256 checksum” 19 3. Send Order: Following is the FIX message to send an order: Header: 8= “FIX4.2”•9 = “Body Length” • 35 = “D” • 49 = “GENEVA” • 56 = “NYSE” • 34 = “1” • 50 = “”• 57 = “PASSWORD” • 52 = “Current Time” Body of Message: 11 = “Client ID” • 55 = “IBM” • 54 = “1” • 38 = “1000” • 40 = “2” • 44 = “75.45” • 100 = “NYSE” • 59 = “0” Trailer: 10 = “Modulo 256 checksum” 4. Cancel Order: Header: 8= “FIX4.2”•9 = “Body Length” • 35 = “F” • 49 = “GENEVA” • 56 = “NYSE” • 34 = “1” • 50 = “”• 57 = “PASSWORD” • 52 = “Current Time” Body of Message: 11 = “Client ID” • 41 = “Client ID of the Send Order Message” Trailer: 10 = “Modulo 256 checksum” 20 Code that creates these messages by employing the API of the FIX engine: Import QuickFix.*; 1. Log in Message message = new Message (); Header: message.getHeader().setField(new StringField(8, “FIX4.2”)); message.getHeader().setField(new StringField(35, “A”)); message.getHeader().setField(new StringField(49, “GENEVA”)); message.getHeader().setField(new StringField(56, “LIME”)); message.getHeader().setField(new StringField(34, “1”)); message.getHeader().setField(new StringField(50, “”)); message.getHeader().setField(new StringField(57, “PASSWORD”)); message.getHeader().setField(new StringField(35, TimeDate.Now.ToString)); Body of the Message: message.setField(new StringField(98, “0”)); message.setField(new StringField(108, “15”)); message.setField(new StringField(553, “JOHN”)); message.setField(new StringField(554, “John’s Password”)); Trailer: Checksum is generated internally when the message is validated. 2. Log out: Only thing different in the log out message is the type of Message field (i.e. tag 35) which is set to “5” indicating that it’s a log out message. Header: message.getHeader().setField(new StringField(35, “5”)); 21 3. Send order: Header: message.getHeader().setField(new StringField(35, “D”)); Body: message.setField(new StringField(11, “Client ID”)); message.setField(new StringField(55, “IBM”)); message.setField(new StringField(54, “1”)); message.setField(new StringField(38, “Quantity”)); message.setField(new StringField(40, “2”)); message.setField(new StringField(44, “75.45”)); message.setField(new StringField(100, “NYSE”)); message.setField(new StringField(59, “0”)); Trailer: This is generated by the FIX engine. 4. Cancel Order: Header: message.getHeader().setField(new StringField(35, “F”)); Body: message.setField(new String Field(11, “Client ID”); message.setField(new String Field(41, “Client ID of the order”); Trailer: This is generated by the FIX engine. After the message is constructed, it is sent through the FIX engine using the active “Session” Session.sendToTarget(message); Here the target is the Lime Server: IP: 12.189.151.195 Port: 7000 22 Just for comparison: message.getHeader().setField(new StringField(35, “D”)); message.setField(new StringField(11, “ClientID”)); message.setField(new StringField(55, “IBM”)); message.setField(new StringField(54, “1”)); message.setField(new StringField(38, “Quantity”)); message.setField(new StringField(40, “2”)); message.setField(new StringField(44, “75.45”)); message.setField(new StringField(100, “NYSE”)); message.setField(new StringField(59, “0”)); (Trailer is generated by the FIX engine.) Session.sendToTarget(message); (Target: IP and Port of the LIME server) hOrder.Side = ActiveSheet.Range("C8").Value hOrder.symbol =(ActiveSheet.Range("C9").Value) hOrder.Exchange = ActiveSheet.Range("C10").Value hOrder.Quantity = ActiveSheet.Range("C11").Value hOrder.Price = ActiveSheet.Range("C12").Value hOrder.PriceType = ActiveSheet.Range("C13").Value hOrder.TIF = ActiveSheet.Range("C15").Value hOrder.Account = ActiveSheet.Range("C16").Value hOrder.UserID = ActiveSheet.Range("G2").Value hOrder.Password = ActiveSheet.Range("G3").Value b = hOrder.Submit(myerr) As you can see, the only difference between using FIX and using REDI is the use of a FIX engine object “Message” and use of a CacheControl object in REDI for the order construction. Technically, the client side of LIME consists of the FIX engine and the client side of REDI is defined by its Interop.REDI library. The application has to make use of the API of these “stubs” and “skeletons”. 23 Difference between using REDI and LIME for execution In order to understand the difference between the two, let’s first look at the basic structure of a Distributed Object Communication. REDI: Both the stubs and skeleton are implemented by GS and the CacheControl object class can invoke methods on their server and similarly their server can invoke methods on the CacheControl object. Since they only provide the limited API of this model (Class library: Interop.Redi), we do not know how the communication takes place. Usually the data associated with “caller” is serialized into byte-streams and then sent over the network.(TCP/IP) But the protocol used to define the streaming data, sent over the network, is unknown to us and will remain so. LIME: We know that FIX protocol is used to communicate with the Lime server which then relays the order to the desired exchange. The stub and skeleton shown in the diagram are implemented in the FIX engine. (Stub in our engine and skeleton in their).We can select the network but I think TCP / IP would suffice given that we do not generate enough volume. Also, note that Citrius® is more like REDI (although it provides L2 data) but the Citrius API and FIX API are different. Thus, FIX is used only for order execution and management and not for market quotes. 24 Conclusion Addition of FIX technology to the SpreadTrader not only improves the speed of execution but also separates out the “GetData” and “SendOrder” functions which are at the heart of this system. This improves the overall stability of the application. Although, a large amount of Level 2 data is to be handled in this system, efficient use of multiple threads enables us to compute number of spread prices at any given time (on different threads, of course.) The application can be loosely separated into three parts: 1. Handling L2 Market quotes 2. Computing Prices and checking conditions 3. Order Execution and Management system (OMS) The first part is implemented solely in Java and is not much different than any other third party API. However, this API (called Citrius®) has many more functions compared to REDI (Refer the Comparison of SpreadTrader 3.0 vs. SpreadTrader 2.) Second part reads the live data from Dynamic data storage of the main program, to compute spread prices and spread sizes. Note that every spread runs on a different thread, thus computations are carried out independent of each other. All the basic data types in Java are thread-safe for “reading” and “writing” is done by a single thread (which deals with Citrius®) The FIX engine works on a lower level (sessions level) and performs the functions necessary to make the FIX protocol compatible with Java program ( Refer the Functions of FIX engine.) Please note that FIX communication takes place in “text format” but our program is concerned with only the application level interface of the FIX engine. We don’t engage in using FIX protocol ourselves; another program (i.e. FIX engine) does it for us. 25