diff --git a/Bitfinex.Net/Bitfinex.Net.csproj b/Bitfinex.Net/Bitfinex.Net.csproj index c668824..7cbbc28 100644 --- a/Bitfinex.Net/Bitfinex.Net.csproj +++ b/Bitfinex.Net/Bitfinex.Net.csproj @@ -1,4 +1,4 @@ - + netstandard2.0;netstandard2.1 enable @@ -51,10 +51,10 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + all runtime; build; native; contentfiles; analyzers; buildtransitive - \ No newline at end of file diff --git a/Bitfinex.Net/Bitfinex.Net.xml b/Bitfinex.Net/Bitfinex.Net.xml index f452940..02a6924 100644 --- a/Bitfinex.Net/Bitfinex.Net.xml +++ b/Bitfinex.Net/Bitfinex.Net.xml @@ -53,6 +53,36 @@ Urls to the API documentation + + + Format a base and quote asset to a Bitfinex recognized symbol + + Base asset + Quote asset + Trading mode + Delivery time for delivery futures + + + + + + + + ctor + + + + + ctor + + Service provider for resolving logging and clients + + + + + + + @@ -2767,6 +2797,14 @@ Spot order book factory methods + + + Create a SymbolOrderBook for the symbol + + The symbol + Book options + + Create a SymbolOrderBook @@ -2775,6 +2813,30 @@ Book options + + + Tracker factory + + + + + Create a new kline tracker + + The symbol + Kline interval + The max amount of klines to retain + The max period the data should be retained + + + + + Create a new trade tracker for a symbol + + The symbol + The max amount of klines to retain + The max period the data should be retained + + Api addresses usable for the Bitfinex clients @@ -5583,6 +5645,9 @@ + + + diff --git a/Bitfinex.Net/BitfinexExchange.cs b/Bitfinex.Net/BitfinexExchange.cs index 0affa2e..87e2653 100644 --- a/Bitfinex.Net/BitfinexExchange.cs +++ b/Bitfinex.Net/BitfinexExchange.cs @@ -1,4 +1,7 @@ -namespace Bitfinex.Net +using CryptoExchange.Net.SharedApis; +using System; + +namespace Bitfinex.Net { /// /// Bitfinex exchange information and configuration @@ -21,5 +24,24 @@ public static class BitfinexExchange public static string[] ApiDocsUrl { get; } = new[] { "https://docs.bitfinex.com/docs/introduction" }; + + /// + /// Format a base and quote asset to a Bitfinex recognized symbol + /// + /// Base asset + /// Quote asset + /// Trading mode + /// Delivery time for delivery futures + /// + public static string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null) + { + if (baseAsset == "USDT") + baseAsset = "UST"; + + if (quoteAsset == "USDT") + quoteAsset = "UST"; + + return $"t{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}"; + } } } diff --git a/Bitfinex.Net/BitfinexTrackerFactory.cs b/Bitfinex.Net/BitfinexTrackerFactory.cs new file mode 100644 index 0000000..09b915a --- /dev/null +++ b/Bitfinex.Net/BitfinexTrackerFactory.cs @@ -0,0 +1,68 @@ +using Bitfinex.Net.Clients; +using Bitfinex.Net.Interfaces; +using Bitfinex.Net.Interfaces.Clients; +using CryptoExchange.Net.SharedApis; +using CryptoExchange.Net.Trackers.Klines; +using CryptoExchange.Net.Trackers.Trades; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using System; + +namespace Bitfinex.Net +{ + /// + public class BitfinexTrackerFactory : IBitfinexTrackerFactory + { + private readonly IServiceProvider? _serviceProvider; + + /// + /// ctor + /// + public BitfinexTrackerFactory() + { + } + + /// + /// ctor + /// + /// Service provider for resolving logging and clients + public BitfinexTrackerFactory(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + /// + public IKlineTracker CreateKlineTracker(SharedSymbol symbol, SharedKlineInterval interval, int? limit = null, TimeSpan? period = null) + { + var restClient = (_serviceProvider?.GetRequiredService() ?? new BitfinexRestClient()).SpotApi.SharedClient; + var socketClient = (_serviceProvider?.GetRequiredService() ?? new BitfinexSocketClient()).SpotApi.SharedClient; + + return new KlineTracker( + _serviceProvider?.GetRequiredService().CreateLogger(restClient.Exchange), + restClient, + socketClient, + symbol, + interval, + limit, + period + ); + } + + /// + public ITradeTracker CreateTradeTracker(SharedSymbol symbol, int? limit = null, TimeSpan? period = null) + { + var restClient = (_serviceProvider?.GetRequiredService() ?? new BitfinexRestClient()).SpotApi.SharedClient; + var socketClient = (_serviceProvider?.GetRequiredService() ?? new BitfinexSocketClient()).SpotApi.SharedClient; + + return new TradeTracker( + _serviceProvider?.GetRequiredService().CreateLogger(restClient.Exchange), + null, + restClient, + socketClient, + symbol, + limit, + period + ); + } + } +} diff --git a/Bitfinex.Net/Clients/SpotApi/BitfinexRestClientSpotApi.cs b/Bitfinex.Net/Clients/SpotApi/BitfinexRestClientSpotApi.cs index 5aac55e..8f27662 100644 --- a/Bitfinex.Net/Clients/SpotApi/BitfinexRestClientSpotApi.cs +++ b/Bitfinex.Net/Clients/SpotApi/BitfinexRestClientSpotApi.cs @@ -74,15 +74,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden /// public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null) - { - if (baseAsset == "USDT") - baseAsset = "UST"; - - if (quoteAsset == "USDT") - quoteAsset = "UST"; - - return $"t{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}"; - } + => BitfinexExchange.FormatSymbol(baseAsset, quoteAsset, tradingMode, deliverTime); #region common interface diff --git a/Bitfinex.Net/Clients/SpotApi/BitfinexRestClientSpotApiShared.cs b/Bitfinex.Net/Clients/SpotApi/BitfinexRestClientSpotApiShared.cs index 5350d2a..19e5c5d 100644 --- a/Bitfinex.Net/Clients/SpotApi/BitfinexRestClientSpotApiShared.cs +++ b/Bitfinex.Net/Clients/SpotApi/BitfinexRestClientSpotApiShared.cs @@ -265,7 +265,10 @@ async Task>> IRecentTradeRestClient.G if (!result) return result.AsExchangeResult>(Exchange, null, default); - return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Select(x => new SharedTrade(Math.Abs(x.Quantity), x.Price, x.Timestamp)).ToArray()); + return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Select(x => new SharedTrade(Math.Abs(x.Quantity), x.Price, x.Timestamp) + { + Side = x.Quantity > 0 ? SharedOrderSide.Buy : SharedOrderSide.Sell + }).ToArray()); } #endregion @@ -697,7 +700,10 @@ async Task>> ITradeHistoryRestClient. nextToken = new DateTimeToken(result.Data.Min(o => o.Timestamp.AddMilliseconds(-1))); // Return - return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data./*Where(x => x. < request.EndTime).*/Select(x => new SharedTrade(Math.Abs(x.Quantity), x.Price, x.Timestamp)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data./*Where(x => x. < request.EndTime).*/Select(x => new SharedTrade(Math.Abs(x.Quantity), x.Price, x.Timestamp) + { + Side = x.Quantity > 0 ? SharedOrderSide.Buy : SharedOrderSide.Sell + }).ToArray(), nextToken); } #endregion diff --git a/Bitfinex.Net/Clients/SpotApi/BitfinexSocketClientSpotApi.cs b/Bitfinex.Net/Clients/SpotApi/BitfinexSocketClientSpotApi.cs index bcde625..3045372 100644 --- a/Bitfinex.Net/Clients/SpotApi/BitfinexSocketClientSpotApi.cs +++ b/Bitfinex.Net/Clients/SpotApi/BitfinexSocketClientSpotApi.cs @@ -71,15 +71,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden /// public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null) - { - if (baseAsset == "USDT") - baseAsset = "UST"; - - if (quoteAsset == "USDT") - quoteAsset = "UST"; - - return $"t{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}"; - } + => BitfinexExchange.FormatSymbol(baseAsset, quoteAsset, tradingMode, deliverTime); public IBitfinexSocketClientSpotApiShared SharedClient => this; diff --git a/Bitfinex.Net/Clients/SpotApi/BitfinexSocketClientSpotApiShared.cs b/Bitfinex.Net/Clients/SpotApi/BitfinexSocketClientSpotApiShared.cs index f6ebff3..b677875 100644 --- a/Bitfinex.Net/Clients/SpotApi/BitfinexSocketClientSpotApiShared.cs +++ b/Bitfinex.Net/Clients/SpotApi/BitfinexSocketClientSpotApiShared.cs @@ -45,10 +45,13 @@ async Task> ITradeSocketClient.SubscribeToTra var symbol = request.Symbol.GetSymbol(FormatSymbol); var result = await SubscribeToTradeUpdatesAsync(symbol, update => { - if (update.UpdateType == SocketUpdateType.Snapshot) + if (update.UpdateType == SocketUpdateType.Snapshot || update.StreamId!.EndsWith(".tu")) return; - handler(update.AsExchangeEvent>(Exchange, update.Data.Select(x => new SharedTrade(x.QuantityAbs, x.Price, x.Timestamp)).ToArray())); + handler(update.AsExchangeEvent>(Exchange, update.Data.Select(x => new SharedTrade(x.QuantityAbs, x.Price, x.Timestamp) + { + Side = x.Quantity > 0 ? SharedOrderSide.Buy : SharedOrderSide.Sell + }).ToArray())); }, ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); diff --git a/Bitfinex.Net/ExtensionMethods/ServiceCollectionExtensions.cs b/Bitfinex.Net/ExtensionMethods/ServiceCollectionExtensions.cs index 02f5a2c..ba86643 100644 --- a/Bitfinex.Net/ExtensionMethods/ServiceCollectionExtensions.cs +++ b/Bitfinex.Net/ExtensionMethods/ServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ -using Bitfinex.Net.Clients; +using Bitfinex.Net; +using Bitfinex.Net.Clients; using Bitfinex.Net.Interfaces; using Bitfinex.Net.Interfaces.Clients; using Bitfinex.Net.Objects.Options; @@ -57,6 +58,7 @@ public static IServiceCollection AddBitfinex( }); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(x => x.GetRequiredService().SpotApi.CommonSpotClient); diff --git a/Bitfinex.Net/Interfaces/IBitfinexOrderBookFactory.cs b/Bitfinex.Net/Interfaces/IBitfinexOrderBookFactory.cs index 1c5dfd7..6a3f03a 100644 --- a/Bitfinex.Net/Interfaces/IBitfinexOrderBookFactory.cs +++ b/Bitfinex.Net/Interfaces/IBitfinexOrderBookFactory.cs @@ -1,5 +1,6 @@ using Bitfinex.Net.Objects.Options; using CryptoExchange.Net.Interfaces; +using CryptoExchange.Net.SharedApis; using System; namespace Bitfinex.Net.Interfaces @@ -14,6 +15,14 @@ public interface IBitfinexOrderBookFactory /// public IOrderBookFactory Spot { get; } + /// + /// Create a SymbolOrderBook for the symbol + /// + /// The symbol + /// Book options + /// + ISymbolOrderBook Create(SharedSymbol symbol, Action? options = null); + /// /// Create a SymbolOrderBook /// diff --git a/Bitfinex.Net/Interfaces/IBitfinexTrackerFactory.cs b/Bitfinex.Net/Interfaces/IBitfinexTrackerFactory.cs new file mode 100644 index 0000000..a82c0df --- /dev/null +++ b/Bitfinex.Net/Interfaces/IBitfinexTrackerFactory.cs @@ -0,0 +1,34 @@ +using CryptoExchange.Net.SharedApis; +using CryptoExchange.Net.Trackers.Klines; +using CryptoExchange.Net.Trackers.Trades; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bitfinex.Net.Interfaces +{ + /// + /// Tracker factory + /// + public interface IBitfinexTrackerFactory + { + /// + /// Create a new kline tracker + /// + /// The symbol + /// Kline interval + /// The max amount of klines to retain + /// The max period the data should be retained + /// + IKlineTracker CreateKlineTracker(SharedSymbol symbol, SharedKlineInterval interval, int? limit = null, TimeSpan? period = null); + + /// + /// Create a new trade tracker for a symbol + /// + /// The symbol + /// The max amount of klines to retain + /// The max period the data should be retained + /// + ITradeTracker CreateTradeTracker(SharedSymbol symbol, int? limit = null, TimeSpan? period = null); + } +} diff --git a/Bitfinex.Net/Objects/Sockets/Subscriptions/BitfinexSubscription.cs b/Bitfinex.Net/Objects/Sockets/Subscriptions/BitfinexSubscription.cs index fb2fdb0..956fdf5 100644 --- a/Bitfinex.Net/Objects/Sockets/Subscriptions/BitfinexSubscription.cs +++ b/Bitfinex.Net/Objects/Sockets/Subscriptions/BitfinexSubscription.cs @@ -80,12 +80,11 @@ public BitfinexSubscription(ILogger logger, return nodeType == NodeType.Array ? typeof(BitfinexTopicUpdate>) : typeof(BitfinexTopicUpdate); } - // After CryptoExchange.Net update: - //public override void DoHandleReset() - //{ - // _channelId = -1; - // _firstUpdate = true; - //} + public override void DoHandleReset() + { + _channelId = -1; + _firstUpdate = true; + } public override void HandleSubQueryResponse(BitfinexResponse message) { @@ -112,9 +111,9 @@ public override CallResult DoHandleMessage(SocketConnection connection, DataEven else if (message.Data is BitfinexUpdate singleUpdate) _handler?.Invoke(message.As>(new[] { singleUpdate.Data }, _channel, _symbol, _firstUpdate ? SocketUpdateType.Snapshot : SocketUpdateType.Update)); else if (message.Data is BitfinexTopicUpdate> array3Update) - _handler?.Invoke(message.As(array3Update.Data, _channel, _symbol, _firstUpdate ? SocketUpdateType.Snapshot : SocketUpdateType.Update)); + _handler?.Invoke(message.As(array3Update.Data, _channel + "." + array3Update.Topic, _symbol, _firstUpdate ? SocketUpdateType.Snapshot : SocketUpdateType.Update)); else if (message.Data is BitfinexTopicUpdate single3Update) - _handler?.Invoke(message.As>(new[] { single3Update.Data }, _channel, _symbol, _firstUpdate ? SocketUpdateType.Snapshot : SocketUpdateType.Update)); + _handler?.Invoke(message.As>(new[] { single3Update.Data }, _channel + "." + single3Update.Topic, _symbol, _firstUpdate ? SocketUpdateType.Snapshot : SocketUpdateType.Update)); _firstUpdate = false; return new CallResult(null); diff --git a/Bitfinex.Net/SymbolOrderBooks/BitfinexOrderBookFactory.cs b/Bitfinex.Net/SymbolOrderBooks/BitfinexOrderBookFactory.cs index 0d66d47..32973cb 100644 --- a/Bitfinex.Net/SymbolOrderBooks/BitfinexOrderBookFactory.cs +++ b/Bitfinex.Net/SymbolOrderBooks/BitfinexOrderBookFactory.cs @@ -3,6 +3,7 @@ using Bitfinex.Net.Objects.Options; using CryptoExchange.Net.Interfaces; using CryptoExchange.Net.OrderBook; +using CryptoExchange.Net.SharedApis; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; @@ -24,12 +25,21 @@ public BitfinexOrderBookFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; - Spot = new OrderBookFactory((symbol, options) => Create(symbol, options), (baseAsset, quoteAsset, options) => Create($"t{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}", options)); + Spot = new OrderBookFactory( + Create, + (sharedSymbol, options) => Create(BitfinexExchange.FormatSymbol(sharedSymbol.BaseAsset, sharedSymbol.QuoteAsset, sharedSymbol.TradingMode, sharedSymbol.DeliverTime), options)); } /// public IOrderBookFactory Spot { get; } + /// + public ISymbolOrderBook Create(SharedSymbol symbol, Action? options = null) + { + var symbolName = BitfinexExchange.FormatSymbol(symbol.BaseAsset, symbol.QuoteAsset, symbol.TradingMode, symbol.DeliverTime); + return Create(symbolName, options); + } + /// public ISymbolOrderBook Create(string symbol, Action? options = null) => new BitfinexSymbolOrderBook(symbol, diff --git a/Examples/Bitfinex.Examples.Api/Bitfinex.Examples.Api.csproj b/Examples/Bitfinex.Examples.Api/Bitfinex.Examples.Api.csproj index 0433e43..f2dfd78 100644 --- a/Examples/Bitfinex.Examples.Api/Bitfinex.Examples.Api.csproj +++ b/Examples/Bitfinex.Examples.Api/Bitfinex.Examples.Api.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable enable true diff --git a/Examples/Bitfinex.Examples.Console/Bitfinex.Examples.Console.csproj b/Examples/Bitfinex.Examples.Console/Bitfinex.Examples.Console.csproj index d47adf5..7c539dc 100644 --- a/Examples/Bitfinex.Examples.Console/Bitfinex.Examples.Console.csproj +++ b/Examples/Bitfinex.Examples.Console/Bitfinex.Examples.Console.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 enable enable diff --git a/Examples/Bitfinex.Examples.OrderBook/Bitfinex.Examples.OrderBook.csproj b/Examples/Bitfinex.Examples.OrderBook/Bitfinex.Examples.OrderBook.csproj new file mode 100644 index 0000000..ec932ce --- /dev/null +++ b/Examples/Bitfinex.Examples.OrderBook/Bitfinex.Examples.OrderBook.csproj @@ -0,0 +1,18 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + diff --git a/Examples/Bitfinex.Examples.OrderBook/Program.cs b/Examples/Bitfinex.Examples.OrderBook/Program.cs new file mode 100644 index 0000000..4888f97 --- /dev/null +++ b/Examples/Bitfinex.Examples.OrderBook/Program.cs @@ -0,0 +1,52 @@ +using Bitfinex.Net.Interfaces; +using CryptoExchange.Net; +using CryptoExchange.Net.SharedApis; +using Microsoft.Extensions.DependencyInjection; +using Spectre.Console; + +var collection = new ServiceCollection(); +collection.AddBitfinex(); +var provider = collection.BuildServiceProvider(); + +var bookFactory = provider.GetRequiredService(); + +// Create and start the order book +var book = bookFactory.Create(new SharedSymbol(TradingMode.Spot, "ETH", "USDT")); +var result = await book.StartAsync(); +if (!result.Success) +{ + Console.WriteLine(result); + return; +} + +// Create Spectre table +var table = new Table(); +table.ShowRowSeparators = true; +table.AddColumn("Bid Quantity", x => { x.RightAligned(); }) + .AddColumn("Bid Price", x => { x.RightAligned(); }) + .AddColumn("Ask Price", x => { x.LeftAligned(); }) + .AddColumn("Ask Quantity", x => { x.LeftAligned(); }); + +for(var i = 0; i < 10; i++) + table.AddEmptyRow(); + +await AnsiConsole.Live(table) + .StartAsync(async ctx => + { + while (true) + { + var snapshot = book.Book; + for (var i = 0; i < 10; i++) + { + var bid = snapshot.bids.ElementAt(i); + var ask = snapshot.asks.ElementAt(i); + table.UpdateCell(i, 0, ExchangeHelpers.Normalize(bid.Quantity).ToString()); + table.UpdateCell(i, 1, ExchangeHelpers.Normalize(bid.Price).ToString()); + table.UpdateCell(i, 2, ExchangeHelpers.Normalize(ask.Price).ToString()); + table.UpdateCell(i, 3, ExchangeHelpers.Normalize(ask.Quantity).ToString()); + } + + ctx.Refresh(); + await Task.Delay(500); + } + }); diff --git a/Examples/Bitfinex.Examples.Tracker/Bitfinex.Examples.Tracker.csproj b/Examples/Bitfinex.Examples.Tracker/Bitfinex.Examples.Tracker.csproj new file mode 100644 index 0000000..ec932ce --- /dev/null +++ b/Examples/Bitfinex.Examples.Tracker/Bitfinex.Examples.Tracker.csproj @@ -0,0 +1,18 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + diff --git a/Examples/Bitfinex.Examples.Tracker/Program.cs b/Examples/Bitfinex.Examples.Tracker/Program.cs new file mode 100644 index 0000000..10e057a --- /dev/null +++ b/Examples/Bitfinex.Examples.Tracker/Program.cs @@ -0,0 +1,104 @@ +using Bitfinex.Net.Interfaces; +using CryptoExchange.Net.SharedApis; +using Microsoft.Extensions.DependencyInjection; +using Spectre.Console; +using System.Globalization; + +var collection = new ServiceCollection(); +collection.AddBitfinex(); +var provider = collection.BuildServiceProvider(); + +var trackerFactory = provider.GetRequiredService(); + +// Create and start the tracker, keep track of the last 10 minutes +var tracker = trackerFactory.CreateTradeTracker(new SharedSymbol(TradingMode.Spot, "ETH", "USDT"), period: TimeSpan.FromMinutes(10)); +var result = await tracker.StartAsync(); +if (!result.Success) +{ + Console.WriteLine(result); + return; +} + +// Create Spectre table +var table = new Table(); +table.ShowRowSeparators = true; +table.AddColumn("5 Min Data").AddColumn("-5 Min", x => { x.RightAligned(); }) + .AddColumn("Now", x => { x.RightAligned(); }) + .AddColumn("Dif", x => { x.RightAligned(); }); + +table.AddRow("Count", "", "", ""); +table.AddRow("Average price", "", "", ""); +table.AddRow("Average weighted price", "", "", ""); +table.AddRow("Buy/Sell Ratio", "", "", ""); +table.AddRow("Volume", "", "", ""); +table.AddRow("Value", "", "", ""); +table.AddRow("Complete", "", "", ""); +table.AddRow("", "", "", ""); +table.AddRow("Status", "", "", ""); +table.AddRow("Synced From", "", "", ""); + +// Set default culture for currency display +CultureInfo ci = new CultureInfo("en-US"); +Thread.CurrentThread.CurrentCulture = ci; +Thread.CurrentThread.CurrentUICulture = ci; + +await AnsiConsole.Live(table) + .StartAsync(async ctx => + { + while (true) + { + // Get the stats from 10 minutes until 5 minutes ago + var secondLastMinute = tracker.GetStats(DateTime.UtcNow.AddMinutes(-10), DateTime.UtcNow.AddMinutes(-5)); + + // Get the stats from 5 minutes ago until now + var lastMinute = tracker.GetStats(DateTime.UtcNow.AddMinutes(-5)); + + // Get the differences between them + var compare = secondLastMinute.CompareTo(lastMinute); + + // Update the columns + UpdateDec(0, 1, secondLastMinute.TradeCount); + UpdateDec(0, 2, lastMinute.TradeCount); + UpdateStr(0, 3, $"[{(compare.TradeCountDif.Difference < 0 ? "red" : "green")}]{compare.TradeCountDif.Difference} / {compare.TradeCountDif.PercentageDifference}%[/]"); + + UpdateStr(1, 1, secondLastMinute.AveragePrice?.ToString("C")); + UpdateStr(1, 2, lastMinute.AveragePrice?.ToString("C")); + UpdateStr(1, 3, $"[{(compare.AveragePriceDif?.Difference < 0 ? "red" : "green")}]{compare.AveragePriceDif?.Difference?.ToString("C")} / {compare.AveragePriceDif?.PercentageDifference}%[/]"); + + UpdateStr(2, 1, secondLastMinute.VolumeWeightedAveragePrice?.ToString("C")); + UpdateStr(2, 2, lastMinute.VolumeWeightedAveragePrice?.ToString("C")); + UpdateStr(2, 3, $"[{(compare.VolumeWeightedAveragePriceDif?.Difference < 0 ? "red" : "green")}]{compare.VolumeWeightedAveragePriceDif?.Difference?.ToString("C")} / {compare.VolumeWeightedAveragePriceDif?.PercentageDifference}%[/]"); + + UpdateDec(3, 1, secondLastMinute.BuySellRatio); + UpdateDec(3, 2, lastMinute.BuySellRatio); + UpdateStr(3, 3, $"[{(compare.BuySellRatioDif?.Difference < 0 ? "red" : "green")}]{compare.BuySellRatioDif?.Difference} / {compare.BuySellRatioDif?.PercentageDifference}%[/]"); + + UpdateDec(4, 1, secondLastMinute.Volume); + UpdateDec(4, 2, lastMinute.Volume); + UpdateStr(4, 3, $"[{(compare.VolumeDif.Difference < 0 ? "red" : "green")}]{compare.VolumeDif.Difference} / {compare.VolumeDif.PercentageDifference}%[/]"); + + UpdateStr(5, 1, secondLastMinute.QuoteVolume.ToString("C")); + UpdateStr(5, 2, lastMinute.QuoteVolume.ToString("C")); + UpdateStr(5, 3, $"[{(compare.QuoteVolumeDif.Difference < 0 ? "red" : "green")}]{compare.QuoteVolumeDif.Difference?.ToString("C")} / {compare.QuoteVolumeDif.PercentageDifference}%[/]"); + + UpdateStr(6, 1, secondLastMinute.Complete.ToString()); + UpdateStr(6, 2, lastMinute.Complete.ToString()); + + UpdateStr(8, 1, tracker.Status.ToString()); + UpdateStr(9, 1, tracker.SyncedFrom?.ToString()); + + ctx.Refresh(); + await Task.Delay(500); + } + }); + + +void UpdateDec(int row, int col, decimal? val) +{ + table.UpdateCell(row, col, val?.ToString() ?? string.Empty); +} + +void UpdateStr(int row, int col, string? val) +{ + table.UpdateCell(row, col, val ?? string.Empty); +} diff --git a/Examples/Examples.sln b/Examples/Examples.sln index c99ffe7..58ff022 100644 --- a/Examples/Examples.sln +++ b/Examples/Examples.sln @@ -7,6 +7,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bitfinex.Examples.Api", "Bi EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bitfinex.Examples.Console", "Bitfinex.Examples.Console\Bitfinex.Examples.Console.csproj", "{FD4F95C8-D9B7-4F81-9245-4CE667DFD421}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bitfinex.Net", "..\Bitfinex.Net\Bitfinex.Net.csproj", "{9D8DC24F-660A-4BD5-B3EC-B5349EC54A74}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bitfinex.Examples.OrderBook", "Bitfinex.Examples.OrderBook\Bitfinex.Examples.OrderBook.csproj", "{23DE7C14-3A34-4464-989D-8E980E9EC677}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bitfinex.Examples.Tracker", "Bitfinex.Examples.Tracker\Bitfinex.Examples.Tracker.csproj", "{5D819C4C-32FE-41B6-B4E4-0C0413A26FFE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +27,18 @@ Global {FD4F95C8-D9B7-4F81-9245-4CE667DFD421}.Debug|Any CPU.Build.0 = Debug|Any CPU {FD4F95C8-D9B7-4F81-9245-4CE667DFD421}.Release|Any CPU.ActiveCfg = Release|Any CPU {FD4F95C8-D9B7-4F81-9245-4CE667DFD421}.Release|Any CPU.Build.0 = Release|Any CPU + {9D8DC24F-660A-4BD5-B3EC-B5349EC54A74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9D8DC24F-660A-4BD5-B3EC-B5349EC54A74}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D8DC24F-660A-4BD5-B3EC-B5349EC54A74}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9D8DC24F-660A-4BD5-B3EC-B5349EC54A74}.Release|Any CPU.Build.0 = Release|Any CPU + {23DE7C14-3A34-4464-989D-8E980E9EC677}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {23DE7C14-3A34-4464-989D-8E980E9EC677}.Debug|Any CPU.Build.0 = Debug|Any CPU + {23DE7C14-3A34-4464-989D-8E980E9EC677}.Release|Any CPU.ActiveCfg = Release|Any CPU + {23DE7C14-3A34-4464-989D-8E980E9EC677}.Release|Any CPU.Build.0 = Release|Any CPU + {5D819C4C-32FE-41B6-B4E4-0C0413A26FFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5D819C4C-32FE-41B6-B4E4-0C0413A26FFE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5D819C4C-32FE-41B6-B4E4-0C0413A26FFE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5D819C4C-32FE-41B6-B4E4-0C0413A26FFE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Examples/README.md b/Examples/README.md index 43ecf8c..a7a05a2 100644 --- a/Examples/README.md +++ b/Examples/README.md @@ -4,4 +4,10 @@ A minimal API showing how to integrate Bitfinex.Net in a web API project ### Bitfinex.Examples.Console -A simple console client demonstrating basic usage \ No newline at end of file +A simple console client demonstrating basic usage + +### Bitfinex.Examples.OrderBook +Example of using the client side order book implementation + +### Bitfinex.Examples.Tracker +Example of using the trade tracker \ No newline at end of file