Exemple #1
0
        public OrderBook GetOrderBook()
        {
            string     endPoint = "https://www.okcoin.com/api/v1/depth.do";
            RestClient client   = new RestClient(endPoint, RestClient.HttpVerb.GET);

            string reqMsg = $"?symbol={TradeSymbolString}&size=5";
            var    json   = client.MakeRequest(reqMsg);

            var response = (JObject)JsonConvert.DeserializeObject(json);
            var asks     = (JArray)response["asks"];
            var bids     = (JArray)response["bids"];

            OrderBook orderBook = new OrderBook();

            foreach (var ask in asks)
            {
                orderBook.AddOrder((double)ask[0], (double)ask[1], MDEntryType.OFFER);
            }
            foreach (var bid in bids)
            {
                orderBook.AddOrder((double)bid[0], (double)bid[1], MDEntryType.BID);
            }

            return(orderBook);
        }
Exemple #2
0
        public void RemoveOffer()
        {
            OrderBook book = new OrderBook();

            book.AddOrder(10, 1, MDEntryType.OFFER);
            book.AddOrder(11, 2, MDEntryType.OFFER);
            book.AddOrder(12, 3, MDEntryType.OFFER);

            book.RemoveOrder(10, MDEntryType.OFFER);

            Assert.AreEqual(11, book.BestOffer.Price);
            Assert.AreEqual(5, book.CumulativeVolume(12, MDEntryType.OFFER));
        }
Exemple #3
0
        public void RemoveBid()
        {
            OrderBook book = new OrderBook();

            book.AddOrder(10, 1, MDEntryType.BID);
            book.AddOrder(11, 2, MDEntryType.BID);
            book.AddOrder(12, 3, MDEntryType.BID);

            book.RemoveOrder(12, MDEntryType.BID);

            Assert.AreEqual(11, book.BestBid.Price);
            Assert.AreEqual(3, book.CumulativeVolume(10, MDEntryType.BID));
        }
Exemple #4
0
        /// <summary>
        /// Initial market data snapshot
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="sessionID"></param>
        public void OnMessage(QuickFix.FIX44.MarketDataSnapshotFullRefresh msg, SessionID sessionID)
        {
            var numMDEntries = msg.GetInt(Tags.NoMDEntries);

            for (int i = 1; i <= numMDEntries; i++)
            {
                var entry     = msg.GetGroup(i, Tags.NoMDEntries);
                var entryType = entry.GetChar(Tags.MDEntryType);
                if (entryType.Equals(MDEntryType.BID) || entryType.Equals(MDEntryType.OFFER))
                {
                    CurrentOrderBook.AddOrder((double)entry.GetDecimal(Tags.MDEntryPx), (double)entry.GetDecimal(Tags.MDEntrySize), entry.GetChar(Tags.MDEntryType));
                }
                else if (entryType.Equals(MDEntryType.TRADE))
                {
                    LastTrade = new Trade()
                    {
                        Price  = (double)entry.GetDecimal(Tags.MDEntryPx),
                        Volume = (double)entry.GetDecimal(Tags.MDEntrySize)
                    };
                }
                else
                {
                    Log.Write($"Unknown entry type {entryType}", 0);
                }
            }
        }
Exemple #5
0
        public OrderBook GetOrderBook()
        {
            var endPoint = $"https://api.bitfinex.com/v1/book/{TradeSymbol}";
            var client   = new RestClient(endPoint, RestClient.HttpVerb.GET);

            var json     = client.MakeRequest("?limit_bids=2&limit_asks=2&group=1", null, false);
            var response = (JObject)JsonConvert.DeserializeObject(json);

            OrderBook orderBook = new OrderBook();

            foreach (var data in response["bids"])
            {
                orderBook.AddOrder((double)data["price"], (double)data["amount"], MDEntryType.BID);
            }
            foreach (var data in response["asks"])
            {
                orderBook.AddOrder((double)data["price"], (double)data["amount"], MDEntryType.OFFER);
            }
            return(orderBook);
        }
