/// <summary>Access the order book for the given pair</summary> public MarketDepth this[CurrencyPair pair] // Worker thread context { get { try { // The locking idea here is, lock to get the stream for 'pair'. // Then lock the orderbook of that stream and make a copy. var stream = (MarketStream)null; lock (Streams) { // Look for the stream for 'pair'. Create if not found. if (!Streams.TryGetValue(pair, out stream) || stream.Socket == null) { stream = Streams[pair] = new MarketStream(pair, this); } } lock (stream.MarketDepth) { // Return a copy since any thread can call this function. return(new MarketDepth(stream.MarketDepth)); } } catch (Exception ex) { BinanceApi.Log.Write(ELogLevel.Error, ex, $"Subscribing to market updates for {pair.Id} failed."); lock (Streams) Streams.Remove(pair); return(new MarketDepth(pair)); } } }
/// <summary>Return the order book for the given pair</summary> public OrderBook this[CurrencyPair pair] // Any thread context { get { try { var stream = (MarketStream)null; var subscribe = false; lock (Streams) { // Look for the stream for 'pair'. Create if not found. if (!Streams.TryGetValue(pair, out stream)) { stream = Streams[pair] = new MarketStream(pair, this); subscribe = true; } } // This cannot be done in the constructor or MarketStream because the Socket calls will deadlock if (subscribe) { // Add a new subscription for updates to 'pair' Socket.SubscribeToExchangeDeltas(pair.Id).Wait(); // Request a full snapshot to initialise the order book var jtok = Socket.QueryExchangeState(pair.Id).Result; var snapshot = jtok.ToObject <MarketSnapshot>(); stream.ApplyUpdate(snapshot); } lock (stream.OrderBook) { // Return a copy since any thread can call this function. return(new OrderBook(stream.OrderBook)); } } catch (Exception ex) { BittrexApi.Log.Write(ELogLevel.Error, $"Subscribing to market updates for {pair} failed. {ex.Message}"); lock (Streams) Streams.Remove(pair); return(new OrderBook(pair, 0)); } } }