Skip to content

Commit af442f4

Browse files
Kukksvslee
authored andcommitted
add ndax ticker websocket (#469)
* add ndax ticker websocket * Cleanup - make Level1Data a nested class - corrected NDAXProduct capitalization
1 parent a42e144 commit af442f4

File tree

4 files changed

+134
-51
lines changed

4 files changed

+134
-51
lines changed

ExchangeSharp/API/Exchanges/NDAX/ExchangeNDAXAPI.cs

Lines changed: 46 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ protected override async Task<IEnumerable<string>> OnGetMarketSymbolsAsync()
4747

4848
protected override async Task<IReadOnlyDictionary<string, ExchangeCurrency>> OnGetCurrenciesAsync()
4949
{
50-
var result = await MakeJsonRequestAsync<IEnumerable<NDaxProduct>>("GetProducts", null,
50+
var result = await MakeJsonRequestAsync<IEnumerable<NDAXProduct>>("GetProducts", null,
5151
new Dictionary<string, object>()
5252
{ {"OMSId", 1}}, "POST");
5353
_symbolToProductId = result.ToDictionary(product => product.Product, product => product.ProductId);
@@ -79,7 +79,7 @@ protected override async Task<IEnumerable<ExchangeOrderResult>> OnGetCompletedOr
7979
{
8080
payload.Add("InstrumentId", await GetInstrumentIdFromMarketSymbol(symbol));
8181
}
82-
var result = await MakeJsonRequestAsync<IEnumerable<Order>>("GetOrdersHistory", null,
82+
var result = await MakeJsonRequestAsync<IEnumerable<Order>>("GetOrderHistory", null,
8383
payload, "POST");
8484

8585
return result.Select(order => order.ToExchangeOrderResult(_marketSymbolToInstrumentIdMapping));
@@ -351,62 +351,58 @@ private async Task EnsureInstrumentIdsAvailable()
351351

352352
return null;
353353
}
354-
355-
protected override Task<IWebSocket> OnGetTickersWebSocketAsync(Action<IReadOnlyCollection<KeyValuePair<string, ExchangeTicker>>> tickers, params string[] marketSymbols)
354+
355+
private async Task<long?[]> GetInstrumentIdFromMarketSymbol(string[] marketSymbols)
356356
{
357-
return base.OnGetTickersWebSocketAsync(tickers, marketSymbols);
357+
return await Task.WhenAll(marketSymbols.Select(GetInstrumentIdFromMarketSymbol));
358358
}
359359

360-
internal Task<IWebSocket> SubscribeWebsocketAsync<T>(Action<T> callback, string functionName, object messageFramepayload = null)
360+
private async Task<string> GetMarketSymbolFromInstrumentId(long instrumentId)
361361
{
362-
if (string.IsNullOrWhiteSpace(functionName))
363-
throw new ArgumentNullException(nameof(functionName));
364-
365-
// Wrap all calls in a frame object.
366-
var frame = new MessageFrame
367-
{
368-
FunctionName = functionName,
369-
MessageType = MessageType.SubscribeToEvent,
370-
SequenceNumber = GetNextSequenceNumber(),
371-
Payload = JsonConvert.SerializeObject(messageFramepayload)
372-
};
373-
374-
return ConnectWebSocketAsync("", (socket, bytes) =>
375-
{
376-
var messageFrame = JsonConvert.DeserializeObject<MessageFrame>(bytes.ToStringFromUTF8().TrimEnd('\0'));
377-
callback.Invoke(messageFrame.PayloadAs<T>());
378-
return Task.CompletedTask;
379-
}, async socket => { await socket.SendMessageAsync(frame); });
362+
await EnsureInstrumentIdsAvailable();
363+
var match = _marketSymbolToInstrumentIdMapping.Where(pair => pair.Value == instrumentId);
364+
return match.Any() ? match.First().Key : null;
380365
}
381366

382-
internal async Task<T> QueryWebsocketOneCallAsync<T>(string functionName, object payload = null)
367+
protected override async Task<IWebSocket> OnGetTickersWebSocketAsync(Action<IReadOnlyCollection<KeyValuePair<string, ExchangeTicker>>> tickers, params string[] marketSymbols)
383368
{
384-
if (string.IsNullOrWhiteSpace(functionName))
385-
throw new ArgumentNullException(nameof(functionName));
369+
var instrumentIds = await GetInstrumentIdFromMarketSymbol(marketSymbols);
386370

387-
// Wrap all calls in a frame object.
388-
var frame = new MessageFrame
389-
{
390-
FunctionName = functionName,
391-
MessageType = MessageType.Request,
392-
SequenceNumber = GetNextSequenceNumber(),
393-
Payload = JsonConvert.SerializeObject(payload)
394-
};
395-
396-
var tcs = new TaskCompletionSource<T>();
397-
var handlerFinished = tcs.Task;
398-
using (ConnectWebSocketAsync("", (socket, bytes) =>
399-
{
400-
var messageFrame = JsonConvert.DeserializeObject<MessageFrame>(bytes.ToStringFromUTF8().TrimEnd('\0'));
401-
tcs.SetResult(messageFrame.PayloadAs<T>());
402-
return Task.CompletedTask;
403-
}, async socket =>
404-
{
405-
await socket.SendMessageAsync(frame);
406-
}))
407-
{
408-
return await handlerFinished;
409-
}
371+
return await ConnectWebSocketAsync("", async (socket, bytes) =>
372+
{
373+
var messageFrame =
374+
JsonConvert.DeserializeObject<MessageFrame>(bytes.ToStringFromUTF8().TrimEnd('\0'));
375+
376+
if (messageFrame.FunctionName.Equals("SubscribeLevel1", StringComparison.InvariantCultureIgnoreCase)
377+
|| messageFrame.FunctionName.Equals("Level1UpdateEvent",
378+
StringComparison.InvariantCultureIgnoreCase))
379+
{
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+
},
388+
async socket =>
389+
{
390+
foreach (var instrumentId in instrumentIds)
391+
{
392+
await socket.SendMessageAsync(new MessageFrame
393+
{
394+
FunctionName = "SubscribeLevel1",
395+
MessageType = MessageType.Request,
396+
SequenceNumber = GetNextSequenceNumber(),
397+
Payload = JsonConvert.SerializeObject(new
398+
{
399+
OMSId = 1,
400+
InstrumentId = instrumentId,
401+
402+
})
403+
});
404+
}
405+
});
410406
}
411407

412408
private long GetNextSequenceNumber()
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
using System;
2+
using Newtonsoft.Json;
3+
4+
namespace ExchangeSharp
5+
{
6+
public sealed partial class ExchangeNDAXAPI
7+
{
8+
class Level1Data
9+
{
10+
[JsonProperty("OMSId")]
11+
public long OmsId { get; set; }
12+
13+
[JsonProperty("InstrumentId")]
14+
public long InstrumentId { get; set; }
15+
16+
[JsonProperty("BestBid")]
17+
public long? BestBid { get; set; }
18+
19+
[JsonProperty("BestOffer")]
20+
public long? BestOffer { get; set; }
21+
22+
[JsonProperty("LastTradedPx")]
23+
public double LastTradedPx { get; set; }
24+
25+
[JsonProperty("LastTradedQty")]
26+
public double LastTradedQty { get; set; }
27+
28+
[JsonProperty("LastTradeTime")]
29+
public long? LastTradeTime { get; set; }
30+
31+
[JsonProperty("SessionOpen")]
32+
public long? SessionOpen { get; set; }
33+
34+
[JsonProperty("SessionHigh")]
35+
public long? SessionHigh { get; set; }
36+
37+
[JsonProperty("SessionLow")]
38+
public long? SessionLow { get; set; }
39+
40+
[JsonProperty("SessionClose")]
41+
public double SessionClose { get; set; }
42+
43+
[JsonProperty("Volume")]
44+
public decimal? Volume { get; set; }
45+
46+
[JsonProperty("CurrentDayVolume")]
47+
public long? CurrentDayVolume { get; set; }
48+
49+
[JsonProperty("CurrentDayNumTrades")]
50+
public long? CurrentDayNumTrades { get; set; }
51+
52+
[JsonProperty("CurrentDayPxChange")]
53+
public long? CurrentDayPxChange { get; set; }
54+
55+
[JsonProperty("Rolling24HrVolume")]
56+
public long? Rolling24HrVolume { get; set; }
57+
58+
[JsonProperty("Rolling24NumTrades")]
59+
public long? Rolling24NumTrades { get; set; }
60+
61+
[JsonProperty("Rolling24HrPxChange")]
62+
public long? Rolling24HrPxChange { get; set; }
63+
64+
[JsonProperty("TimeStamp")]
65+
public string TimeStamp { get; set; }
66+
67+
public ExchangeTicker ToExchangeTicker(string currencyPair)
68+
{
69+
var currencyParts = currencyPair.Split(new[] { "_" }, StringSplitOptions.RemoveEmptyEntries);
70+
return new ExchangeTicker()
71+
{
72+
Bid = BestBid.GetValueOrDefault(),
73+
Ask = BestOffer.GetValueOrDefault(),
74+
Id = InstrumentId.ToString(),
75+
Last = LastTradeTime.GetValueOrDefault(),
76+
Volume = new ExchangeVolume()
77+
{
78+
BaseCurrency = currencyParts[0],
79+
QuoteCurrency = currencyParts[1],
80+
BaseCurrencyVolume = Volume.GetValueOrDefault()
81+
}
82+
};
83+
}
84+
}
85+
}
86+
}

ExchangeSharp/API/Exchanges/NDAX/Models/NDAXProduct.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ namespace ExchangeSharp
44
{
55
public sealed partial class ExchangeNDAXAPI
66
{
7-
class NDaxProduct
7+
class NDAXProduct
88
{
99
[JsonProperty("OMSId")]
1010
public long OmsId { get; set; }

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ The following cryptocurrency exchanges are supported:
4040
| Poloniex | x | x | T R B |
4141
| YoBit | x | x | |
4242
| ZB.com | wip | | R |
43+
| NDAX | x | x | T |
4344

4445
The following cryptocurrency services are supported:
4546
- Cryptowatch (partial)

0 commit comments

Comments
 (0)