3
3
using System . Linq ;
4
4
using System . Threading ;
5
5
using System . Threading . Tasks ;
6
+ using ExchangeSharp . NDAX ;
6
7
using Newtonsoft . Json ;
7
8
using Newtonsoft . Json . Linq ;
8
9
@@ -11,7 +12,7 @@ namespace ExchangeSharp
11
12
public sealed partial class ExchangeNDAXAPI : ExchangeAPI
12
13
{
13
14
public override string BaseUrl { get ; set ; } = "https://api.ndax.io:8443/AP" ;
14
- public override string BaseUrlWebSocket { get ; set ; } = "wss://apindaxstage.cdnhop.net /WSGateway" ;
15
+ public override string BaseUrlWebSocket { get ; set ; } = "wss://api.ndax.io /WSGateway" ;
15
16
16
17
private AuthenticateResult authenticationDetails = null ;
17
18
public override string Name => ExchangeName . NDAX ;
@@ -366,9 +367,11 @@ private async Task<string> GetMarketSymbolFromInstrumentId(long instrumentId)
366
367
367
368
protected override async Task < IWebSocket > OnGetTickersWebSocketAsync ( Action < IReadOnlyCollection < KeyValuePair < string , ExchangeTicker > > > tickers , params string [ ] marketSymbols )
368
369
{
369
- var instrumentIds = await GetInstrumentIdFromMarketSymbol ( marketSymbols ) ;
370
+ var instrumentIds = marketSymbols == null || marketSymbols . Length == 0 ?
371
+ ( await GetMarketSymbolsMetadataAsync ( ) ) . Select ( s => ( long ? ) long . Parse ( s . AltMarketSymbol ) ) . ToArray ( ) :
372
+ await GetInstrumentIdFromMarketSymbol ( marketSymbols ) ;
370
373
371
- return await ConnectWebSocketAsync ( "" , async ( socket , bytes ) =>
374
+ return await ConnectWebSocketAsync ( "" , async ( socket , bytes ) =>
372
375
{
373
376
var messageFrame =
374
377
JsonConvert . DeserializeObject < MessageFrame > ( bytes . ToStringFromUTF8 ( ) . TrimEnd ( '\0 ' ) ) ;
@@ -377,14 +380,20 @@ protected override async Task<IWebSocket> OnGetTickersWebSocketAsync(Action<IRea
377
380
|| messageFrame . FunctionName . Equals ( "Level1UpdateEvent" ,
378
381
StringComparison . InvariantCultureIgnoreCase ) )
379
382
{
380
- var rawPayload = messageFrame . PayloadAs < Level1Data > ( ) ;
381
- var symbol = await GetMarketSymbolFromInstrumentId ( rawPayload . InstrumentId ) ;
382
- tickers . Invoke ( new [ ]
383
- {
384
- new KeyValuePair < string , ExchangeTicker > ( symbol , rawPayload . ToExchangeTicker ( symbol ) ) ,
385
- } ) ;
386
- }
387
- } ,
383
+ var token = JToken . Parse ( messageFrame . Payload ) ;
384
+ if ( token [ "errormsg" ] == null )
385
+ {
386
+ var rawPayload = messageFrame . PayloadAs < Level1Data > ( ) ;
387
+ var symbol = await GetMarketSymbolFromInstrumentId ( rawPayload . InstrumentId ) ;
388
+ tickers . Invoke ( new [ ]
389
+ {
390
+ new KeyValuePair < string , ExchangeTicker > ( symbol , rawPayload . ToExchangeTicker ( symbol ) ) ,
391
+ } ) ;
392
+ }
393
+ else // "{\"result\":false,\"errormsg\":\"Resource Not Found\",\"errorcode\":104,\"detail\":\"Instrument not Found\"}"
394
+ Logger . Info ( messageFrame . Payload ) ;
395
+ }
396
+ } ,
388
397
async socket =>
389
398
{
390
399
foreach ( var instrumentId in instrumentIds )
@@ -405,7 +414,73 @@ await socket.SendMessageAsync(new MessageFrame
405
414
} ) ;
406
415
}
407
416
408
- private long GetNextSequenceNumber ( )
417
+ protected override async Task < IWebSocket > OnGetTradesWebSocketAsync ( Func < KeyValuePair < string , ExchangeTrade > , Task > callback , params string [ ] marketSymbols )
418
+ {
419
+ var instrumentIds = marketSymbols == null || marketSymbols . Length == 0 ?
420
+ ( await GetMarketSymbolsMetadataAsync ( ) ) . Select ( s => ( long ? ) long . Parse ( s . AltMarketSymbol ) ) . ToArray ( ) :
421
+ await GetInstrumentIdFromMarketSymbol ( marketSymbols ) ;
422
+
423
+ return await ConnectWebSocketAsync ( "" , async ( socket , bytes ) =>
424
+ {
425
+ var messageFrame =
426
+ JsonConvert . DeserializeObject < MessageFrame > ( bytes . ToStringFromUTF8 ( ) . TrimEnd ( '\0 ' ) ) ;
427
+
428
+ if ( messageFrame . FunctionName . Equals ( "SubscribeTrades" , StringComparison . InvariantCultureIgnoreCase )
429
+ || messageFrame . FunctionName . Equals ( "OrderTradeEvent" , StringComparison . InvariantCultureIgnoreCase )
430
+ || messageFrame . FunctionName . Equals ( "TradeDataUpdateEvent" , StringComparison . InvariantCultureIgnoreCase ) )
431
+ {
432
+ if ( messageFrame . Payload != "[]" )
433
+ {
434
+ var token = JToken . Parse ( messageFrame . Payload ) ;
435
+ if ( token . Type == JTokenType . Array )
436
+ { // "[[34838,2,0.4656,10879.5,311801351,311801370,1570134695227,1,0,0,0],[34839,2,0.4674,10881.7,311801352,311801370,1570134695227,1,0,0,0]]"
437
+ var jArray = token as JArray ;
438
+ for ( int i = 0 ; i < jArray . Count ; i ++ )
439
+ {
440
+ var tradesToken = jArray [ i ] ;
441
+ var symbol = await GetMarketSymbolFromInstrumentId ( tradesToken [ 1 ] . ConvertInvariant < long > ( ) ) ;
442
+ var trade = tradesToken . ParseTradeNDAX ( amountKey : 2 , priceKey : 3 ,
443
+ typeKey : 8 , timestampKey : 6 ,
444
+ TimestampType . UnixMilliseconds , idKey : 0 ,
445
+ typeKeyIsBuyValue : "0" ) ;
446
+ if ( messageFrame . FunctionName . Equals ( "SubscribeTrades" , StringComparison . InvariantCultureIgnoreCase ) )
447
+ {
448
+ trade . Flags |= ExchangeTradeFlags . IsFromSnapshot ;
449
+ if ( i == jArray . Count - 1 )
450
+ {
451
+ trade . Flags |= ExchangeTradeFlags . IsLastFromSnapshot ;
452
+ }
453
+ }
454
+ await callback (
455
+ new KeyValuePair < string , ExchangeTrade > ( symbol , trade ) ) ;
456
+ }
457
+ }
458
+ else // "{\"result\":false,\"errormsg\":\"Invalid Request\",\"errorcode\":100,\"detail\":null}"
459
+ Logger . Info ( messageFrame . Payload ) ;
460
+ }
461
+ }
462
+ } ,
463
+ async socket =>
464
+ {
465
+ foreach ( var instrumentId in instrumentIds )
466
+ {
467
+ await socket . SendMessageAsync ( new MessageFrame
468
+ {
469
+ FunctionName = "SubscribeTrades" ,
470
+ MessageType = MessageType . Request ,
471
+ SequenceNumber = GetNextSequenceNumber ( ) ,
472
+ Payload = JsonConvert . SerializeObject ( new
473
+ {
474
+ OMSId = 1 ,
475
+ InstrumentId = instrumentId ,
476
+ IncludeLastCount = 100 ,
477
+ } )
478
+ } ) ;
479
+ }
480
+ } ) ;
481
+ }
482
+
483
+ private long GetNextSequenceNumber ( )
409
484
{
410
485
// Best practice is to carry an even sequence number.
411
486
Interlocked . Add ( ref _sequenceNumber , 2 ) ;
0 commit comments