Black Ocean Messaging API

1. Introduction
  1. The Black Ocean messaging API is designed to send/receive information in a binary protocol over TCP/IP. All messages include a 4 byte header designed to convey the message type, 2 bytes and the length of the current message, 2 bytes.
  2. Messages related to Orders are contained in one message, BOTransaction. For those of you who are more familiar with messaging protocols such as Arca, this will be a departure to what you are used to. Black Ocean is designed for HFT traders and as such, this format allows us to clear the incoming buffers very quickly where processing of orders can be implemented by the entity using the information, such as the Risk Module, Matching Engine, etc. This also allows us to package them into bulk messages internally for transmission to the appropriate server to consume.
  3. We have included all the messages used by Black Ocean in Excel spreadsheets. These spreadsheets contain all the fields and field types as well as the byte offset of each field in the message. We highly recommend the end user create enumerations to define the buffer offsets as messages can and do change both in size and structure. The spreadsheets also contain the total length of each message including the 4 byte header
    2. Rate limits
    1. Black Ocean reserves the right to limit the number of open order requests a user can have. There are two main reasons why this is beneficial to both parties:
    i. The case where the user is sending thousands or tens of thousands of messages without waiting for a response to those messages is usually indicative of a run away process and the #1 reason traders go broke on algorithmic trading mishaps. The best available and safest practice is never to send another order until a response to the previous order has been received. Black Ocean recognizes not every client is the same and there may be valid reasons for not waiting, so, in light of that, if a client can show justification for sending more than 500 orders before receiving a response, orders above 500 will be rejected until such time as the user has received 1 response. In short, after 500 orders have been sent, the user must receive one response before sending another order. Cancels do not count towards this total. Even with a 500 open order request limit, it is possible to send thousands or 10's of thousands of orders per second. If you need more than the current limit, please contact your Black Ocean Account Manager and request a higher limit.
    ii. The second reason a user might want to send more than 500 without receiving a reply is because they are spamming the system. This hurts everyone as these orders, orders which are usually far away from the top of the book do require processing time and that impacts orders which are honest in nature.
    3. Security
    1. Black Ocean uses a two step approach to security.
    i. All users intending to submit trades to the exchange must first login through an Administrative Server. This server does the following two things
    • 1. Using the private key supplied to the user during the account creation, the Admin Server compares the 2FA key generated with the key on file.
    • 2. If the 2FA comparison was successful the user will be supplied with the IP Address of the Connection Server and the session ID to be used while trading. It is essential this session ID be submitted for all requests.
    • 3. The user must then logon to the Connection server again using the 2FA method and the session id supplied by the Admin Logon.
    • 4. All of the messages and procedures will be described in sections to follow.
    • 5. 2FA is currently disabled in the test environment to allow the users to be able to test the login and order submittals but must be completed during the certification process in order to gain access to the production environment.
    ii. This two step process is necessary as Black Ocean has more than one Order Entry Server and based on loading, each session will not necessarily be on the previously connected Order Entry Server (OES). This process allows us to better serve our users by allowing us to move users to servers with lighter loading.
    iii. The 2FA process can be implemented programmatically to eliminate the need for a user to manually input the correct information.
    iv. The 2FA process can be disabled at the request of the user with the permission of Black Ocean.
    v. All users who are using our co-location facility will not be required to use 2FA for logins.
    4. Header before all messages
    1.Each message has a 4 byte header
    i. The first 2 bytes are reserved for message types
    1. In most cases messages requiring 2 char's is not needed and so the first byte of the buffer received will have the Message Type in it. But should enough messages be required, 2 bytes have been reserved for this purpose.
    ii. The 3rd and 4th bytes are reserved for the length of the actual message including the 4 byte header length.
    5. Available Messages
    1.BOClientLogon which also doubles as the server logon response
    i. First byte of the header = 'H'
    ii. Length is as listed in the excel spreadsheet (143 bytes currently), so the 3rd and 4th bytes should hold the value, 143.

    2. BOInstrumentRequest
    i. First byte of the header = 'Y'
    ii. Length is as listed in the excel spreadsheet (62 bytes currently), so the 3rd and 4th bytes should hold the value, 62
    6. Login to Admin Server
    1. Login requires connecting to the predefined Administrative Server IP address and submitting a BOClientLogon message. Please review the attached excel spreadsheet for the required fields. The first byte in this message is always the character 'H'. The server will do the required security checks based on the user name, the account and the 2FA value in the field 2FA from the user 2FA generation. The server will validate the supplied information and respond with the status of the login in the field, LoginStatus, please see the possible response values on the spreadsheet.
    2. If the validation was successful (passed all security checks) the server will respond with a LoginStatus = 1. The server will also supply the IP address of the Primary and Secondary OES (Order Entry Server) along with the session id to be used in connecting to the OES.
    3. If the validation was unsuccessful, the LoginStatus will be set to 2 and the connection will be terminated.
    4. Example:
    i. Client Message
    • 1. FIX::N_BIT10::BOClientLogon* _logon = new(_nlogon) FIX::N_BIT10::BOClientLogon();
    • 2. _logon->setUserName(name_);
    • 3. _logon->setTradingSessionID(200);
    • 4. _logon->setAccount((int)100500);
    • 5. _logon->setKey(100004320) // generated by 2FA
    • 6. _logon->setSendingTime(1000000000000); generated from calling time function in nanoseconds
    • 7. _logon->setMsgSeqNum(10000);
    • 8. FIX::Message* _msg = _logon;
    ii. Server Response
    • 1. FIX::N_BIT10::BOClientLogon* _logon = new(_nlogon) FIX::N_BIT10::BOClientLogon();
    • 2. _logon->setUserName("OES1");
    • 3. _logon->setTradingSessionID(200);
    • 4. _logon->setAccount((int)100500);
    • 5. _logon->setLogonStatus(1);
    • 6. _logon->setPrimaryOrderEntryIP("192.1.1.1:32050");
    • 7. _logon->setSecondaryOrderEntryIP("192.1.1.2:32050");
    • 8. _logon->setSendingTime(11111111111111);
    • 9. _logon->setRejectReason(0); // not required if logon successful
    • 10. FIX::Message* _msg = _logon;
    5.Failure of the Primary Order Entry Server
    • i. In the event of a loss of connection, the user should try 3 times to reconnect to the OES and failing that, should then initiate a logon to the secondary OES. If desired, the user may connect to the secondary previously and after failure and reconnect tries, roll their outputs to the secondary. Orders directed to the secondary with a valid primary will be rejected.
    7. Login to the OES
    1. Login requires establishing a connection to the OES IP address supplied in step #4 above.
    2. The user sends a BOClientLogon message containing the session id obtained in section #4 above.
    3. See step #4 for examples of typical client/server messages as the sequence is identical with the exception of the IP addresses delivered by the admin server.
    4. In the BOClientLogon message the user also generates a 2FA key which will be compared to the one on file (the server will also generate the key and do a comparison).
    5. If the validation is correct using the 2FA key, the account and user name, the login will be successful and the user will be notified with a value of 1 in the BOClientLogon message they receive as a response.
    6. After the logon is complete and successful, the server will send two types of unsolicited messages:
    7. RiskUserSymbol:
    • i. This message conveys to the user the current account balances for each instrument for which the user has positions or account equity. For each instrument the user will receive one message. In the UpdateType field in the message, upon start this value will be set to RISK_SYMBOL_SNAPSHOT_START. The last RiskUserSymbol message will set the UpdateType to RISK_SYMBOL_SNAPSHOT_END signifying the end of updates. Please review the attached excel spreadsheet for fields and buffer offsets as well as any enumeration types and value.
    • ii. It is important to remember that activity may have occurred in the account since the last login so it is very important to review this information and update any values stored during the last session.
    8. BOTransaction:
    • i. The purpose of the message(s) is to notify the user of all open orders. The UpdateType upon start will be set to TRANSACTION_SNAPSHOT_START and upon completion the last message will contain TRANSACTION_SNAPSHOT_END in the UpdateType field.
    • ii. If the logon was not successful, the reject reason will be set in the RejectReason field and the connection will be closed.
    • iii. These messages are just duplicates of what the user initially sent when submitting the order and is the response from the matching engine only if the order was accepted.
    • iv. Orders which were executed while the user was logged out will be applied to the Risk Account and will be reflected in the account values in the previous section.
    8. Time Values
    1. Black Ocean uses nanosecond timing. All time values are to be set to nanoseconds.
    2. Black Ocean uses this function call to set the times:
    i. uint64_t microseconds_since_epoch = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
    9. Heart beats
    1. Heart Beating will occur every 30 seconds unless data is received by either party. It is preferable the client send a heartbeat message before this time value elapses.
    i. BOHeartbeat , first byte of the header is '0', read as the character zero.
    1. BOHeartbeat* _hb = new(_nlogon) FIX::N_BIT10::BOHeartbeat();
    ii. No other fields are necessary

    2. If data is not received in 30 seconds, the party affected will send a test request. The first byte of the header should be '1' for the BOTestRequest message. '1' is the character value of one.
    • 1. BOTestRequest* _hb = new(_nlogon) FIX::N_BIT10::BOTestRequest();
    • 2. If no response is received for the test request, the affected party should close the connection and take action.
    10. Instrument Master
    1. Upon a successful logon to the OES, it is highly recommended (Actually required if the user has not previously connected and obtained the information) the user sends a BOInstrumentRequest message to the OES. The response from the server to this message contains information about all instruments available for trading on the Black Ocean Exchange. Information included:
    i. SymbolEnum:
    • 1. A brief description of what is a symbol enum is required at this point. In keeping with the original idea that Black Ocean is intended for HFT traders, strings are almost entirely ignored throughout the messaging and in the operation of the platform. Instruments are identified by a unique short integer assigned to them in the INSTRUMENT_MASTER database table. The reasoning behind this is instead of hash based lookups on strings, Black Ocean accesses almost all information based on indexes, most of which are based on the symbol enum for a particular instrument. Due to this fact, the SymbolEnum field is probably a member of almost every message. If string values are set in messages Black Ocean will simply echo them back to the end user.
    ii. SymbolType:
    • 1. There are three (3) basic types of instruments
    • a. Spot
    • b. Futures
    • c. Derivatives
    • 2. The SymbolType field defines the type of instrument contained in this message
    iii. PriceIncrement
    • 1. Not all instruments tick at the same value, some tick at .000001 and others at .5. It is imperative that you use the right price increment in the prices you supply to the Black Ocean platform. The entire system is very sensitive to the previously mentioned SymbolEnum but almost all lookups in the Matching Engine are based on price. If the user consistently assigns the wrong price increment, this will result in the trading being disabled and the user API will require recertification in order to resume trading.
    iv. Max and Min Size
    • 1. It is reasonable to assume that based on the instrument, orders of a certain size should be rejected. This means orders of size .000000000001 will certainly be rejected as nuisance orders and orders of size 1000000 will be rejected as probably a fat finger mistake. Black Ocean is responsible for determining these limits and they will be conveyed in these two fields.
    v. Examples:
    • 1. Client: It is not necessary to set the message type as long as the first byte of the header is set to 'Y'.
    • a. FIX::N_BIT10::BOClientLogon* _ir = new(_nlogon) FIX::N_BIT10::BOClientLogon(FIX::N_BIT10::MESSAGE_TYPE::);
    • b. _ir->setMessageType(FIX::N_BIT10::MESSAGE_TYPE::INSTRUMENT_DATA);
    • c. _ir->Account(100500);
    • d. _ir->RequestType(0);
    • e. _ir->Key();
    • f. _ir->SymbolName();
    • g. _ir->SymbolType();
    • h. _ir->SymbolEnum();
    • i. _ir->UserName();
    • j. _ir->TradingSessionID();
    • k. _ir->SendTime();
    • l. _ir->LastSeqNum();
    • 2. A value of 1 in RequestType for the client is a request for all the instruments. A value of 2 indicates the value of the instrument requested is in the SymbolEnum field.
    • 3. Server Responds with a BOInstrument message, first byte of the header will be 'Q'
    • a. FIX::N_BIT10::BOInstrument* _ir = new(_nlogon) FIX::N_BIT10::BOInstrument();
    • b. _id->MessageType(FIX::N_BIT10::MESSAGE_TYPE::INSTRUMENT_RESPONSE);
    • c. _id->SymbolEnum(3);
    • d. _id->ResponseType();
    • e. _id->SymbolName("FLYUSDT");
    • f. _id->SymbolType(FIX::N_BIT10::SYMBOL_TYPE::SPOT);
    • g. _id->PriceIncrement(0.00001);
    • h. _id->MaxSize(BO to determine);
    • i. _id->MinSize(BO to determine);
    • j. _id->SendTime(100000000);
    • k. _id->SeqNum(1000000);
    • 4. If the request involves more than one instrument to be returned, the ResponseType field will contain the value FIX::N_BIT10::RESPONSE_TYPE::SNAPSHOT_START.
    • 5. In messages in between a multi part instrument data request, the ResponseType field will contain the value FIX::N_BIT10::RESPONSE_TYPE::SNAPSHOT_CONTINUATION.
    • 6. The final message of a multi instrument request, the ResponseType field will contain the value FIX::N_BIT10::RESPONSE_TYPE::SNAPSHOT_END.
    11. Risk
    1. Risk management is very important to Black Ocean. Black Ocean performs pre and post risk checks on all orders.
    i. All orders which would affect the account equity are checked before sending them to the Matching Engine.
    • 1. New orders and Cancel/Replace orders are checked to ensure the equity in the account is sufficient to allow the user to enter into the position. Example:
    • a. User wants to sell 5 BTCUSDT. The equity will be checked to ensure the user has 5 BTC to sell. If not, the order will be rejected.
    • b. User wants to buy 5 BTCUSDT. The equity of USDT will be checked at the current price and size to ensure the USDT equity is sufficient.
    • c. Cancel/Replace orders which would cause the current outstanding liability to be reduced are not counted until such time as the matching engine indicates the C/R was successful.
    • d. All New Orders or C/R orders which would increase the position size are counted as orders which have been executed due to the fact it is possible they will be executed. Therefore, the current equity will be debited by the order amount * the price minus the values in the original order.
    • e. All orders which have a TIF (Time in Force) of REDUCE will be checked by the risk engine to ensure they only reduce the position size and will be rejected if the order would increase the position size.
    • 2. Cancels, Cancel/Replace and Executions are checked by the risk management before returning the order to the user to return the unused equity in the case of a cancel and to update the positions in the case of an execution or partial execution and to update the equity in the case the C/R reduced the outstanding liability.
    12. Entering, Cancelling, Cancel/Replace and Executions of Orders
    1. All operations related to Orders are contained in one message, the BOTransaction message.
    2. Obviously the user is free to internally create their own messages and simply fill in our BOTransaction structure according to the requirements. We have provided an excel spreadsheet which lists every field in the message and the buffer offset of each field.
    3. After orders are validated by the Risk Engine, the orders which passed the validation are then sent to the matching engine for that instrument.
    4. Execution of orders
    • i. Orders which have been submitted but not placed on the book if executed will have a message type of QUOTE_FILL or QUOTE_FILL_PARTIAL to indicate they interacted with a resting order.
    • ii. Resting orders will have a message type of EXECUTION or EXECUTION_PARTIAL.
    5. Current message types supported for orders:
    • i. MESSAGE_TYPE : short {
    • ii. ORDER_NEW = 1,
    • iii. CANCEL_REPLACE,
    • iv. MARGIN_CANCEL_REPLACE,
    • v. MARGIN_EXECUTE,
    • vi. ORDER_STATUS,
    • vii. ORDER_CANCEL,
    • viii. MARGIN_CANCEL,
    • ix. EXECUTION,
    • x. EXECUTION_PARTIAL,
    • xi. MARGIN_EXECUTION, // 10
    • xii. MARGIN_PARTIAL_EXECUTION,
    • xiii. REJECT,
    • xiv. ORDER_REJECT,
    • xv. ORDER_ACK,
    • xvi. CANCELLED, // 15
    • xvii. REPLACED,
    • xviii. QUOTE_FILL,
    • xix. QUOTE_FILL_PARTIAL,
    • xx. MARGIN_REPLACED,
    • xxi. CANCEL_REPLACE_REJECT,
    • xxii. INSTRUMENT_DATA
    6. The fields and buffer offsets of all fields in the BOTransaction are listed here but can also be found in the accompanying excel spreadsheet.
    • i. TRANSACTION_OFFSET : short {
    • ii. MESSAGE_TYPE_OFFSET = 4,
    • iii. ATTRIBUTE = 6,
    • iv. ACCOUNT = 8,
    • v. ORDER_ID = 12,
    • vi. SYMBOL_ENUM = 20,
    • vii. ORDER_TYPE = 22,
    • viii. SYMBOL_TYPE = 24,
    • ix. BO_PRICE = 26,
    • x. BO_SIDE = 34,
    • xi. BO_ORDER_QTY = 36,
    • xii. BO_TIME_IN_FORCE = 44,
    • xiii. STOP_LIMIT_PRICE = 46,
    • xiv. SYMBOL = 54,
    • xv. ORIG_ORDER_ID = 66,
    • xvi. BO_CANCEL_SHARES = 74,
    • xvii. EXEC_ID = 82,
    • xviii. EXEC_SHARES = 90,
    • xix. REMAINING_QUANTITY = 98,
    • xx. EXEC_FEE = 106,
    • xxi. EXPIRATION_DATE = 114,
    • xxii. TRADER_ID = 126,
    • xxiii. REJECT_REASON = 132,
    • xxiv. SENDING_TIME = 134,
    • xxv. TRADING_SESSION_ID = 142,
    • xxvi. KEY = 146,
    • xxvii. DISPLAY_SIZE = 150,
    • xxviii. REFRESH_SIZE = 158,
    • xxix. LAYERS = 166,
    • xxx. SIZE_INCREMENT = 168,
    • xxxi. PRICE_INCREMENT = 176,
    • xxxii. PRICE_OFFSET = 184,
    • xxxiii. BO_ORIGPRICE = 192,
    • xxxiv. EXEC_PRICE = 200,
    • xxxv. MSG_SEQ_NUM = 208,
    • xxxvi. TAKE_PROFIT_PRICE = 216,
    • xxxvii. TRIGGER_TYPE = 224,
    • xxxviii. ATTRIBUTES_TYPE = 226,
    • xxxix. };
    7. This part can be a little confusing at first but here is the explanation of how order types are classified. All BOTransaction messages start with the first byte of the header being set to 'T', the 3rd and 4th bytes set to the length of the message and the 5th and 6th bytes set to the Order MessageType listed above.
    • i. Example:
    • 1. [T][\'0'][][238][][1] would be a BOTransaction with a message type of ORDER_NEW.
    • 2. Here is an example of how we set the message type:
    • a. *((short*)(jnode->hldr_->buffer_ + FIX::N_BIT10::TRANSACTION_OFFSET::MESSAGE_TYPE_OFFSET)) = FIX::N_BIT10::MESSAGE_TYPE::REPLACED;
    • 3. As can be seen, the offset into the buffer is through the TRANSACTION_OFFSET enum. This is the preferred way of doing it rather than hard coding the value since the messages may change and finding all the instances in the code would be tedious and error prone.
    8. Order Types
    • i. enum ORD_TYPE : short {
    • ii. LMT = 1,
    • iii. MKT,
    • iv. STOP_MKT,
    • v. STOP_LMT,
    • vi. PEG,
    • vii. HIDDEN,
    • viii. PEG_HIDDEN,
    • ix. OCO,
    • x. ICE,
    • xi. SNIPER_MKT,
    • xii. SNIPER_LIMIT,
    • xiii. TSM, // TRAILING_STOP_MKT
    • xiv. TSL, // TRAILING_STOP_LMT
    • xv. TPSL_MARKET, // Has 3 prices associated with it, entry, profit and stop
    • xvi. TPSL_LIMIT, // Has 3 prices associated with it, entry, profit and stop
    • xvii. };
    • Please see the attached document for explanations of the various order types
    • At the current time TPSL orders are disabled but will be enabled very shortly
    • Attributes
    • i. Almost all of Black Oceans order types may have attributes attached to them. Attributes such as hidden, display/refresh, etc. Here is a list of the available Attribute types
    • 1. enum ATTRIBUTE_ENUM : char {
    • 2. POPPED,
    • 3. HIDDEN_ATTRIBUTE,
    • 4. DISPLAYSIZE_ATTRIBUTE,
    • 5. STOPMKT_ATTRIBUTE,
    • 6. STOPLMT_ATTRIBUTE,
    • 7. TSL_ATTRIBUTE,
    • 8. TSM_ATTRIBUTE,
    • 9. PEG_ATTRIBUTE,
    • 10. POSTONLY_ATTRIBUTE,
    • 11. REDUCE_ATTRIBUTE,
    • 12. };
    • ii. Attributes were attached to certain orders to give special meaning to the order. In the case where an order is designated with the DISPLAY_TYPE or any order where a price is optional, the attribute must be set in order to differentiate any trash in the buffer which might result in a value indicating it should be used when in reality no display/refresh was intended.
    • iii. The Attribute is a character string of 12 bytes. To set the attribute, you set the offset position in the string to 'Y' indicating this attribute should be used.
    • iv. Example of how to set an attribute:
    • 1. char buffer[12];
    • 2. memset(buffer, 'N', sizeof(buffer));
    • 3. buffer[ATTRIBUTE_ENUM:: DISPLAYSIZE_ATTRIBUTE] = 'Y';
    • v. We use these attributes in the following way:
    • 1. char* attributes = (char*)(buf->buffer_ + FIX::N_BIT10::TRANSACTION_OFFSET::ATTRIBUTES_TYPE);
    • 2. char displayattribute = attributes[FIX::N_BIT10::ATTRIBUTE_ENUM::DISPLAYSIZE_ATTRIBUTE];
    • 3. if(displayattribute == 'Y') {
    • 4. displaysize = *((double *)(buf->buffer_ + FIX::N_BIT10::TRANSACTION_OFFSET::DISPLAY_SIZE));
    • 5. } else {
    • 6. displaysize = 0.0;
    • 7. }
    • vi. At the present time, only display/refresh and hidden attributes are used but work is underway to add all attributes to all order types
    • Examples of the fields required for each order type are shown later in this document
    13. Special Message types such as MESSAGE_TYPE::ORDER_CANCEL, etc
    1. ORDER_CANCEL
    • i. As stated earlier, Black Ocean orders are very sensitive to symbol enums and prices. In order to cancel an order, it is essential that the original price of the order is set in the BOPrice field and must include the original order id, side, correct symbol enum in the SymbolEnum field.
    2. CANCEL_REPLACE
    • i. Cancel Replace orders must include the original price in the BOOrigPrice field as well as the original order id in the OrigOrderID field and include the symbol enum in the SymbolEnum field.
    14. Special Order Types
    1. ICE
    • i. Black Ocean provides true ICE orders. ICE orders are intended to allow the user to place multiple orders on the book at predesignated offsets and sizes. Currently, ICE orders are limited to 10 layers but this will change to allow users as many layers as they desire with multipliers to increase offsets and sizes. But currently, all ICE orders will be layered at the OFFSET increment chosen and the SIZE INCREMENT chosen.
    • ii. Black Ocean will provide a cancel replace message for the top layer which was moved and from there the user can determine where the remaining orders are in the book based on the remaining layer size and the offset increment which was submitted with the order.
    • iii. When cancelling an ICE order, as with all orders especially those which move as the book price moves, the ORIGINAL price submitted with the order must be including in the CANCEL request due to the fact the order may have moved from its original price location but the cancel information remains at the original location. Do not use the cancel replace price sent as the book price moves as the price to cancel as it is just an indicator of where your ICE order layering starts.
    • iv. Calculating the order size
    1. The order size is calculated using the number of layers desired and the size increment of each layer, example
    a. Layers = 5
    b. Size Increment = 1
    c. OrdQty = 5 * 1, or 5.
    • v. ICE orders by nature are intended to follow the book as the TOP of Book price moves away from the order. The distance from the top of the book is determined by the Price Offset. If the price offset is set to 0, the top layer of the orders will be at the top of the book. If the PriceOffset is .5, the top layer will be .5 below the top of the book and so on and so on. As the Top of book approaches the order, it will maintain its position.
    • vi. Currently, the display/refresh attribute is unavailable for ICE orders as the size increment is used. This may change in the future to allow this attribute to be used.
    • vii. Should ICE orders submitted to the book cross the book, the ICE order will be executed until the size increment is exhausted for the layer and then repriced. If that new price also crosses the book execution will continue until the order is exhausted or the new price does not cross the book which is where the order will be placed.
    2. PEG
    • i. Peg orders are pegged to the top of the book and move as the tob price changes. To cancel a peg order the original price, side, symbol enum and original order id must be submitted.
    • ii. Peg orders can have display/refresh and hidden attributes
    3. OCO
    • i. OCO orders are orders intended to either capture a profit on an existing position or stop the order out at a predefined price.
    • ii. Stop orders associated with an OCO currently are STOP MKT orders (subject to change shortly to allow STOP_LIMIT and TSM/TSL order types).
    • iii. In order to cancel a stop order, the original price, original stop price, side, and symbol enum must be submitted with the cancel request.
    • iv. OCO orders can have display/refresh and hidden attributes
    15. Time in Force for orders
    1. Currently the following TIF modifiers are supported
    • i. enum TIF : short {
    • ii. FOK = 1,
    • iii. GTC,
    • iv. IOC,
    • v. POO, // Make only
    • vi. RED, // Reduce only
    • vii. DAY,
    • viii. };
    2. Fill or Kill (FOK)
    • i. Orders with this attribute will only be executed if the full volume of the order can be filled and cancelled if this is not possible
    3. Good till Cancelled (GTC)
    • i. Good till cancel orders remain on the book until executed or cancelled
    4. Immediate or Cancel (IOC)
    • i. IOC orders will only be executed up the price indicated in the order. If not filled upon reaching this price, the order will be cancelled
    5. Post only Orders (POO)
    • i. POO orders will only be executed if they will be placed on the book and not executed. Disclaimer to this: If there is hidden volume on the book, the order will be executed and the user will be charged a taker fee. If not done in this manner users could simply send orders of the smallest size increment to be used as price discovery.
    6. Reduce only Orders (RED)
    • i. Reduce only orders will only be sent to the matching engine if they will reduce the size of the current position
    7. DAY
    • i. Day orders are currently disabled but are intended as session orders. This means if the user has orders on the book and logs out all DAY orders will be cancelled.
    16. Example order types
    1. LMT – New Order with Display/Refresh and Hidden attributes, values in red are required fields
    • i. FIX::N_BIT10::BOTransaction* _t = new(_nlogon); // uses placement new
    • ii. _t->setMessageType(FIX::N_BIT10::MESSAGE_TYPE::ORDER_NEW);
    • iii. _t->setAccount(100500);
    • iv. _t->setTradingSessionID(200);
    • v. _t->setOrderType(FIX::N_BIT10::ORD_TYPE::LMT);
    • vi. _t->setBOSide((short)FIX::N_BIT10::SIDE::SELL);
    • vii. _t->setOrderID(500);
    • viii. char attributes[12];
    • ix. memset(attributes, 'N', sizeof(attributes));
    • x. attributes[FIX::N_BIT10::ATTRIBUTES_ENUM::HIDDEN_ATTRIBUTE] = 'Y';
    • xi. attributes[FIX::N_BIT10::ATTRIBUTES_ENUM::DISPLAYSIZE_ATTRIBUTE] = 'Y';
    • xii. _t->setAttributes(&attributes[0]);
    • xiii. _t->setBOPrice(9165.0);
    • xiv. _t->setBOOrderQty(5.00);
    • xv. _t->setDisplaySize(0.50); // required because display attribute is set
    • xvi. _t->setRefreshSize(0.25); // required because display attribute is set
    • xvii. _t->setSymbolType(FIX::N_BIT10:: SYMBOL_TYPE::SPOT);
    • xviii. _t->setSymbolEnum(FIX::N_BIT10::SYMBOL_VALUE_ENUM::BTCUSDT);
    • xix. _t->setTraderID("NONE");
    • xx. _t setMsgSeqNum(++msgSeqNum);
    • xxi. _t->setSymbolName("FLYUSDT");
    2. Server response to new order accepted
    • i. FIX::N_BIT10::BOTransaction* _t = new(_nlogon); // uses placement new
    • ii. _t->setMessageType(FIX::N_BIT10::MESSAGE_TYPE::ACK);
    • iii. _t->setAccount(100500);
    • iv. _t->setTradingSessionID(200);
    • v. _t->setOrderType(FIX::N_BIT10::ORD_TYPE::LMT);
    • vi. _t->setBOSide((short)FIX::N_BIT10::SIDE::SELL);
    • vii. _t->setOrderID(500);
    • viii. _t->setBOPrice(9165.0);
    • ix. _t->setBOOrderQty(5.00);
    • x. _t->setDisplaySize(0.50); // required because display attribute is set
    • xi. _t->setRefreshSize(0.25); // required because display attribute is set
    • xii. _t->setSymbolType(FIX::N_BIT10:: SYMBOL_TYPE::SPOT);
    • xiii. _t->setSymbolEnum(FIX::N_BIT10::SYMBOL_VALUE_ENUM::BTCUSDT);
    • xiv. _t setMsgSeqNum(++msgSeqNum);
    • xv. _t->setTraderID("NONE");
    • xvi. _t->setSymbolName("FLYUSDT");
    3. LMT – Cancel Replace would be used to cancel replace the order in the previous example
    • i. _t = new(_nlogon) FIX::N_BIT10::BOTransaction();
    • ii. _t->setMessageType(FIX::N_BIT10::MESSAGE_TYPE::CANCEL_REPLACE);
    • iii. _t->setAccount(100500);
    • iv. _t->setOrderType(FIX::N_BIT10::ORD_TYPE::LMT);
    • v. _t->setBOOrderQty(5.0);
    • vi. _t->setBOPrice(9170.0);
    • vii. _t->setBOOrigPrice(9165.0);
    • viii. _t->setBOSide((short)FIX::N_BIT10::SIDE::SELL);
    • ix. _t->setOrderID(501);
    • x. _t->setOrigOrderID(500);
    • xi. _t->setTradingSessionID(200);
    • xii. _t->setSymbolType(FIX::N_BIT10:: SYMBOL_TYPE::SPOT);
    • xiii. _t->setSymbolEnum FIX::N_BIT10::SYMBOL_VALUE_ENUM::FLYUSDT);
    • xiv. _t setMsgSeqNum(++msgSeqNum);
    • xv. _t->setTraderID("NONE");
    • xvi. _t->setSymbolName("FLYUSDT");

    4. Server Response to Cancel Replace
    • i. _t = new(_nlogon) FIX::N_BIT10::BOTransaction();
    • ii. _t->setMessageType(FIX::N_BIT10::MESSAGE_TYPE::REPLACED);
    • iii. _t->setAccount(100500);
    • iv. _t->setOrderType(FIX::N_BIT10::ORD_TYPE::LMT);
    • v. _t->setBOOrderQty(5.0);
    • vi. _t->setBOPrice(9165.0);
    • vii. _t->setBOOrigPrice(9165.0);
    • viii. _t->setBOSide((short)FIX::N_BIT10::SIDE::SELL);
    • ix. _t->setOrderID(501);
    • x. _t->setOrigOrderID(500);
    • xi. _t->setTradingSessionID(200);
    • xii. _t->setSymbolType(FIX::N_BIT10:: SYMBOL_TYPE::SPOT);
    • xiii. _t->setSymbolEnum FIX::N_BIT10::SYMBOL_VALUE_ENUM::FLYUSDT);
    • xiv. _t setMsgSeqNum(++msgSeqNum);
    • xv. _t->setTraderID("NONE");
    • xvi. _t->setSymbolName("FLYUSDT");
    • xvii.
    5. Limit order Cancel User
    • i. t = new(_nlogon) FIX::N_BIT10::BOTransaction();
    • ii. _t->setMessageType(FIX::N_BIT10::MESSAGE_TYPE::ORDER_CANCEL);
    • iii. _t->setAccount(100500);
    • iv. _t->setOrderType(FIX::N_BIT10::ORD_TYPE::LMT);
    • v. _t->setBOOrderQty(5.0);
    • vi. _t->setBOPrice(9170.0);
    • vii. _t->setBOOrigPrice(9170.0);
    • viii. _t->setBOSide((short)FIX::N_BIT10::SIDE::SELL);
    • ix. _t->setOrderID(502);
    • x. _t->setOrigOrderID(501);
    • xi. _t->setTradingSessionID(200);
    • xii. _t->setSymbolType(FIX::N_BIT10:: SYMBOL_TYPE::SPOT);
    • xiii. _t->setSymbolEnum FIX::N_BIT10::SYMBOL_VALUE_ENUM::FLYUSDT);
    • xiv. _t setMsgSeqNum(++msgSeqNum);
    • xv. _t->setTraderID("NONE");
    • xvi. _t->setSymbolName("FLYUSDT");
    • xvii. LMT are stationary orders and since this order was cancel replaced, you must use the cancel replace price as the price in which to cancel the order and the order id of the order id used in the cancel replace as in the example above. The original order when submitted was 500 with a price of 9165 and then cancel replaced with a new price of 9170 and order id of 501. The price to cancel is 9170 and the order id is 501.
    6. Limit order Cancel : Server Response
    • i. t = new(_nlogon) FIX::N_BIT10::BOTransaction();
    • ii. _t->setMessageType(FIX::N_BIT10::MESSAGE_TYPE::CANCELLED);
    • iii. _t->setAccount(100500);
    • iv. _t->setOrderType(FIX::N_BIT10::ORD_TYPE::LMT);
    • v. _t->setBOOrderQty(5.0);
    • vi. _t->setBOPrice(9170.0);
    • vii. _t->setBOOrigPrice(9170.0);
    • viii. _t->setBOSide((short)FIX::N_BIT10::SIDE::SELL);
    • ix. _t->setOrderID(502);
    • x. _t->setCancelShares(5.0)
    • xi. _t->setOrigOrderID(501);
    • xii. _t->setTradingSessionID(200);
    • xiii. _t->setSymbolType(FIX::N_BIT10:: SYMBOL_TYPE::SPOT);
    • xiv. _t->setSymbolEnum FIX::N_BIT10::SYMBOL_VALUE_ENUM::FLYUSDT);
    • xv. _t setMsgSeqNum(++msgSeqNum);
    • xvi. _t->setSymbolName("FLYUSDT");
    • xvii. _t->setTraderID("NONE");

    7. ICE Order example
    • i. FIX::N_BIT10::BOTransaction* _t = new(_nlogon) FIX::N_BIT10::BOTransaction();
    • ii. _t->setMessageType(FIX::N_BIT10::MESSAGE_TYPE::ORDER_NEW);
    • iii. _t->setAccount(100500);
    • iv. _t->setTradingSessionID(200);
    • v. _t->setOrderType(FIX::N_BIT10::ORD_TYPE::ICE);
    • vi. _t->setBOSide((short)FIX::N_BIT10::SIDE::SELL);
    • vii. _t->setOrderID(ordID_++);
    • viii. _t->setBOPrice(9165.0);
    • ix. _t->setBOOrderQty(5.000);
    • x. _t->setPriceIncrement(1.000);
    • xi. _t->setSizeIncrement(1.000);
    • xii. _t->setPriceOffset(10.000);
    • xiii. _t->setLayers(5.000);
    • xiv. _t->setSymbolType(FIX::N_BIT10:: SYMBOL_TYPE::SPOT);
    • xv. _t->setSymbolEnum FIX::N_BIT10::SYMBOL_VALUE_ENUM::FLYUSDT);
    • xvi. _t setMsgSeqNum(++msgSeqNum);
    • xvii. _t->setSymbolName("FLYUSDT");
    • xviii. _t->setTraderID("NONE");
    8. PEG Order Type Example
    • i. FIX::N_BIT10::BOTransaction* _t = new(_nlogon) FIX::N_BIT10::BOTransaction();
    • ii. _t->setMessageType(FIX::N_BIT10::MESSAGE_TYPE::ORDER_NEW);
    • iii. _t->setAccount(100500);
    • iv. _t->setTradingSessionID(200);
    • v. _t->setOrderType(FIX::N_BIT10::ORD_TYPE::PEG);
    • vi. _t->setBOSide((short)FIX::N_BIT10::SIDE::SELL);
    • vii. _t->setOrderID(ordID_++);
    • viii. _t->setBOPrice(9165.0);
    • ix. _t->setBOOrderQty(5.000);
    • x. _t->setStopLimitPrice(9160.000);
    • xi. _t->setDisplaySize(0.50);
    • xii. _t->setRefreshSize(0.25);
    • xiii. _t->setSymbolType(FIX::N_BIT10:: SYMBOL_TYPE::SPOT);
    • xiv. _t->setSymbolEnum FIX::N_BIT10::SYMBOL_VALUE_ENUM::FLYUSDT);
    • xv. _t setMsgSeqNum(++msgSeqNum);
    • xvi. _t->setSymbolName("FLYUSDT");
    • xvii. _t->setTraderID("NONE");
    9. OCO Order Example
    • i. FIX::N_BIT10::BOTransaction* _t = new(_nlogon) FIX::N_BIT10::BOTransaction();
    • ii. _t->setMessageType(FIX::N_BIT10::MESSAGE_TYPE::ORDER_NEW);
    • iii. _t->setAccount(100500);
    • iv. _t->setTradingSessionID(200);
    • v. _t->setOrderType(FIX::N_BIT10::ORD_TYPE::PEG);
    • vi. _t->setBOSide((short)FIX::N_BIT10::SIDE::SELL);
    • vii. _t->setOrderID(ordID_++);
    • viii. _t->setBOPrice(9165.0);
    • ix. _t->setBOOrderQty(5.000);
    • x. _t->setStopLimitPrice(9160.000);
    • xi. _t->setDisplaySize(0.50);
    • xii. _t->setRefreshSize(0.25);
    • xiii. _t->setSymbolType(FIX::N_BIT10:: SYMBOL_TYPE::SPOT);
    • xiv. _t->setSymbolEnum FIX::N_BIT10::SYMBOL_VALUE_ENUM::FLYUSDT);
    • xv. _t setMsgSeqNum(++msgSeqNum);
    • xvi. _t->setSymbolName("FLYUSDT");
    • xvii. _t->setTraderID("NONE");
    17. Enumerations
    1. Attribute
    • i. enum ATTRIBUTE_ENUM : char {
    • ii. POPPED,
    • iii. HIDDEN_ATTRIBUTE,
    • iv. DISPLAYSIZE_ATTRIBUTE,
    • v. STOPMKT_ATTRIBUTE,
    • vi. STOPLMT_ATTRIBUTE,
    • vii. TSL_ATTRIBUTE,
    • viii. TSM_ATTRIBUTE,
    • ix. PEG_ATTRIBUTE,
    • x. POSTONLY_ATTRIBUTE,
    • xi. REDUCE_ATTRIBUTE,
    • xii. }
    2. SymbolEnum
    • i. enum SYMBOL_VALUE_ENUM : short {
    • ii. BTCUSD = 1,
    • iii. USDUSDT,,
    • iv. FLYUSDT,
    • v. BTCUSDT,
    • vi. ETHUSD,
    • vii. ETHGBP,
    • viii. BTC,
    • ix. LTC,
    • x. XRPUSD,
    • xi. USDT,
    • xii. XRP,
    • xiii. USD,
    • xiv. USDC,
    • xv. };
    3. SymbolType
    • i. enum SYMBOL_TYPE : short {
    • ii. SPOT = 1,
    • iii. FUT,
    • iv. DERIVITIVE,
    • v. };
    4. Fee Type
    • i. enum FEE_TYPE : short {
    • ii. MAKE = 1,
    • iii. TAKE,
    • iv. };
    5. Side
    • i. enum SIDE : short {
    • ii. BUY = 1,
    • iii. SELL,
    • iv. SELLSHORT,
    • v. };
    6. enum TIF : short {
    7. FOK = 1,
    8. GTC,
    9. IOC,
    10. POO, // Make only
    11. RED, // Reduce only
    12. DAY,
    13. };