Exemple #6
0
        public void ChangeBid()
        {
            OrderBook book = new OrderBook();

            book.AddOrder(10, 1, MDEntryType.BID);
            book.AddOrder(11, 2, MDEntryType.BID);
            book.AddOrder(12, 3, MDEntryType.BID);

            book.ChangeOrder(12.5, 4, MDEntryType.BID);

            Assert.AreEqual(12.5, book.BestBid.Price);
            Assert.AreEqual(4, book.BestBid.Volume);
            Assert.AreEqual(12, book.BestBid.Next.Price);
            Assert.AreEqual(3, book.BestBid.Next.Volume);

            Assert.AreEqual(4, book.NumBids);

            Assert.AreEqual(7, book.CumulativeVolume(11.2, MDEntryType.BID));
            Assert.AreEqual(10, book.CumulativeVolume(10, MDEntryType.BID));

            Assert.IsNull(book.BestOffer);
        }
Exemple #7
0
        public void AddOffers()
        {
            OrderBook book = new OrderBook();

            book.AddOrder(10, 1, MDEntryType.OFFER);
            book.AddOrder(11, 2, MDEntryType.OFFER);
            book.AddOrder(12, 3, MDEntryType.OFFER);

            Assert.AreEqual(10, book.BestOffer.Price);
            Assert.AreEqual(1, book.BestOffer.Volume);
            Assert.AreEqual(11, book.BestOffer.Next.Price);
            Assert.AreEqual(2, book.BestOffer.Next.Volume);

            Assert.AreEqual(3, book.NumOffers);

            Assert.AreEqual(6, book.CumulativeVolume(12, MDEntryType.OFFER));
            Assert.AreEqual(1, book.CumulativeVolume(10, MDEntryType.OFFER));

            Assert.AreEqual(11, book.PriceDepth(2, MDEntryType.OFFER));
            Assert.AreEqual(12, book.PriceDepth(5, MDEntryType.OFFER));

            Assert.IsNull(book.BestBid);
        }
Exemple #8
0
        public void AddBids()
        {
            OrderBook book = new OrderBook();

            book.AddOrder(10, 1, MDEntryType.BID);
            book.AddOrder(11, 2, MDEntryType.BID);
            book.AddOrder(12, 3, MDEntryType.BID);

            Assert.AreEqual(12, book.BestBid.Price);
            Assert.AreEqual(3, book.BestBid.Volume);
            Assert.AreEqual(11, book.BestBid.Next.Price);
            Assert.AreEqual(2, book.BestBid.Next.Volume);

            Assert.AreEqual(3, book.NumBids);

            Assert.AreEqual(3, book.CumulativeVolume(12, MDEntryType.BID));
            Assert.AreEqual(6, book.CumulativeVolume(10, MDEntryType.BID));

            Assert.AreEqual(11, book.PriceDepth(4, MDEntryType.BID));
            Assert.AreEqual(12, book.PriceDepth(3, MDEntryType.BID));

            Assert.IsNull(book.BestOffer);
        }
 public IHttpActionResult Post([FromBody] AddOrderRequestModel request)
 {
     OrderBook.AddOrder(request.IsBuyOrder, request.Amount, request.Count, request.UserId);
     return(Ok());
 }
Exemple #10
0
        // QUESTION: Consider making async: https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap
        public OrderResponseBL SubmitOrder(IOrderContext context, ISubscriber subscriber, IAccountServiceRpcClient accountService, OrderBL order)
        {
#if (PERF || PERF_FINE || PERF_FINEST)
            long start = Now;
#endif
            OrderResponseBL insertResponse = InsertOrder(context, subscriber, order);
            if (insertResponse.HasErrors)
            {
                return(insertResponse);
            }

            OrderBook book = order.IsMarketOrder ?
                             order.IsBuyOrder ? SellBook : BuyBook :
                             order.IsBuyOrder ? BuyBook : SellBook;
            if (order.IsMarketOrder)
            {
                // QUESTION: Could potentially optimize to not do an initial save of a Market order
                //           but can we allow order entry during market close hours? What's MarketOnOpen?
                // The actual outcome of the match will be responded back asynchronously
                OrderTransactionResponseBL fillResponse = FillMarketOrder(accountService, order, book);
                if (fillResponse.HasErrors)
                {
                    return(insertResponse);
                }
                fillResponse = SaveOrderTransaction(context, subscriber, fillResponse.Data);
                if (fillResponse.HasErrors)
                {
                    return(insertResponse);
                }
#if DIAGNOSTICS
                DiagnosticsWriteDetails(fillResponse.Data);
#endif
#if (PERF || PERF_FINE || PERF_FINEST)
                Logger.Here().Information(String.Format("SubmitOrder: Market order executed in {0} milliseconds", ((Now - start) / TimeSpan.TicksPerMillisecond)));
#endif
                return(new OrderResponseBL(order));
            }

            book.AddOrder(order);
            bool done = false;
            while (!done)
            {
                if (BuyBook.IsEmpty || SellBook.IsEmpty)
                {
                    throw new SystemException("Order book is empty");                                 // TODO: Handle order book is empty
                }
                // The new order triggered a match
                // We'll try to match it here, but respond back with the insertResponse regardless
                // The actual outcome of the match will be responded back asynchronously
                if (BuyBook.First.StrikePrice >= SellBook.First.StrikePrice)
                {
                    OrderTransactionResponseBL fillResponse = TryFillOrderBook(accountService);
                    if (fillResponse.HasErrors)
                    {
                        return(insertResponse);
                    }
                    fillResponse = SaveOrderTransaction(context, subscriber, fillResponse.Data);
                    if (fillResponse.HasErrors)
                    {
                        return(insertResponse);
                    }
#if DIAGNOSTICS
                    DiagnosticsWriteDetails(fillResponse.Data);
#endif
                }
                else
                {
                    done = true;
                }
            }
#if (PERF || PERF_FINE || PERF_FINEST)
            Logger.Here().Information(String.Format("SubmitOrder: Processed in {0} milliseconds", ((Now - start) / TimeSpan.TicksPerMillisecond)));
#endif
            return(insertResponse);
        }
