Skip to content

Commit

Permalink
Trackers (#168)
Browse files Browse the repository at this point in the history
Updated examples
Updated CryptoExchange.Net to v8.1.0
Moved FormatSymbol to BitfinexExchange class
Added support Side setting on SharedTrade model
Added BitfinexTrackerFactory
Added overload to Create method on BitfinexOrderBookFactory support SharedSymbol parameter
Added filtering of TradeUpdate messages in Shared rest trade socket subscription (Trade execution messages are still processed)
  • Loading branch information
JKorf authored Oct 28, 2024
1 parent 131772f commit 09702a0
Show file tree
Hide file tree
Showing 21 changed files with 456 additions and 38 deletions.
4 changes: 2 additions & 2 deletions Bitfinex.Net/Bitfinex.Net.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
<Nullable>enable</Nullable>
Expand Down Expand Up @@ -51,10 +51,10 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="CryptoExchange.Net" Version="8.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="CryptoExchange.Net" Version="8.0.3" />
</ItemGroup>
</Project>
65 changes: 65 additions & 0 deletions Bitfinex.Net/Bitfinex.Net.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 23 additions & 1 deletion Bitfinex.Net/BitfinexExchange.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
namespace Bitfinex.Net
using CryptoExchange.Net.SharedApis;
using System;

namespace Bitfinex.Net
{
/// <summary>
/// Bitfinex exchange information and configuration
Expand All @@ -21,5 +24,24 @@ public static class BitfinexExchange
public static string[] ApiDocsUrl { get; } = new[] {
"https://docs.bitfinex.com/docs/introduction"
};

/// <summary>
/// Format a base and quote asset to a Bitfinex recognized symbol
/// </summary>
/// <param name="baseAsset">Base asset</param>
/// <param name="quoteAsset">Quote asset</param>
/// <param name="tradingMode">Trading mode</param>
/// <param name="deliverTime">Delivery time for delivery futures</param>
/// <returns></returns>
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()}";
}
}
}
68 changes: 68 additions & 0 deletions Bitfinex.Net/BitfinexTrackerFactory.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <inheritdoc />
public class BitfinexTrackerFactory : IBitfinexTrackerFactory
{
private readonly IServiceProvider? _serviceProvider;

/// <summary>
/// ctor
/// </summary>
public BitfinexTrackerFactory()
{
}

/// <summary>
/// ctor
/// </summary>
/// <param name="serviceProvider">Service provider for resolving logging and clients</param>
public BitfinexTrackerFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}

/// <inheritdoc />
public IKlineTracker CreateKlineTracker(SharedSymbol symbol, SharedKlineInterval interval, int? limit = null, TimeSpan? period = null)
{
var restClient = (_serviceProvider?.GetRequiredService<IBitfinexRestClient>() ?? new BitfinexRestClient()).SpotApi.SharedClient;
var socketClient = (_serviceProvider?.GetRequiredService<IBitfinexSocketClient>() ?? new BitfinexSocketClient()).SpotApi.SharedClient;

return new KlineTracker(
_serviceProvider?.GetRequiredService<ILoggerFactory>().CreateLogger(restClient.Exchange),
restClient,
socketClient,
symbol,
interval,
limit,
period
);
}

/// <inheritdoc />
public ITradeTracker CreateTradeTracker(SharedSymbol symbol, int? limit = null, TimeSpan? period = null)
{
var restClient = (_serviceProvider?.GetRequiredService<IBitfinexRestClient>() ?? new BitfinexRestClient()).SpotApi.SharedClient;
var socketClient = (_serviceProvider?.GetRequiredService<IBitfinexSocketClient>() ?? new BitfinexSocketClient()).SpotApi.SharedClient;

return new TradeTracker(
_serviceProvider?.GetRequiredService<ILoggerFactory>().CreateLogger(restClient.Exchange),
null,
restClient,
socketClient,
symbol,
limit,
period
);
}
}
}
10 changes: 1 addition & 9 deletions Bitfinex.Net/Clients/SpotApi/BitfinexRestClientSpotApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden

/// <inheritdoc />
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

Expand Down
10 changes: 8 additions & 2 deletions Bitfinex.Net/Clients/SpotApi/BitfinexRestClientSpotApiShared.cs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,10 @@ async Task<ExchangeWebResult<IEnumerable<SharedTrade>>> IRecentTradeRestClient.G
if (!result)
return result.AsExchangeResult<IEnumerable<SharedTrade>>(Exchange, null, default);

