11using System ;
2+ using System . Collections . Generic ;
23using System . Linq ;
34using Binance . Client . Websocket . Client ;
45using Binance . Client . Websocket . Responses . Orders ;
@@ -16,9 +17,10 @@ namespace Crypto.Websocket.Extensions.Orders.Sources
1617 /// </summary>
1718 public class BinanceOrderSource : OrderSourceBase
1819 {
19- private readonly CryptoOrderCollection _partiallyFilledOrders = new CryptoOrderCollection ( ) ;
20+ private readonly CryptoOrderCollection _partiallyFilledOrders = new ( ) ;
2021 private BinanceWebsocketClient _client = null ! ;
2122 private IDisposable ? _subscription ;
23+ private IDisposable ? _subscriptionFutures ;
2224
2325 /// <inheritdoc />
2426 public BinanceOrderSource ( BinanceWebsocketClient client ) : base ( client . Logger )
@@ -38,12 +40,14 @@ public void ChangeClient(BinanceWebsocketClient client)
3840
3941 _client = client ;
4042 _subscription ? . Dispose ( ) ;
43+ _subscriptionFutures ? . Dispose ( ) ;
4144 Subscribe ( ) ;
4245 }
4346
4447 private void Subscribe ( )
4548 {
4649 _subscription = _client . Streams . OrderUpdateStream . Subscribe ( HandleOrdersSafe ) ;
50+ _subscriptionFutures = _client . Streams . FuturesOrderUpdateStream . Subscribe ( HandleOrdersSafe ) ;
4751 }
4852
4953 private void HandleOrdersSafe ( OrderUpdate response )
@@ -57,12 +61,30 @@ private void HandleOrdersSafe(OrderUpdate response)
5761 _client . Logger . LogError ( e , "[Binance] Failed to handle order info, error: '{error}'" , e . Message ) ;
5862 }
5963 }
64+
65+ private void HandleOrdersSafe ( FuturesOrderUpdate response )
66+ {
67+ try
68+ {
69+ HandleOrders ( response ) ;
70+ }
71+ catch ( Exception e )
72+ {
73+ _client . Logger . LogError ( e , "[Binance] Failed to handle futures order info, error: '{error}'" , e . Message ) ;
74+ }
75+ }
6076
6177 private void HandleOrders ( OrderUpdate response )
6278 {
6379 var order = ConvertOrder ( response ) ;
6480 OrderUpdatedSubject . OnNext ( order ) ;
6581 }
82+
83+ private void HandleOrders ( FuturesOrderUpdate response )
84+ {
85+ var order = ConvertOrder ( response ) ;
86+ OrderUpdatedSubject . OnNext ( order ) ;
87+ }
6688
6789 /// <summary>
6890 /// Convert Binance orders to crypto orders
@@ -80,8 +102,8 @@ public CryptoOrder[] ConvertOrders(OrderUpdate[] orders)
80102 public CryptoOrder ConvertOrder ( OrderUpdate order )
81103 {
82104 var id = order . Id . ToString ( ) ;
83- var existingCurrent = ExistingOrders . ContainsKey ( id ) ? ExistingOrders [ id ] : null ;
84- var existingPartial = _partiallyFilledOrders . ContainsKey ( id ) ? _partiallyFilledOrders [ id ] : null ;
105+ var existingCurrent = ExistingOrders . GetValueOrDefault ( id ) ;
106+ var existingPartial = _partiallyFilledOrders . GetValueOrDefault ( id ) ;
85107 var existing = existingPartial ?? existingCurrent ;
86108
87109 var price = Math . Abs ( FirstNonZero ( order . LastPriceFilled , order . Price , existing ? . Price ) ?? 0 ) ;
@@ -133,6 +155,65 @@ public CryptoOrder ConvertOrder(OrderUpdate order)
133155
134156 return newOrder ;
135157 }
158+
159+ /// <summary>
160+ /// Convert Binance order to crypto order
161+ /// </summary>
162+ public CryptoOrder ConvertOrder ( FuturesOrderUpdate orderUpdate )
163+ {
164+ var order = orderUpdate . Order ;
165+
166+ var id = order . OrderId . ToString ( ) ;
167+ var existingCurrent = ExistingOrders . GetValueOrDefault ( id ) ;
168+ var existingPartial = _partiallyFilledOrders . GetValueOrDefault ( id ) ;
169+ var existing = existingPartial ?? existingCurrent ;
170+
171+ var price = Math . Abs ( FirstNonZero ( order . LastFilledPrice , order . Price , existing ? . Price ) ?? 0 ) ;
172+ var priceAvg = Math . Abs ( FirstNonZero ( order . AveragePrice , order . LastFilledPrice , order . Price , existing ? . PriceAverage ) ?? 0 ) ;
173+
174+ var amountQuote = FirstNonZero ( order . Quantity * order . Price , existing ? . AmountOrigQuote ) ;
175+ var amountFilledQuote = FirstNonZero ( order . LastFilledQuantity * order . LastFilledPrice ) ;
176+ var amountFilledQuoteCumulative = FirstNonZero ( order . AccumulatedFilledQuantity * priceAvg , existing ? . AmountFilledCumulativeQuote ) ;
177+
178+ var currentStatus = ConvertOrderStatus ( order ) ;
179+
180+ var newOrder = new CryptoOrder
181+ {
182+ Id = id ,
183+ GroupId = existing ? . GroupId ?? null ,
184+ ClientId = ! string . IsNullOrWhiteSpace ( order . ClientOrderId ) ?
185+ order . ClientOrderId : existing ? . ClientId ,
186+ Pair = order . Symbol ?? existing ? . Pair ?? string . Empty ,
187+ Side = order . Side == OrderSide . Sell ? CryptoOrderSide . Ask : CryptoOrderSide . Bid ,
188+ AmountFilled = order . LastFilledQuantity ,
189+ AmountFilledCumulative = order . AccumulatedFilledQuantity ,
190+ AmountOrig = FirstNonZero ( order . Quantity , existing ? . AmountOrig ) ,
191+ AmountFilledQuote = amountFilledQuote ,
192+ AmountFilledCumulativeQuote = amountFilledQuoteCumulative ,
193+ AmountOrigQuote = amountQuote ,
194+ Created = order . TradeTime ?? existing ? . Created ,
195+ Updated = orderUpdate . TransactionTime ?? orderUpdate . EventTime ,
196+ Price = price ,
197+ PriceAverage = priceAvg ,
198+ Fee = order . Commission ,
199+ FeeCurrency = order . CommissionAsset ,
200+ OrderStatus = currentStatus ,
201+ OrderStatusRaw = order . Status . ToString ( ) ,
202+ CanceledReason = order . ExecutionType . ToString ( ) ,
203+ Type = ConvertOrderType ( order . Type ) ?? existing ? . Type ?? CryptoOrderType . Undefined ,
204+ TypePrev = existing ? . TypePrev ?? existing ? . Type ?? ConvertOrderType ( order . Type ) ?? CryptoOrderType . Undefined ,
205+ OnMargin = existing ? . OnMargin ?? false
206+ } ;
207+
208+
209+ if ( currentStatus == CryptoOrderStatus . PartiallyFilled )
210+ {
211+ // save partially filled orders
212+ _partiallyFilledOrders [ newOrder . Id ] = newOrder ;
213+ }
214+
215+ return newOrder ;
216+ }
136217
137218
138219 /// <summary>
@@ -178,6 +259,25 @@ public static CryptoOrderStatus ConvertOrderStatus(OrderUpdate order)
178259 return CryptoOrderStatus . Canceled ;
179260 }
180261 }
262+
263+ /// <summary>
264+ /// Convert order status
265+ /// </summary>
266+ public static CryptoOrderStatus ConvertOrderStatus ( FuturesOrderData order )
267+ {
268+ var status = order . Status ;
269+ switch ( status )
270+ {
271+ case OrderStatus . New :
272+ return CryptoOrderStatus . Active ;
273+ case OrderStatus . PartiallyFilled :
274+ return CryptoOrderStatus . PartiallyFilled ;
275+ case OrderStatus . Filled :
276+ return CryptoOrderStatus . Executed ;
277+ default :
278+ return CryptoOrderStatus . Canceled ;
279+ }
280+ }
181281
182282
183283 private static double ? FirstNonZero ( params double ? [ ] numbers )
0 commit comments