Exemple #11
0
        private void SocketTerminal_OnMessageReceived(object sender, MessageReceivedEventArgs e)
        {
            Log.Write($"Message received: {e.Message}", 3);

            var data = JsonConvert.DeserializeObject(e.Message);

            if (data is JObject)
            {
                var dataObject = (JObject)data;
                var eventType  = dataObject["event"].ToString();
                if (eventType.Equals("subscribed"))
                {
                    ChannelID.Add(dataObject["channel"].ToString(), (int)dataObject["chanId"]);
                }
                else if (eventType.Equals("auth"))
                {
                    var errorCode = dataObject["code"];
                    if (errorCode != null)
                    {
                        Log.Write($"Authentication failure with code {errorCode} | msg: {dataObject["msg"]}", 0);
                    }
                }
                else if (eventType.Equals("error"))
                {
                    Log.Write($"Error code: {dataObject["code"]} | msg: {dataObject["msg"]}", 0);
                }
            }
            else if (data is JArray)
            {
                var dataArray = (JArray)data;
                var channelID = (int)dataArray[0];
                if (channelID == ChannelID["auth"])
                {
                    var msgType = dataArray[1].ToString();
                    if (msgType.Equals("ws"))   // wallet snapshot
                    {
                        var wallets = dataArray[2];
                        for (var wal = wallets.First; wal != null; wal = wal.Next)
                        {
                            if (wal[0].ToString().Equals("exchange"))
                            {
                                var currency = wal[1].ToString();
                                if (currency.Equals("USD"))
                                {
                                    BalanceFiat = (double)wal[2];
                                }
                                else if (currency.Equals(Symbol))
                                {
                                    BalanceSecurity = (double)wal[2];
                                }
                            }
                        }
                    }
                    else if (msgType.Equals("wu"))  // wallet update
                    {
                        // Only consider exchange wallets
                        if (dataArray[2][0].ToString().Equals("exchange"))
                        {
                            var currency = dataArray[2][1].ToString();
                            if (currency.Equals("USD"))
                            {
                                BalanceFiat = (double)dataArray[2][2];
                            }
                            else if (currency.Equals(Symbol))
                            {
                                BalanceSecurity = (double)dataArray[2][2];
                            }
                        }
                    }
                    else if (msgType.Equals("on"))  // new order confirmation
                    {
                        string symbol = dataArray[2][3].ToString();
                        if (symbol.Equals(TradeSymbol))
                        {
                            var order = new Order()
                            {
                                OrderID       = dataArray[2][0].ToString(),
                                ClientOrderID = (long)dataArray[2][2],
                                Price         = (double)dataArray[2][16],
                                Time          = new DateTime(1970, 1, 1).AddMilliseconds((double)dataArray[2][4]),
                                Volume        = Math.Abs((double)dataArray[2][7]),
                                FilledVolume  = Math.Abs((double)dataArray[2][6] - (double)dataArray[2][7]),
                                Side          = (double)dataArray[2][6] > 0 ? Side.BUY : Side.SELL,
                                OrderType     = dataArray[2][8].ToString().Contains("LIMIT") ? OrdType.LIMIT : OrdType.MARKET
                            };
                            CurrentOrders.Add(order);
                            OrderSubmitCallback?.Invoke(false);
                            OrderSubmitCallback = null;
                            Log.Write($"Submitted {order}", 2);
                        }
                    }
                    else if (msgType.Equals("oc"))  // cancel order confirmation
                    {
                        string symbol = dataArray[2][3].ToString();
                        if (symbol.Equals(TradeSymbol))
                        {
                            string status  = dataArray[2][13].ToString();
                            string orderId = dataArray[2][0].ToString();
                            var    order   = CurrentOrders.FirstOrDefault(o => o.OrderID.Equals(orderId));

                            if (order != null)
                            {
                                if (status.Contains("EXECUTED")) // executed
                                {
                                    order.FilledVolume = Math.Abs((double)dataArray[2][6] - (double)dataArray[2][7]);
                                    Log.Write($"Executed {order}", 2);
                                }
                                else if (status.Contains("PARTIALLY FILLED"))
                                {
                                    order.FilledVolume = Math.Abs((double)dataArray[2][6] - (double)dataArray[2][7]);
                                    Log.Write($"Partial fill {order}", 2);
                                }
                                else // cancelled
                                {
                                    CurrentOrders.Remove(order);
                                    OrderCancelCallback?.Invoke(false);
                                    OrderCancelCallback = null;
                                    Log.Write($"Cancelled {order}", 2);
                                }
                            }
                            else
                            {
                                // unregistered
                                order = new Order()
                                {
                                    OrderID       = dataArray[2][0].ToString(),
                                    ClientOrderID = (long)dataArray[2][2],
                                    Price         = (double)dataArray[2][16],
                                    Time          = new DateTime(1970, 1, 1).AddMilliseconds((double)dataArray[2][4]),
                                    Volume        = Math.Abs((double)dataArray[2][7]),
                                    FilledVolume  = Math.Abs((double)dataArray[2][6] - (double)dataArray[2][7]),
                                    Side          = (double)dataArray[2][6] > 0 ? Side.BUY : Side.SELL,
                                    OrderType     = dataArray[2][8].ToString().Contains("LIMIT") ? OrdType.LIMIT : OrdType.MARKET
                                };

                                if (status.Contains("EXECUTED"))
                                {
                                    Log.Write($"Executed unregistered {orderId} (This should happen VERY rarily)", 2);
                                }
                                else
                                {
                                    Log.Write($"Cancelled unregistered {orderId}", 2);
                                }
                            }
                        }
                    }
                    else if (msgType.Equals("os"))  // order info snapshot
                    {
                        var orders = dataArray[2];
                        foreach (var order in orders)
                        {
                            string symbol  = order[3].ToString();
                            string orderId = order[0].ToString();
                            // If order is not yet registered locally
                            if (symbol.Equals(TradeSymbol) && !CurrentOrders.Any(o => o.OrderID.Equals(orderId)))
                            {
                                CurrentOrders.Add(new Order()
                                {
                                    OrderID       = orderId,
                                    ClientOrderID = (long)order[2],
                                    Price         = (double)order[12],
                                    Volume        = Math.Abs((double)order[7]),
                                    FilledVolume  = Math.Abs((double)order[6] - (double)order[7]),
                                    Side          = (double)order[6] > 0 ? Side.BUY : Side.SELL,
                                    OrderType     = order[8].ToString().Contains("LIMIT") ? OrdType.LIMIT : OrdType.MARKET,
                                    Time          = new DateTime(1970, 1, 1).AddMilliseconds((double)order[4]),
                                });
                            }
                        }
                    }
                    else if (msgType.Equals("ou"))  // order info update
                    {
                        string symbol  = dataArray[2][3].ToString();
                        string orderId = dataArray[2][0].ToString();
                        if (symbol.Equals(TradeSymbol))
                        {
                            var order = CurrentOrders.FirstOrDefault(o => o.OrderID.Equals(orderId));
                            if (order == null)
                            {
                                order = new Order()
                                {
                                    OrderID       = dataArray[2][0].ToString(),
                                    ClientOrderID = (int)dataArray[2][2],
                                    Time          = new DateTime(1970, 1, 1).AddMilliseconds((double)dataArray[2][4]),
                                    Volume        = Math.Abs((double)dataArray[2][7]),
                                    FilledVolume  = Math.Abs((double)dataArray[2][6] - (double)dataArray[2][7]),
                                    Side          = (double)dataArray[2][6] > 0 ? Side.BUY : Side.SELL,
                                    OrderType     = dataArray[2][8].ToString().Contains("LIMIT") ? OrdType.LIMIT : OrdType.MARKET
                                };
                                CurrentOrders.Add(order);
                            }
                            else
                            {
                                order.FilledVolume = Math.Abs((double)dataArray[2][6] - (double)dataArray[2][7]);
                                Log.Write($"Update {order}", 2);
                            }
                        }
                    }
                    else if (msgType.Equals("tu"))  // trades
                    {
                        string symbol = dataArray[2][1].ToString();
                        if (TradeSymbol.Contains(symbol))
                        {
                            string orderId = dataArray[2][3].ToString();
                            var    order   = CurrentOrders.FirstOrDefault(o => o.OrderID.Equals(orderId));
                            if (order != null)
                            {
                                order.FilledVolume = Math.Abs((double)dataArray[2][4]);
                                Log.Write($"Trade info about {order}", 2);
                                if (order.FilledVolume >= order.Volume)
                                {
                                    CurrentOrders.Remove(order);
                                }
                            }
                            else
                            {
                                Log.Write($"Trade info about unregistered order", 1);
                            }
                        }
                    }
                    else if (msgType.Equals("n"))   // notification
                    {
                        string status = dataArray[2][6].ToString();
                        if (status.Equals("ERROR"))
                        {
                            Log.Write($"Error: {dataArray[2][7].ToString()}", 0);
                            string req = dataArray[2][1].ToString();
                            if (req.Equals("on-req"))   // new order error
                            {
                                OrderSubmitCallback?.Invoke(true);
                            }
                            else if (req.Equals("oc-req"))  // cancel order error
                            {
                                OrderCancelCallback?.Invoke(true);
                            }
                        }
                        else if (status.Equals("FAILURE"))
                        {
                            Log.Write($"Failure: {dataArray[2][7].ToString()}", 0);
                        }
                        else if (status.Equals("SUCCESS"))
                        {
                            Log.Write($"Notification: {dataArray[2][7].ToString()}", 2);
                        }
                        else if (status.Equals("INFO"))
                        {
                            Log.Write($"Information: {dataArray[2][7].ToString()}", 2);
                        }
                    }
                }
                else if (ChannelID.ContainsKey("trades") && channelID == ChannelID["trades"])
                {
                    if (dataArray[1] is JArray) // snapshot
                    {
                        var trades    = dataArray[1];
                        var lastTrade = trades.First;
                        LastTrade = new Trade()
                        {
                            Price  = (double)lastTrade[3],
                            Volume = (double)lastTrade[2]
                        };
                    }
                    else // update
                    {
                        if (dataArray[1].ToString().Equals("te"))
                        {
                            LastTrade = new Trade()
                            {
                                Price  = (double)dataArray[2][3],
                                Volume = (double)dataArray[2][2]
                            };
                        }
                    }
                }
                else if (ChannelID.ContainsKey("book") && channelID == ChannelID["book"])
                {
                    // heartbeat
                    if (dataArray[1].ToString().Equals("hb"))
                    {
                    }
                    // Snapshot
                    else if (dataArray[1][0] is JArray)
                    {
                        foreach (var entry in dataArray[1])
                        {
                            int count = (int)entry[1];
                            if (count == 0)
                            {
                                Log.Write("Error: zero count in order book snapshot", 0);
                            }
                            else
                            {
                                double volume = (double)entry[2];
                                CurrentOrderBook.AddOrder((double)entry[0], volume, volume > 0 ? MDEntryType.BID : MDEntryType.OFFER);
                            }
                        }
                    }
                    // Update
                    else
                    {
                        int count = (int)dataArray[1][1];
                        if (count > 0)  // change bid
                        {
                            CurrentOrderBook.ChangeOrder((double)dataArray[1][0], (double)dataArray[1][2], (double)dataArray[1][2] > 0 ? MDEntryType.BID : MDEntryType.OFFER);
                        }
                        else // remove
                        {
                            CurrentOrderBook.RemoveOrder((double)dataArray[1][0], (double)dataArray[1][2] > 0 ? MDEntryType.BID : MDEntryType.OFFER);
                        }
                    }
                }
            }
            else
            {
                Log.Write($"Unknown message json type: {data.GetType()}", 0);
            }
        }