return result.AsExchangeResult<IEnumerable<SharedTrade>>(Exchange, request.Symbol.TradingMode, result.Data.Select(x => new SharedTrade(Math.Abs(x.Quantity), x.Price, x.Timestamp)).ToArray());
return result.AsExchangeResult<IEnumerable<SharedTrade>>(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
Expand Down Expand Up @@ -697,7 +700,10 @@ async Task<ExchangeWebResult<IEnumerable<SharedTrade>>> ITradeHistoryRestClient.
nextToken = new DateTimeToken(result.Data.Min(o => o.Timestamp.AddMilliseconds(-1)));

// Return
return result.AsExchangeResult<IEnumerable<SharedTrade>>(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<IEnumerable<SharedTrade>>(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

Expand Down
10 changes: 1 addition & 9 deletions Bitfinex.Net/Clients/SpotApi/BitfinexSocketClientSpotApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden

/// <inheritdoc />
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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,13 @@ async Task<ExchangeResult<UpdateSubscription>> 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<IEnumerable<SharedTrade>>(Exchange, update.Data.Select(x => new SharedTrade(x.QuantityAbs, x.Price, x.Timestamp)).ToArray()));
handler(update.AsExchangeEvent<IEnumerable<SharedTrade>>(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<UpdateSubscription>(Exchange, result);
Expand Down
4 changes: 3 additions & 1 deletion Bitfinex.Net/ExtensionMethods/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -57,6 +58,7 @@ public static IServiceCollection AddBitfinex(
});

services.AddTransient<IBitfinexOrderBookFactory, BitfinexOrderBookFactory>();
services.AddTransient<IBitfinexTrackerFactory, BitfinexTrackerFactory>();
services.AddTransient<IBitfinexRestClient, BitfinexRestClient>();
services.AddTransient(x => x.GetRequiredService<IBitfinexRestClient>().SpotApi.CommonSpotClient);

Expand Down
9 changes: 9 additions & 0 deletions Bitfinex.Net/Interfaces/IBitfinexOrderBookFactory.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Bitfinex.Net.Objects.Options;
using CryptoExchange.Net.Interfaces;
using CryptoExchange.Net.SharedApis;
using System;

namespace Bitfinex.Net.Interfaces
Expand All @@ -14,6 +15,14 @@ public interface IBitfinexOrderBookFactory
/// </summary>
public IOrderBookFactory<BitfinexOrderBookOptions> Spot { get; }

/// <summary>
/// Create a SymbolOrderBook for the symbol
/// </summary>
/// <param name="symbol">The symbol</param>
/// <param name="options">Book options</param>
/// <returns></returns>
ISymbolOrderBook Create(SharedSymbol symbol, Action<BitfinexOrderBookOptions>? options = null);

/// <summary>
/// Create a SymbolOrderBook
/// </summary>
Expand Down
34 changes: 34 additions & 0 deletions Bitfinex.Net/Interfaces/IBitfinexTrackerFactory.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// Tracker factory
/// </summary>
public interface IBitfinexTrackerFactory
{
/// <summary>
/// Create a new kline tracker
/// </summary>
/// <param name="symbol">The symbol</param>
/// <param name="interval">Kline interval</param>
/// <param name="limit">The max amount of klines to retain</param>
/// <param name="period">The max period the data should be retained</param>
/// <returns></returns>
IKlineTracker CreateKlineTracker(SharedSymbol symbol, SharedKlineInterval interval, int? limit = null, TimeSpan? period = null);

/// <summary>
/// Create a new trade tracker for a symbol
/// </summary>
/// <param name="symbol">The symbol</param>
/// <param name="limit">The max amount of klines to retain</param>
/// <param name="period">The max period the data should be retained</param>
/// <returns></returns>
ITradeTracker CreateTradeTracker(SharedSymbol symbol, int? limit = null, TimeSpan? period = null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,11 @@ public BitfinexSubscription(ILogger logger,
return nodeType == NodeType.Array ? typeof(BitfinexTopicUpdate<IEnumerable<T>>) : typeof(BitfinexTopicUpdate<T>);
}

// 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)
{
Expand All @@ -112,9 +111,9 @@ public override CallResult DoHandleMessage(SocketConnection connection, DataEven
else if (message.Data is BitfinexUpdate<T> singleUpdate)
_handler?.Invoke(message.As<IEnumerable<T>>(new[] { singleUpdate.Data }, _channel, _symbol, _firstUpdate ? SocketUpdateType.Snapshot : SocketUpdateType.Update));
else if (message.Data is BitfinexTopicUpdate<IEnumerable<T>> 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<T> single3Update)
_handler?.Invoke(message.As<IEnumerable<T>>(new[] { single3Update.Data }, _channel, _symbol, _firstUpdate ? SocketUpdateType.Snapshot : SocketUpdateType.Update));
_handler?.Invoke(message.As<IEnumerable<T>>(new[] { single3Update.Data }, _channel + "." + single3Update.Topic, _symbol, _firstUpdate ? SocketUpdateType.Snapshot : SocketUpdateType.Update));

_firstUpdate = false;
return new CallResult(null);
Expand Down
Loading

0 comments on commit 09702a0

Please sign in to comment.