diff --git a/Brokerages/Bitfinex/BestBidAskUpdatedEventArgs.cs b/Brokerages/Bitfinex/BestBidAskUpdatedEventArgs.cs
new file mode 100644
index 000000000000..753a2f976f31
--- /dev/null
+++ b/Brokerages/Bitfinex/BestBidAskUpdatedEventArgs.cs
@@ -0,0 +1,67 @@
+/*
+ * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
+ * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+using System;
+
+namespace QuantConnect.Brokerages.Bitfinex
+{
+ ///
+ /// Event arguments class for the event
+ ///
+ public sealed class BestBidAskUpdatedEventArgs : EventArgs
+ {
+ ///
+ /// Gets the new best bid price
+ ///
+ public Symbol Symbol { get; }
+
+ ///
+ /// Gets the new best bid price
+ ///
+ public decimal BestBidPrice { get; }
+
+ ///
+ /// Gets the new best bid size
+ ///
+ public decimal BestBidSize { get; }
+
+ ///
+ /// Gets the new best ask price
+ ///
+ public decimal BestAskPrice { get; }
+
+ ///
+ /// Gets the new best ask size
+ ///
+ public decimal BestAskSize { get; }
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ /// The symbol
+ /// The newly updated best bid price
+ /// >The newly updated best bid size
+ /// The newly updated best ask price
+ /// The newly updated best ask size
+ public BestBidAskUpdatedEventArgs(Symbol symbol, decimal bestBidPrice, decimal bestBidSize, decimal bestAskPrice, decimal bestAskSize)
+ {
+ Symbol = symbol;
+ BestBidPrice = bestBidPrice;
+ BestBidSize = bestBidSize;
+ BestAskPrice = bestAskPrice;
+ BestAskSize = bestAskSize;
+ }
+ }
+}
diff --git a/Brokerages/Bitfinex/BitfinexBrokerage.Messaging.cs b/Brokerages/Bitfinex/BitfinexBrokerage.Messaging.cs
index 2ce156ac010c..c731bca27510 100644
--- a/Brokerages/Bitfinex/BitfinexBrokerage.Messaging.cs
+++ b/Brokerages/Bitfinex/BitfinexBrokerage.Messaging.cs
@@ -14,7 +14,9 @@
*/
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -30,6 +32,10 @@ public partial class BitfinexBrokerage : BaseWebsocketsBrokerage, IDataQueueHand
///
/// Wss message handler
///
+ ///
+ #region Declarations
+ private readonly ConcurrentDictionary _orderBooks = new ConcurrentDictionary();
+ #endregion
///
///
protected override void OnMessageImpl(object sender, WebSocketMessage e)
@@ -49,6 +55,23 @@ protected override void OnMessageImpl(object sender, WebSocketMessage e)
_lastHeartbeatUtcTime = DateTime.UtcNow;
return;
}
+ else if (ChannelList.ContainsKey(id) && ChannelList[id].Name == "book")
+ {
+ if (raw[1].Type == JTokenType.Array)
+ {
+ //order book snapshot
+ var data = raw[1].ToObject(typeof(string[][]));
+ PopulateOrderBook(data, ChannelList[id].Symbol);
+ return;
+ }
+ else
+ {
+ //order book update
+ var data = raw.ToObject(typeof(string[]));
+ L2Update(data, ChannelList[id].Symbol);
+ }
+
+ }
else if (ChannelList.ContainsKey(id) && ChannelList[id].Name == "ticker")
{
//ticker
@@ -72,6 +95,39 @@ protected override void OnMessageImpl(object sender, WebSocketMessage e)
PopulateTrade(term, data);
return;
}
+ else if (id == "0" && (term == "on" || term == "ou" || term == "oc"))
+ {
+ //order updates
+ Log.Trace("BitfinexBrokerage.OnMessage(): Order update");
+ var data = raw[2].ToObject(typeof(string[]));
+ UpdateOrder(term, data);
+ return;
+
+ }
+ else if (id == "0" && term == "os")
+ {
+ //order snapshot
+ Log.Trace("BitfinexBrokerage.OnMessage(): Order Snapshot");
+ var data = raw[2].ToObject(typeof(string[][]));
+ PopulateOrder(data);
+
+ }
+ else if (id == "0" && (term == "pn" || term == "pu" || term == "pc"))
+ {
+ //position updates
+ Log.Trace("BitfinexBrokerage.OnMessage(): Order update");
+ var data = raw[2].ToObject(typeof(string[]));
+ return;
+
+ }
+ else if (id == "0" && term == "ps")
+ {
+ //position snapshot
+ Log.Trace("BitfinexBrokerage.OnMessage(): Position Snapshot");
+ //var data = raw[2].ToObject(typeof(string[][]));
+ return;
+
+ }
else if (term == "ws")
{
//wallet
@@ -84,7 +140,7 @@ protected override void OnMessageImpl(object sender, WebSocketMessage e)
return;
}
}
- else if ((raw.channel == "ticker" || raw.channel == "trades") && raw.@event == "subscribed")
+ else if ((raw.channel == "ticker" || raw.channel == "trades" || raw.channel == "book") && raw.@event == "subscribed")
{
var channel = (string)raw.channel;
var currentChannelId = (string)raw.chanId;
@@ -119,7 +175,7 @@ protected override void OnMessageImpl(object sender, WebSocketMessage e)
return;
}
- Log.Trace("BitfinexBrokerage.OnMessage(): " + e.Message);
+ //Log.Trace("BitfinexBrokerage.OnMessage(): " + e.Message);
}
catch (Exception ex)
{
@@ -128,6 +184,95 @@ protected override void OnMessageImpl(object sender, WebSocketMessage e)
}
}
+ private void PopulateOrderBook(string[][] data, string symbol)
+ {
+ OrderBook orderBook;
+ if (!_orderBooks.TryGetValue(symbol, out orderBook))
+ {
+ orderBook = new OrderBook(symbol);
+ _orderBooks[symbol] = orderBook;
+ }
+ else
+ {
+ orderBook.BestBidAskUpdated -= OnBestBidAskUpdated;
+ orderBook.Clear();
+ }
+
+ foreach (var item in data)
+ {
+ var msg = new Messages.OrderBook(item);
+ // Positive values -> bid
+ if (msg.Price > 0)
+ {
+ orderBook.UpdateAskRow(msg.Price, msg.Amount);
+ }
+ // negative values -> ask.
+ else if (msg.Price < 0)
+ {
+ orderBook.UpdateBidRow(msg.Price, msg.Amount);
+ }
+
+ orderBook.BestBidAskUpdated += OnBestBidAskUpdated;
+ }
+ return;
+ }
+
+ private void OnBestBidAskUpdated(object sender, BestBidAskUpdatedEventArgs e)
+ {
+ EmitQuoteTick(e.Symbol, e.BestBidPrice, e.BestBidSize, e.BestAskPrice, e.BestAskSize);
+ }
+
+ private void L2Update(string[] data, string symbol)
+ {
+ var orderBook = _orderBooks[symbol];
+
+ var msg = new Messages.L2Update(data);
+
+ // Positive values -> bid
+ if (msg.Price > 0)
+ {
+ if (msg.Count == 0)
+ {
+ orderBook.RemoveAskRow(msg.Price);
+ }
+ else
+ {
+ orderBook.UpdateAskRow(msg.Price, msg.Amount);
+ }
+ }
+ // negative values -> ask.
+ else if (msg.Price < 0)
+ {
+ if (msg.Count == 0)
+ {
+ orderBook.RemoveBidRow(msg.Price);
+ }
+ else
+ {
+ orderBook.UpdateBidRow(msg.Price, msg.Amount);
+ }
+ }
+ return;
+ }
+
+ private void EmitQuoteTick(Symbol symbol, decimal bidPrice, decimal bidSize, decimal askPrice, decimal askSize)
+ {
+ lock (Ticks)
+ {
+ Ticks.Add(new Tick
+ {
+ AskPrice = askPrice,
+ BidPrice = bidPrice,
+ Value = (askPrice + bidPrice) / 2m,
+ Time = DateTime.UtcNow,
+ Symbol = symbol,
+ TickType = TickType.Quote,
+ AskSize = askSize,
+ BidSize = bidSize
+ });
+ }
+ }
+
private void PopulateTicker(string response, string symbol)
{
var data = JsonConvert.DeserializeObject(response, settings);
@@ -168,6 +313,51 @@ private void PopulateTradeTicker(string response, string symbol)
}
}
+ private void UpdateOrder(string term, string[] data)
+ {
+ var msg = new Messages.OrderUpdate(data);
+ OrderDirection direction = msg.OrderAmount < 0 ? OrderDirection.Sell : OrderDirection.Buy;
+ Symbol symbol = Symbol.Create(msg.OrderPair.ToUpper(), SecurityType.Crypto, BrokerageMarket);
+
+ Log.Trace(msg.ToString());
+ // order new
+ if (term == "on")
+ {
+ // var orderEvent = new OrderEvent
+ //(
+ // orderId, symbol, DateTime.UtcNow, OrderStatus.New,
+ // direction, msg.OrderPrice, msg.OrderAmount, 0, "Bitfinex New Order Event"
+ //);
+ // OnOrderEvent(orderEvent);
+ return;
+ }
+ // todo - order update
+ else if (term == "ou")
+ {
+ return;
+ }
+ // order cancel
+ else if (term == "oc")
+ {
+ // var orderEvent = new OrderEvent
+ //(
+ // orderId, symbol, DateTime.UtcNow, OrderStatus.Canceled,
+ // direction, msg.OrderPrice, msg.OrderAmount, 0, "Bitfinex Cancel Order Event"
+ //);
+ //OnOrderEvent(orderEvent);
+ return;
+ }
+ }
+
+ private void PopulateOrder(string[][] data)
+ {
+ foreach (var item in data)
+ {
+ var msg = new Messages.OrderUpdate(item);
+ Log.Trace(msg.ToString());
+ }
+ }
+
private void PopulateWallet(string[][] data)
{
foreach (var item in data)
@@ -303,6 +493,16 @@ public void Subscribe(Packets.LiveNodePacket job, IEnumerable symbols)
pair = item.Value
}));
+ WebSocket.Send(JsonConvert.SerializeObject(new
+ {
+ @event = "subscribe",
+ channel = "book",
+ pair = item.Value,
+ prec = "P0", // default P0
+ freq = "F0", // default F0
+ length = "5" // default 25
+ }));
+
Log.Trace("BitfinexBrokerage.Subscribe(): Sent subcribe for " + item.Value);
}
}
diff --git a/Brokerages/Bitfinex/Messages/L2Update.cs b/Brokerages/Bitfinex/Messages/L2Update.cs
new file mode 100644
index 000000000000..57b999a404fe
--- /dev/null
+++ b/Brokerages/Bitfinex/Messages/L2Update.cs
@@ -0,0 +1,61 @@
+/*
+ * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
+ * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+namespace QuantConnect.Brokerages.Bitfinex.Messages
+{
+ ///
+ /// Ticker message object
+ ///
+ public class L2Update : BaseMessage
+ {
+ private const int _channelId = 0;
+ private const int _price = 1;
+ private const int _count = 2;
+ private const int _amount = 3;
+
+ ///
+ /// L2Update Message constructor
+ ///
+ ///
+ public L2Update(string[] values)
+ : base(values)
+ {
+ ChannelId = GetInt(_channelId);
+ Price = TryGetDecimal(_price);
+ Count = GetInt(_count);
+ Amount = TryGetDecimal(_amount);
+ }
+
+ ///
+ /// Channel Id
+ ///
+ public int ChannelId { get; set; }
+
+ ///
+ /// Price
+ ///
+ public decimal Price { get; set; }
+
+ ///
+ /// Count
+ ///
+ public decimal Count { get; set; }
+
+ ///
+ /// Amount
+ ///
+ public decimal Amount { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Brokerages/Bitfinex/Messages/OrderBook.cs b/Brokerages/Bitfinex/Messages/OrderBook.cs
new file mode 100644
index 000000000000..9110a5ce5389
--- /dev/null
+++ b/Brokerages/Bitfinex/Messages/OrderBook.cs
@@ -0,0 +1,54 @@
+/*
+ * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
+ * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+namespace QuantConnect.Brokerages.Bitfinex.Messages
+{
+ ///
+ /// Ticker message object
+ ///
+ public class OrderBook : BaseMessage
+ {
+ private const int _price = 0;
+ private const int _count = 1;
+ private const int _amount = 2;
+
+ ///
+ /// Ticker Message constructor
+ ///
+ ///
+ public OrderBook(string[] values)
+ : base(values)
+ {
+ Price = TryGetDecimal(_price);
+ Count = GetInt(_count);
+ Amount = TryGetDecimal(_amount);
+ }
+
+ ///
+ /// Price
+ ///
+ public decimal Price { get; set; }
+
+ ///
+ /// Count
+ ///
+ public decimal Count { get; set; }
+
+ ///
+ /// Amount
+ ///
+ public decimal Amount { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Brokerages/Bitfinex/Messages/OrderUpdate.cs b/Brokerages/Bitfinex/Messages/OrderUpdate.cs
new file mode 100644
index 000000000000..86915e3f6e20
--- /dev/null
+++ b/Brokerages/Bitfinex/Messages/OrderUpdate.cs
@@ -0,0 +1,98 @@
+/*
+ * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
+ * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+using System;
+
+namespace QuantConnect.Brokerages.Bitfinex.Messages
+{
+ ///
+ /// Ticker message object
+ ///
+ public class OrderUpdate : BaseMessage
+ {
+ private const int _id = 0;
+ private const int _pair = 1;
+ private const int _amount = 2;
+ private const int _amount_orig = 3;
+ private const int _type = 4;
+ private const int _status = 5;
+ private const int _price = 6;
+ private const int _price_avg = 7;
+ private const int _created_at = 8;
+ private const int _notify = 9;
+ private const int _hidden = 10;
+ private const int _oco = 11;
+
+ ///
+ /// L2Update Message constructor
+ ///
+ ///
+ public OrderUpdate(string[] values)
+ : base(values)
+ {
+ OrderId = GetLong(_id);
+ OrderPair = GetString(_pair);
+ OrderAmount = TryGetDecimal(_id);
+ //OrderAmountOrig =
+ OrderType = GetString(_type);
+ OrderStatus = GetString(_status);
+ OrderPrice = TryGetDecimal(_price);
+ OrderPriceAvg = TryGetDecimal(_price_avg);
+ OrderCreatedAt = GetString(_created_at);
+ //OrderNotify = GetString(_notify);
+ //OrderHidden = GetInt(_hidden);
+ //OrderOco = GetInt(_oco);
+ }
+
+ ///
+ /// Order Id
+ ///
+ public long OrderId { get; set; }
+
+ ///
+ /// Order Pair
+ ///
+ public string OrderPair { get; set; }
+
+ ///
+ /// Order Amount
+ ///
+ public decimal OrderAmount { get; set; }
+
+ ///
+ /// Order Type
+ ///
+ public string OrderType { get; set; }
+
+ ///
+ /// Order Status
+ ///
+ public string OrderStatus { get; set; }
+
+ ///
+ /// Order Price
+ ///
+ public decimal OrderPrice { get; set; }
+
+ ///
+ /// Order Price Avg
+ ///
+ public decimal OrderPriceAvg { get; set; }
+
+ ///
+ /// Order Created At
+ ///
+ public string OrderCreatedAt { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Brokerages/Bitfinex/OrderBook.cs b/Brokerages/Bitfinex/OrderBook.cs
new file mode 100644
index 000000000000..e90cea94e493
--- /dev/null
+++ b/Brokerages/Bitfinex/OrderBook.cs
@@ -0,0 +1,173 @@
+/*
+ * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
+ * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace QuantConnect.Brokerages.Bitfinex
+{
+ ///
+ /// Represents a full order book for a security.
+ /// It contains prices and order sizes for each bid and ask level.
+ /// The best bid and ask prices are also kept up to date.
+ ///
+ public class OrderBook
+ {
+ private readonly object _locker = new object();
+ private readonly Symbol _symbol;
+ private readonly SortedDictionary _bids = new SortedDictionary();
+ private readonly SortedDictionary _asks = new SortedDictionary();
+
+ ///
+ /// Event fired each time or are changed
+ ///
+ public event EventHandler BestBidAskUpdated;
+
+ ///
+ /// The best bid price
+ ///
+ public decimal BestBidPrice { get; private set; }
+
+ ///
+ /// The best bid size
+ ///
+ public decimal BestBidSize { get; private set; }
+
+ ///
+ /// The best ask price
+ ///
+ public decimal BestAskPrice { get; private set; }
+
+ ///
+ /// The best ask size
+ ///
+ public decimal BestAskSize { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ /// The symbol for the order book
+ public OrderBook(Symbol symbol)
+ {
+ _symbol = symbol;
+ }
+
+ ///
+ /// Clears all bid/ask levels and prices.
+ ///
+ public void Clear()
+ {
+ lock (_locker)
+ {
+ _bids.Clear();
+ _asks.Clear();
+ }
+
+ BestBidPrice = 0;
+ BestBidSize = 0;
+ BestAskPrice = 0;
+ BestAskSize = 0;
+ }
+
+ ///
+ /// Updates or inserts a bid price level in the order book
+ ///
+ /// The bid price level to be inserted or updated
+ /// The new size at the bid price level
+ public void UpdateBidRow(decimal price, decimal size)
+ {
+ lock(_locker)
+ {
+ _bids[price] = size;
+ }
+
+ if (BestBidPrice == 0 || price >= BestBidPrice)
+ {
+ BestBidPrice = price;
+ BestBidSize = size;
+
+ BestBidAskUpdated?.Invoke(this, new BestBidAskUpdatedEventArgs(_symbol, BestBidPrice, BestBidSize, BestAskPrice, BestAskSize));
+ }
+ }
+
+ ///
+ /// Updates or inserts an ask price level in the order book
+ ///
+ /// The ask price level to be inserted or updated
+ /// The new size at the ask price level
+ public void UpdateAskRow(decimal price, decimal size)
+ {
+ lock(_locker)
+ {
+ _asks[price] = size;
+ }
+
+ if (BestAskPrice == 0 || price <= BestAskPrice)
+ {
+ BestAskPrice = price;
+ BestAskSize = size;
+
+ BestBidAskUpdated?.Invoke(this, new BestBidAskUpdatedEventArgs(_symbol, BestBidPrice, BestBidSize, BestAskPrice, BestAskSize));
+ }
+ }
+
+ ///
+ /// Removes a bid price level from the order book
+ ///
+ /// The bid price level to be removed
+ public void RemoveBidRow(decimal price)
+ {
+ lock(_locker)
+ {
+ _bids.Remove(price);
+ }
+
+ if (price == BestBidPrice)
+ {
+ lock(_locker)
+ {
+ BestBidPrice = _bids.Keys.LastOrDefault();
+ BestBidSize = BestBidPrice > 0 ? _bids[BestBidPrice] : 0;
+ }
+
+ BestBidAskUpdated?.Invoke(this, new BestBidAskUpdatedEventArgs(_symbol, BestBidPrice, BestBidSize, BestAskPrice, BestAskSize));
+ }
+ }
+
+ ///
+ /// Removes an ask price level from the order book
+ ///
+ /// The ask price level to be removed
+ public void RemoveAskRow(decimal price)
+ {
+ lock(_locker)
+ {
+ _asks.Remove(price);
+ }
+
+ if (price == BestAskPrice)
+ {
+ lock(_locker)
+ {
+ BestAskPrice = _asks.Keys.FirstOrDefault();
+ BestAskSize = BestAskPrice > 0 ? _asks[BestAskPrice] : 0;
+ }
+
+ BestBidAskUpdated?.Invoke(this, new BestBidAskUpdatedEventArgs(_symbol, BestBidPrice, BestBidSize, BestAskPrice, BestAskSize));
+ }
+ }
+ }
+}
diff --git a/Brokerages/QuantConnect.Brokerages.csproj b/Brokerages/QuantConnect.Brokerages.csproj
index 85183df8a3ef..29a2bce1d7c9 100644
--- a/Brokerages/QuantConnect.Brokerages.csproj
+++ b/Brokerages/QuantConnect.Brokerages.csproj
@@ -171,12 +171,16 @@
+
+
+
+
diff --git a/Tests/Brokerages/Bitfinex/BitfinexBrokerageIntegrationTests.cs b/Tests/Brokerages/Bitfinex/BitfinexBrokerageIntegrationTests.cs
index c9b7d8fa8369..1539c8a5a348 100644
--- a/Tests/Brokerages/Bitfinex/BitfinexBrokerageIntegrationTests.cs
+++ b/Tests/Brokerages/Bitfinex/BitfinexBrokerageIntegrationTests.cs
@@ -23,7 +23,7 @@ public class BitfinexBrokerageIntegrationTests : BitfinexBrokerageIntegrationTes
{
#region Properties
- protected override Symbol Symbol => Symbol.Create("BTCUSD", SecurityType.Forex, Market.Bitfinex);
+ protected override Symbol Symbol => Symbol.Create("BTCUSD", SecurityType.Crypto, Market.Bitfinex);
///
/// Gets a high price for the specified symbol so a limit sell won't fill
diff --git a/Tests/Brokerages/Bitfinex/BitfinexBrokerageIntegrationTestsBase.cs b/Tests/Brokerages/Bitfinex/BitfinexBrokerageIntegrationTestsBase.cs
index ab79c00eb9cd..756cd7bc2eed 100644
--- a/Tests/Brokerages/Bitfinex/BitfinexBrokerageIntegrationTestsBase.cs
+++ b/Tests/Brokerages/Bitfinex/BitfinexBrokerageIntegrationTestsBase.cs
@@ -57,13 +57,13 @@ protected override decimal GetDefaultQuantity()
protected override IBrokerage CreateBrokerage(IOrderProvider orderProvider, ISecurityProvider securityProvider)
{
- var restClient = new RestClient("https://api.gdax.com");
+ var restClient = new RestClient("https://api.bitfinex.com");
var webSocketClient = new WebSocketWrapper();
var algorithm = new Mock();
algorithm.Setup(a => a.BrokerageModel).Returns(new BitfinexBrokerageModel(AccountType.Cash));
- return new BitfinexBrokerage(Config.Get("gdax-url", "wss://ws-feed.gdax.com"), webSocketClient, restClient, Config.Get("bitfinex-api-key"), Config.Get("bitfinex-api-secret"),
+ return new BitfinexBrokerage(Config.Get("bitfinex-wss", "wss://api2.bitfinex.com:3000/ws"), webSocketClient, restClient, Config.Get("bitfinex-api-key"), Config.Get("bitfinex-api-secret"),
algorithm.Object);
}
diff --git a/Tests/Brokerages/Bitfinex/BitfinexBrokerageWebsocketsTests.cs b/Tests/Brokerages/Bitfinex/BitfinexBrokerageWebsocketsTests.cs
index 78c242cf4b63..b358ed96f62f 100644
--- a/Tests/Brokerages/Bitfinex/BitfinexBrokerageWebsocketsTests.cs
+++ b/Tests/Brokerages/Bitfinex/BitfinexBrokerageWebsocketsTests.cs
@@ -367,10 +367,11 @@ public void SubscribeTest()
_unit.Subscribe(new[] { Symbol.Create("BTCUSD", SecurityType.Crypto, Market.Bitfinex), Symbol.Create("UNIVERSE", SecurityType.Crypto, Market.Bitfinex),
Symbol.Create("ETHBTC", SecurityType.Crypto, Market.Bitfinex)});
- Assert.AreEqual(4, actualSymbols.Count);
- Assert.AreEqual(4, actualChannels.Count);
+ Assert.AreEqual(6, actualSymbols.Count);
+ Assert.AreEqual(6, actualChannels.Count);
CollectionAssert.Contains(actualChannels, "ticker");
CollectionAssert.Contains(actualChannels, "trades");
+ CollectionAssert.Contains(actualChannels, "book");
CollectionAssert.Contains(actualSymbols, "BTCUSD");
CollectionAssert.Contains(actualSymbols, "ETHBTC");
}