private unsafe void BookRebuild(LimeQuoteMessage message) { //UNDONE: Use the symbol_len field from the message and the action to filter LimeQuotesInterop.book_rebuild_msg *bookMsg = (LimeQuotesInterop.book_rebuild_msg *)message.Ptr; int last = 0; for (int i = 0; i < LimeQuotesInterop.SYMBOL_LEN; i++) { if (bookMsg->symbol[i] == 0) { last = i; break; } } string symbol = new string((sbyte *)bookMsg->symbol, 0, last); log.InfoFormat("Book Rebuild for {0} id {1} flags {2}", symbol, bookMsg->symbol_index, bookMsg->symbol_flags); using (_SymbolIDLock.Using()) { uint id = Reverse(bookMsg->symbol_index); if (!_SymbolID.ContainsKey(symbol)) { _SymbolID.Add(symbol, id); _IDToSymbol.Add(id, symbol); _IDToBookRebuild.Add(id, (bookMsg->symbol_flags & 1) == 0); } else { _SymbolID[symbol] = id; _IDToSymbol[id] = symbol; _IDToBookRebuild[id] = (bookMsg->symbol_flags & 1) == 0; } } }
protected override void ReceiveMessage(LimeQuoteMessage message) { switch (message.MessageType) { case LimeQuotesInterop.limeq_message_type.SUBSCRIPTION_REPLY: SubscriptionReply(message); break; case LimeQuotesInterop.limeq_message_type.BOOK_REBUILD: BookRebuild(message); break; case LimeQuotesInterop.limeq_message_type.TRADE: TradeUpdate(message); break; case LimeQuotesInterop.limeq_message_type.ORDER: OrderUpdate(message); break; case LimeQuotesInterop.limeq_message_type.MOD_EXECUTION: ModExecution(message); break; default: log.InfoFormat("Message {0} not handled", message.MessageType); break; } }
static readonly string BATS = "BATS"; // Citirus Demo server private unsafe void RequestStartSymbol(SymbolInfo symbol, Agent symbolAgent) { StartSymbolHandler(symbol, symbolAgent); if (symbol.OptionChain != OptionChain.None) { //TODO: Implement options throw new NotSupportedException(); //StartSymbolOptionHandler(symbol, symbolAgent); } LimeQuoteMessage message = (LimeQuoteMessage)Socket.MessageFactory.Create(); LimeQuotesInterop.subscription_request_msg *subRequest = (LimeQuotesInterop.subscription_request_msg *)message.Ptr; subRequest->msg_type = LimeQuotesInterop.limeq_message_type.SUBSCRIPTION_REQUEST; ushort msgLength = (ushort)(sizeof(LimeQuotesInterop.subscription_request_msg) - 64 + symbol.Symbol.Length + 1); subRequest->msg_len = Reverse(msgLength); message.Length = msgLength; //TODO: Fix to use user selected qsid for (int i = 0; i < 4; i++) { subRequest->qsid[i] = (byte)BATS[i]; } subRequest->flags = LimeQuotesInterop.subscription_flags.SUBSCRIPTION_FLAG_MARKET_DATA; subRequest->num_symbols = 1; for (int i = 0; i < symbol.Symbol.Length; i++) { subRequest->syb_symbols[i] = (byte)symbol.Symbol[i]; } subRequest->syb_symbols[symbol.Symbol.Length] = 0; log.InfoFormat("Sending subscrption request for {0}", symbol.Symbol); while (!Socket.TrySendMessage(message)) { if (IsInterrupted) { return; } Factory.Parallel.Yield(); } //TODO: Options not yet implemented EventItem item; if (symbol.DisableRealtimeSimulation) { item = new EventItem(symbol, EventType.StartBroker); symbolAgent.SendEvent(item); } item = new EventItem(symbol, EventType.StartRealTime); symbolAgent.SendEvent(item); }
private unsafe void SubscriptionReply(LimeQuoteMessage message) { LimeQuotesInterop.subscription_reply_msg *subReply = (LimeQuotesInterop.subscription_reply_msg *)message.Ptr; if (subReply->outcome != LimeQuotesInterop.subscription_outcome.SUBSCRIPTION_SUCCESSFUL) { log.ErrorFormat("Subscription request failed: error code {0}", subReply->outcome.ToString()); } else { log.InfoFormat("Subscription started"); } }
public unsafe override void SendLogin() { Socket.MessageFactory = new MessageFactoryLimeQuotes(); LimeQuoteMessage message = (LimeQuoteMessage)Socket.MessageFactory.Create(); LimeQuotesInterop.login_request_msg *loginRequest = (LimeQuotesInterop.login_request_msg *)message.Ptr; ushort msgLength = (ushort)sizeof(LimeQuotesInterop.login_request_msg); loginRequest->msg_len = Swap(msgLength); loginRequest->msg_type = LimeQuotesInterop.limeq_message_type.LOGIN_REQUEST; loginRequest->auth_type = LimeQuotesInterop.auth_types.CLEAR_TEXT; message.Length = msgLength; for (int i = 0; i < UserName.Length; i++) { loginRequest->uname[i] = (byte)UserName[i]; } for (int i = 0; i < Password.Length; i++) { loginRequest->passwd[i] = (byte)Password[i]; } for (int i = 0; i < LimeQuotesInterop.HOST_ID_LEN; i++) { loginRequest->host_id[i] = 0; } loginRequest->session_type = LimeQuotesInterop.app_type.CPP_API; loginRequest->heartbeat_interval = LimeQuotesInterop.heartbeat; loginRequest->timeout_interval = LimeQuotesInterop.heartbeatTimeout; loginRequest->ver_major = LimeQuotesInterop.majorVersion; loginRequest->ver_minor = LimeQuotesInterop.minorVersion; if (trace) { log.Trace("Sending: " + UserName); } if (debug) { log.Debug("Sending: " + UserName); } while (!Socket.TrySendMessage(message)) { if (IsInterrupted) { return; } Factory.Parallel.Yield(); } }
private unsafe void TradeUpdate(LimeQuoteMessage message) { var trade = (LimeQuotesInterop.trade_msg *)message.Ptr; uint symbolIndex = Reverse(trade->common.symbol_index); var symbol = FindSymbol(symbolIndex); var symbolInfo = Factory.Symbol.LookupSymbol(symbol); var handler = symbolHandlers[symbolInfo.BinaryIdentifier]; double price = LimeQuoteMessage.priceToDouble(trade->common.price_mantissa, trade->common.price_exponent); uint totalVolume = Reverse(trade->total_volume); handler.Last = price; handler.LastSize = (int)totalVolume; if (UseLocalTickTime) { SetLocalTickTIme(handler); if (trace) { log.TraceFormat("Trade {0} at {1} ", symbol, price); } //handler.SendQuote(); } else { // is simulator. var ordertime = trade->common.timestamp | ((long)trade->common.order_id << 32); SetSimulatorTime(handler, ordertime); if (trace) { log.TraceFormat("Trade {0} at {1} time: {2}", symbol, price, new TimeStamp(ordertime)); } //handler.SendQuote(); } handler.SendTimeAndSales(); }
public unsafe override bool VerifyLogin() { bool verified = false; Message message; if (!Socket.TryGetMessage(out message)) { return(verified); } LimeQuoteMessage limeMessage = (LimeQuoteMessage)message; if (limeMessage.MessageType == LimeQuotesInterop.limeq_message_type.LOGIN_RESPONSE) { LimeQuotesInterop.login_response_msg *response = (LimeQuotesInterop.login_response_msg *)limeMessage.Ptr; if (response->response_code == LimeQuotesInterop.reject_reason_code.LOGIN_SUCCEEDED) { log.Info("Lime Login verified"); verified = true; } else { log.ErrorFormat("Lime Quotes Login Failed: {0}", response->response_code.ToString()); } } else if (limeMessage.MessageType == LimeQuotesInterop.limeq_message_type.LIMEQ_CONTROL) { var response = (LimeQuotesInterop.limeq_control_msg *)limeMessage.Ptr; log.InfoFormat("Lime Control {0}", response->code); } else { log.ErrorFormat("Lime unexpected message {0}", limeMessage.MessageType); } return(verified); }
public unsafe static void LogMessage(byte *message, Log log) { ushort length = (ushort)((message[0] << 8) | message[1]); if (length < 3) { return; } var messageType = (LimeQuotesInterop.limeq_message_type)message[2]; string logMessage = ""; string symbol = ""; switch (messageType) { case LimeQuotesInterop.limeq_message_type.LOGIN_RESPONSE: var lrm = (LimeQuotesInterop.login_response_msg *)message; logMessage = string.Format("Login Response ({1} bytes) Ver={5}.{6}, Resp={3}, heartbeat={2}, timeout={5}", messageType, length, lrm->heartbeat_interval, lrm->response_code, lrm->timeout_interval, lrm->ver_major, lrm->ver_minor); break; case LimeQuotesInterop.limeq_message_type.BOOK_REBUILD: var br = (LimeQuotesInterop.book_rebuild_msg *)message; int symLength = 0; for (int i = 0; i < 21; i++) { if (br->symbol[i] == 0) { symLength = i; break; } } symbol = new string((sbyte *)br->symbol, 0, symLength); logMessage = string.Format("Book rebuild symbol '{0}' flags: {1} index {2}", symbol, br->symbol_flags, Reverse(br->symbol_index)); break; case LimeQuotesInterop.limeq_message_type.ORDER: var order = (LimeQuotesInterop.order_msg *)message; logMessage = string.Format("Order id {0}: symbol '{1}' price {6} timestamp {2} side {3} shares {4} flags {5}", order->common.order_id, GetSymbol(order->common.symbol_index), order->common.timestamp, order->common.side, Reverse(order->common.shares), order->common.quote_flags, LimeQuoteMessage.priceToDouble(order->common.price_mantissa, order->common.price_exponent)); break; case LimeQuotesInterop.limeq_message_type.TRADE: var trade = (LimeQuotesInterop.trade_msg *)message; logMessage = string.Format("Trade id {0}: symbol '{1}' price {10} timestamp {2} size {3} shared {4} flags {5} fill {6} fill2 {7} flags {8} total vol {9}", trade->common.order_id, GetSymbol(trade->common.symbol_index), trade->common.timestamp, trade->common.side, Reverse(trade->common.shares), trade->common.quote_flags, trade->fill1, Reverse(trade->fill2), trade->flags, Reverse(trade->total_volume), LimeQuoteMessage.priceToDouble(trade->common.price_mantissa, trade->common.price_exponent) ); break; default: logMessage = string.Format("Message {0} ({1} bytes)", messageType, length); break; } log.Trace(logMessage); log.Trace("Message HexDump: " + Environment.NewLine + HexDump(message, length, 32)); }
private unsafe void TimeAndSalesUpdate(LimeQuoteMessage message) { throw new NotImplementedException(); }
private unsafe void OrderUpdate(LimeQuoteMessage message) { LimeQuotesInterop.order_msg *order = (LimeQuotesInterop.order_msg *)message.Ptr; bool isTopOfBook = (order->common.quote_flags & 1) == 1; uint symbolIndex = Reverse(order->common.symbol_index); var symbol = FindSymbol(symbolIndex); bool bookUpdate = true; if (!_IDToBookRebuild.TryGetValue(symbolIndex, out bookUpdate)) { bookUpdate = true; } if (isTopOfBook) { SymbolHandler handler; try { SymbolInfo symbolInfo = Factory.Symbol.LookupSymbol(symbol); handler = symbolHandlers[symbolInfo.BinaryIdentifier]; } catch (ApplicationException) { log.Info("Received tick: " + new string(message.DataIn.ReadChars(message.Remaining))); throw; } // For the simulator, it should send the Ask first, then the bid. However, the test code expects // both prices to appear in one quote. So we cache the ask, then send the quote on the bid. bool sendQuote = false; double price = LimeQuoteMessage.priceToDouble(order->common.price_mantissa, order->common.price_exponent); long ordertime = order->common.timestamp | ((long)order->common.order_id << 32); if (order->common.side == LimeQuotesInterop.quote_side.SELL) { handler.Ask = price; handler.AskSize = (int)Reverse(order->common.shares); if (trace) { log.TraceFormat("Ask {0} at {1} size {2} time: {3}", symbol, price, handler.AskSize, new TimeStamp(ordertime)); } } else { handler.Bid = price; handler.BidSize = (int)Reverse(order->common.shares); if (trace) { log.TraceFormat("Bid {0} at {1} size {2} time: {3}", symbol, price, handler.BidSize, new TimeStamp(ordertime)); } sendQuote = true; } //TODO: Translate Cirtris timestamp to internal if (UseLocalTickTime) { if (trace) { log.TraceFormat("{0}: Bid {1} Ask: {2} BidShares {3} AskShares: {4}", symbol, handler.Bid, handler.Ask, handler.BidSize, handler.AskSize); } SetLocalTickTIme(handler); handler.SendQuote(); } else { // is simulator. if (sendQuote) { SetSimulatorTime(handler, ordertime); handler.SendQuote(); } } } else if (trace) { log.TraceFormat("Quote not top of book"); } }
protected abstract void ReceiveMessage(LimeQuoteMessage message);