diff --git a/src/ExchangeSharp/API/Exchanges/Poloniex/ExchangePoloniexAPI.cs b/src/ExchangeSharp/API/Exchanges/Poloniex/ExchangePoloniexAPI.cs index faef1eb1..f61b8be7 100644 --- a/src/ExchangeSharp/API/Exchanges/Poloniex/ExchangePoloniexAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Poloniex/ExchangePoloniexAPI.cs @@ -326,29 +326,31 @@ protected override async Task> OnG protected override async Task> OnGetMarketSymbolsAsync() { - List symbols = new List(); - var tickers = await GetTickersAsync(); - foreach (var kv in tickers) - { - symbols.Add(kv.Key); - } - return symbols; + return (await GetMarketSymbolsMetadataAsync()).Where(x => x.IsActive.Value).Select(x => x.MarketSymbol); } protected internal override async Task> OnGetMarketSymbolsMetadataAsync() { - //https://poloniex.com/public?command=returnOrderBook¤cyPair=all&depth=0 - /* - * "BTC_CLAM": { - "asks": [], - "bids": [], - "isFrozen": "0", - "seq": 37268918 - }, ... + //https://docs.poloniex.com/#returnticker + /* + { + "BTC_BTS": { + "id": 14, + "last": "0.00000090", + "lowestAsk": "0.00000091", + "highestBid": "0.00000089", + "percentChange": "-0.02173913", + "baseVolume": "0.28698296", + "quoteVolume": "328356.84081156", + "isFrozen": "0", + "postOnly": "0", + "high24hr": "0.00000093", + "low24hr": "0.00000087" + },... */ - var markets = new List(); - Dictionary lookup = await MakeJsonRequestAsync>("/public?command=returnOrderBook¤cyPair=all&depth=0"); + var markets = new List(); + Dictionary lookup = await MakeJsonRequestAsync>("/public?command=returnTicker"); // StepSize is 8 decimal places for both price and amount on everything at Polo const decimal StepSize = 0.00000001m; const decimal minTradeSize = 0.0001m; @@ -357,8 +359,9 @@ protected internal override async Task> OnGetMarketS { var market = new ExchangeMarket { MarketSymbol = kvp.Key, IsActive = false }; - string isFrozen = kvp.Value["isFrozen"].ToStringInvariant(); - if (string.Equals(isFrozen, "0")) + string isFrozen = kvp.Value["isFrozen"].ToStringInvariant(); + string postOnly = kvp.Value["postOnly"].ToStringInvariant(); + if (string.Equals(isFrozen, "0") && string.Equals(postOnly, "0")) { market.IsActive = true; } @@ -366,7 +369,8 @@ protected internal override async Task> OnGetMarketS string[] pairs = kvp.Key.Split('_'); if (pairs.Length == 2) { - market.QuoteCurrency = pairs[0]; + market.MarketId = kvp.Value["id"].ToStringLowerInvariant(); + market.QuoteCurrency = pairs[0]; market.BaseCurrency = pairs[1]; market.PriceStepSize = StepSize; market.QuantityStepSize = StepSize; @@ -440,10 +444,19 @@ protected override async Task OnGetTickersWebSocketAsync(Action OnGetTradesWebSocketAsync(Func, Task> callback, params string[] marketSymbols) { - Dictionary> messageIdToSymbol = new Dictionary>(); + Dictionary messageIdToSymbol = new Dictionary(); + Dictionary symbolToMessageId = new Dictionary(); + var symMeta = await GetMarketSymbolsMetadataAsync(); + foreach (var symbol in symMeta) + { + messageIdToSymbol.Add(int.Parse(symbol.MarketId), symbol.MarketSymbol); + symbolToMessageId.Add(symbol.MarketSymbol, int.Parse(symbol.MarketId)); + } return await ConnectPublicWebSocketAsync(string.Empty, async (_socket, msg) => { JToken token = JToken.Parse(msg.ToStringFromUTF8()); + if (token.Type == JTokenType.Object && token["error"] != null) + throw new APIException($"Exchange returned error: {token["error"].ToStringInvariant()}"); int msgId = token[0].ConvertInvariant(); if (msgId == 1010 || token.Count() == 2) // "[7,2]" @@ -459,18 +472,17 @@ protected override async Task OnGetTradesWebSocketAsync(Func(market, 0); + // can also populate messageIdToSymbol from here + continue; } else if (dataType == "t") { - if (messageIdToSymbol.TryGetValue(msgId, out Tuple symbol)) - { // 0 1 2 3 4 5 - // ["t", "", <1 for buy 0 for sell>, "", "", ] - ExchangeTrade trade = data.ParseTrade(amountKey: 4, priceKey: 3, typeKey: 2, timestampKey: 5, - timestampType: TimestampType.UnixSeconds, idKey: 1, typeKeyIsBuyValue: "1"); - await callback(new KeyValuePair(symbol.Item1, trade)); + if (messageIdToSymbol.TryGetValue(msgId, out string symbol)) + { // 0 1 2 3 4 5 6 + // ["t", "", <1 for buy 0 for sell>, "", "", , ""] + ExchangeTrade trade = data.ParseTrade(amountKey: 4, priceKey: 3, typeKey: 2, timestampKey: 6, + timestampType: TimestampType.UnixMilliseconds, idKey: 1, typeKeyIsBuyValue: "1"); + await callback(new KeyValuePair(symbol, trade)); } } else if (dataType == "o") @@ -484,14 +496,19 @@ protected override async Task OnGetTradesWebSocketAsync(Func { + IEnumerable marketIDs = null; if (marketSymbols == null || marketSymbols.Length == 0) { - marketSymbols = (await GetMarketSymbolsAsync()).ToArray(); + marketIDs = messageIdToSymbol.Keys; + } + else + { + marketIDs = marketSymbols.Select(s => symbolToMessageId[s]); } // subscribe to order book and trades channel for each symbol - foreach (var sym in marketSymbols) + foreach (var id in marketIDs) { - await _socket.SendMessageAsync(new { command = "subscribe", channel = NormalizeMarketSymbol(sym) }); + await _socket.SendMessageAsync(new { command = "subscribe", channel = id }); } }); }