protected override async Task OnGetHistoricalTradesAsync(Func <IEnumerable <ExchangeTrade>, bool> callback, string symbol, DateTime?startDate = null, DateTime?endDate = null) { List <ExchangeTrade> allTrades = new List <ExchangeTrade>(); var trades = await MakeRequestOkexAsync(symbol, "/trades.do?symbol=$SYMBOL$"); foreach (JToken trade in trades.Item1) { // [ { "date": "1367130137", "date_ms": "1367130137000", "price": 787.71, "amount": 0.003, "tid": "230433", "type": "sell" } ] allTrades.Add(new ExchangeTrade { Amount = trade["amount"].ConvertInvariant <decimal>(), Price = trade["price"].ConvertInvariant <decimal>(), Timestamp = CryptoUtility.UnixTimeStampToDateTimeMilliseconds(trade["date_ms"].ConvertInvariant <long>()), Id = trade["tid"].ConvertInvariant <long>(), IsBuy = trade["type"].ToStringInvariant() == "buy" }); } callback(allTrades); }
private ExchangeOrderResult ParseOrder(JToken result) { decimal amount = result["original_amount"].ConvertInvariant <decimal>(); decimal amountFilled = result["executed_amount"].ConvertInvariant <decimal>(); return(new ExchangeOrderResult { Amount = amount, AmountFilled = amountFilled, Price = result["price"].ConvertInvariant <decimal>(), AveragePrice = result["avg_execution_price"].ConvertInvariant <decimal>(), Message = string.Empty, OrderId = result["id"].ToStringInvariant(), Result = (amountFilled == amount ? ExchangeAPIOrderResult.Filled : (amountFilled == 0 ? ExchangeAPIOrderResult.Pending : ExchangeAPIOrderResult.FilledPartially)), OrderDate = CryptoUtility.UnixTimeStampToDateTimeMilliseconds(result["timestampms"].ConvertInvariant <double>()), Symbol = result["symbol"].ToStringInvariant(), IsBuy = result["side"].ToStringInvariant() == "buy" }); }
private IEnumerable <ExchangeTrade> ParseTradesWebSocket(JToken token) { var trades = new List <ExchangeTrade>(); foreach (var t in token) { var trade = new ExchangeTrade() { Amount = t["amount"].ConvertInvariant <decimal>(), // System.OverflowException: Value was either too large or too small for an Int64. // Id = x["id"].ConvertInvariant<long>(), IsBuy = t["direction"].ToStringLowerInvariant().EqualsWithOption("buy"), Price = t["price"].ConvertInvariant <decimal>(), Timestamp = CryptoUtility.UnixTimeStampToDateTimeMilliseconds(t["ts"].ConvertInvariant <long>()) }; trades.Add(trade); } return(trades); }
private ExchangeOrderResult ParseOrder(JToken token) { ExchangeOrderResult result = new ExchangeOrderResult() { OrderId = token["id"].ToStringInvariant(), Symbol = token["symbol"].ToStringInvariant(), Amount = token["amount"].ConvertInvariant <decimal>(), AmountFilled = token["field-amount"].ConvertInvariant <decimal>(), Price = token["price"].ConvertInvariant <decimal>(), OrderDate = CryptoUtility.UnixTimeStampToDateTimeMilliseconds(token["created-at"].ConvertInvariant <long>()), IsBuy = token["type"].ToStringInvariant().StartsWith("buy"), Result = ParseState(token["state"].ToStringInvariant()), }; if (result.Price == 0 && result.AmountFilled != 0m) { var amountCash = token["field-cash-amount"].ConvertInvariant <decimal>(); result.Price = amountCash / result.AmountFilled; } return(result); }
private ExchangeTicker ParseTickerV2(string symbol, JToken ticker) { // {"buy":"0.00001273","change":"-0.00000009","changePercentage":"-0.70%","close":"0.00001273","createdDate":1527355333053,"currencyId":535,"dayHigh":"0.00001410","dayLow":"0.00001174","high":"0.00001410","inflows":"19.52673814","last":"0.00001273","low":"0.00001174","marketFrom":635,"name":{},"open":"0.00001282","outflows":"52.53715678","productId":535,"sell":"0.00001284","symbol":"you_btc","volume":"5643177.15601228"} decimal last = ticker["last"].ConvertInvariant <decimal>(); decimal vol = ticker["volume"].ConvertInvariant <decimal>(); return(new ExchangeTicker { Ask = ticker["sell"].ConvertInvariant <decimal>(), Bid = ticker["buy"].ConvertInvariant <decimal>(), Last = last, Volume = new ExchangeVolume { BaseVolume = vol, BaseSymbol = symbol, ConvertedVolume = vol * last, ConvertedSymbol = symbol, Timestamp = CryptoUtility.UnixTimeStampToDateTimeMilliseconds(ticker["createdDate"].ConvertInvariant <long>()) } }); }
protected override async Task <ExchangeTicker> OnGetTickerAsync(string symbol) { /* * {{ * "status": "ok", * "ch": "market.naseth.detail.merged", * "ts": 1525136582460, * "tick": { * "amount": 1614089.3164448638, * "open": 0.014552, * "close": 0.013308, * "high": 0.015145, * "id": 6442118070, * "count": 74643, * "low": 0.013297, * "version": 6442118070, * "ask": [ * 0.013324, * 0.0016 * ], * "vol": 22839.223396720725, * "bid": [ * 0.013297, * 3192.2322 * ] * } * }} */ symbol = NormalizeSymbol(symbol); JToken obj = await MakeJsonRequestAsync <JToken>("/market/detail/merged?symbol=" + symbol); var tick = obj["tick"]; var ts = CryptoUtility.UnixTimeStampToDateTimeMilliseconds(obj["ts"].ConvertInvariant <double>()); return(ParseTicker(symbol, ts, tick)); }
protected override async Task OnGetHistoricalTradesAsync(Func <IEnumerable <ExchangeTrade>, bool> callback, string symbol, DateTime?startDate = null, DateTime?endDate = null) { /* [ { * "a": 26129, // Aggregate tradeId * "p": "0.01633102", // Price * "q": "4.70443515", // Quantity * "f": 27781, // First tradeId * "l": 27781, // Last tradeId * "T": 1498793709153, // Timestamp * "m": true, // Was the buyer the maker? * "M": true // Was the trade the best price match? * } ] */ HistoricalTradeHelperState state = new HistoricalTradeHelperState(this) { Callback = callback, EndDate = endDate, ParseFunction = (JToken token) => { DateTime timestamp = CryptoUtility.UnixTimeStampToDateTimeMilliseconds(token["T"].ConvertInvariant <long>()); return(new ExchangeTrade { Amount = token["q"].ConvertInvariant <decimal>(), Price = token["p"].ConvertInvariant <decimal>(), Timestamp = timestamp, Id = token["a"].ConvertInvariant <long>(), IsBuy = token["m"].ConvertInvariant <bool>() }); }, StartDate = startDate, Symbol = symbol, TimestampFunction = (DateTime dt) => ((long)CryptoUtility.UnixTimestampFromDateTimeMilliseconds(dt)).ToStringInvariant(), Url = "/aggTrades?symbol=[symbol]&startTime={0}&endTime={1}", }; await state.ProcessHistoricalTrades(); }
private ExchangeOrderResult ParseOrder(JToken token) { /* * { * "result": true, * "orders": [ * { * "amount": 0.1, * "avg_price": 0, * "create_date": 1418008467000, * "deal_amount": 0, * "order_id": 10000591, * "orders_id": 10000591, * "price": 500, * "status": 0, * "symbol": "btc_usd", * "type": "sell" * }, * * */ ExchangeOrderResult result = new ExchangeOrderResult { Amount = token["amount"].ConvertInvariant <decimal>(), AmountFilled = token["deal_amount"].ConvertInvariant <decimal>(), Price = token["price"].ConvertInvariant <decimal>(), AveragePrice = token["avg_price"].ConvertInvariant <decimal>(), IsBuy = token["type"].ToStringInvariant().StartsWith("buy"), OrderDate = CryptoUtility.UnixTimeStampToDateTimeMilliseconds(token["create_date"].ConvertInvariant <long>()), OrderId = token["order_id"].ToStringInvariant(), Symbol = token["symbol"].ToStringInvariant(), Result = ParseOrderStatus(token["status"].ConvertInvariant <int>()), }; return(result); }
private ExchangeOrderResult ParseClientOrder(JToken token) { // "data": [{"id": 4910,"currencyPair": "BTC/USD","goodUntilTime": 0,"type": "MARKET_SELL","orderStatus": "EXECUTED","issueTime": 1409920636701,"price": null,"quantity": 2.85714285,"remainingQuantity": 0,"commission": null,"commissionRate": 0.005, "lastModificationTime": 1409920636701 }, .. ] ExchangeOrderResult order = new ExchangeOrderResult() { OrderId = token["id"].ToStringInvariant(), Symbol = token["currencyPair"].ToStringInvariant(), OrderDate = CryptoUtility.UnixTimeStampToDateTimeMilliseconds(token["issueTime"].ConvertInvariant <long>()), IsBuy = token["type"].ToStringInvariant().Contains("BUY"), Price = token["price"].ConvertInvariant <decimal>(), Amount = token["quantity"].ConvertInvariant <decimal>(), Fees = token["commission"].ConvertInvariant <decimal>(), }; order.AmountFilled = order.Amount - token["remainingQuantity"].ConvertInvariant <decimal>(); switch (token["status"].ToStringInvariant()) { case "CANCELLED": order.Result = ExchangeAPIOrderResult.Canceled; break; } return(order); }
protected override IWebSocket OnGetTickersWebSocket(Action <IReadOnlyCollection <KeyValuePair <string, ExchangeTicker> > > callback) { if (callback == null) { return(null); } Symbols = OnGetSymbolsMetadataAsync().GetAwaiter().GetResult(); symbolDict = Symbols.GroupBy(p => (p.MarketCurrency + p.BaseCurrency).ToLowerInvariant()).ToDictionary(k => k.Key, k => k.FirstOrDefault()); return(ConnectWebSocket(string.Empty, (msg, _socket) => { //消息返回事件 /* * {"id":"id1","status":"ok","subbed":"market.btcusdt.trade.detail","ts":1527574853489} * * * {{ * "ch": "market.btcusdt.trade.detail", * "ts": 1527574905759, * "tick": { * "id": 8232977476, * "ts": 1527574905623, * "data": [ * { * "amount": 0.3066, * "ts": 1527574905623, * "id": 82329774765058180723, * "price": 7101.81, * "direction": "buy" * } * ] * } * }} */ try { var freshTickers = new Dictionary <string, ExchangeTicker>(StringComparer.OrdinalIgnoreCase); var str = msg.UTF8StringFromGzip(); JToken token = JToken.Parse(str); if (token["status"] != null) { return; } else if (token["ping"] != null) { _socket.SendMessage(str.Replace("ping", "pong")); return; } var ch = token["ch"].ToStringInvariant(); var sArray = ch.Split('.'); var symbol = sArray[1]; var tickData = token["tick"]; var id = tickData["id"].ConvertInvariant <long>(); var ticks = tickData["data"]; string marketName = token["ch"].ToStringInvariant().Split('.')[1]; if (!symbolDict.ContainsKey(marketName)) { return; } foreach (JToken tick in ticks) { DateTime timestamp = CryptoUtility.UnixTimeStampToDateTimeMilliseconds(tick["ts"].ConvertInvariant <long>()); decimal last = tick["price"].ConvertInvariant <decimal>(); decimal volume = tick["amount"].ConvertInvariant <decimal>(); var t = new ExchangeTicker { Last = last, Volume = new ExchangeVolume { ConvertedVolume = volume, ConvertedSymbol = symbolDict[marketName].BaseCurrency, BaseSymbol = symbolDict[marketName].MarketCurrency, Timestamp = timestamp } }; freshTickers[marketName] = t; } callback(freshTickers); } catch { } }, (_socket) => { var symbols = GetSymbols().ToArray(); foreach (string symbol in symbols) { string normalizedSymbol = NormalizeSymbol(symbol); long id = Interlocked.Increment(ref webSocketId); string channel = $"market.{normalizedSymbol}.trade.detail"; string msg = $"{{\"sub\":\"{channel}\",\"id\":\"id{id}\"}}"; _socket.SendMessage(msg); } })); }
private ExchangeOrderResult ParseOrder(JToken token) { /* * "symbol": "IOTABTC", * "orderId": 1, * "clientOrderId": "12345", * "transactTime": 1510629334993, * "price": "1.00000000", * "origQty": "1.00000000", * "executedQty": "0.00000000", * "status": "NEW", * "timeInForce": "GTC", * "type": "LIMIT", * "side": "SELL", * "fills": [ * { * "price": "4000.00000000", * "qty": "1.00000000", * "commission": "4.00000000", * "commissionAsset": "USDT" * }, * { * "price": "3999.00000000", * "qty": "5.00000000", * "commission": "19.99500000", * "commissionAsset": "USDT" * }, * { * "price": "3998.00000000", * "qty": "2.00000000", * "commission": "7.99600000", * "commissionAsset": "USDT" * }, * { * "price": "3997.00000000", * "qty": "1.00000000", * "commission": "3.99700000", * "commissionAsset": "USDT" * }, * { * "price": "3995.00000000", * "qty": "1.00000000", * "commission": "3.99500000", * "commissionAsset": "USDT" * } * ] */ ExchangeOrderResult result = new ExchangeOrderResult { Amount = token["origQty"].ConvertInvariant <decimal>(), AmountFilled = token["executedQty"].ConvertInvariant <decimal>(), Price = token["price"].ConvertInvariant <decimal>(), IsBuy = token["side"].ToStringInvariant() == "BUY", OrderDate = CryptoUtility.UnixTimeStampToDateTimeMilliseconds(token["time"].ConvertInvariant <long>(token["transactTime"].ConvertInvariant <long>())), OrderId = token["orderId"].ToStringInvariant(), Symbol = token["symbol"].ToStringInvariant() }; switch (token["status"].ToStringInvariant()) { case "NEW": result.Result = ExchangeAPIOrderResult.Pending; break; case "PARTIALLY_FILLED": result.Result = ExchangeAPIOrderResult.FilledPartially; break; case "FILLED": result.Result = ExchangeAPIOrderResult.Filled; break; case "CANCELED": case "PENDING_CANCEL": case "EXPIRED": case "REJECTED": result.Result = ExchangeAPIOrderResult.Canceled; break; default: result.Result = ExchangeAPIOrderResult.Error; break; } ParseAveragePriceAndFeesFromFills(result, token["fills"]); return(result); }
protected override IWebSocket OnGetTickersWebSocket(Action <IReadOnlyCollection <KeyValuePair <string, ExchangeTicker> > > callback) { if (callback == null) { return(null); } return(ConnectWebSocket(string.Empty, (msg, _socket) => { /* # Request # {'event':'addChannel','channel':'ok_sub_spot_bch_btc_ticker'} # Response # [ # { # "channel": "ok_sub_spot_bch_btc_ticker", # "data": { # "high": "10000", # "vol": "185.03743858", # "last": "111", # "low": "0.00000001", # "buy": "115", # "change": "101", # "sell": "115", # "dayLow": "0.00000001", # "dayHigh": "10000", # "timestamp": 1500444626000 # } # } # ] */ try { var freshTickers = new Dictionary <string, ExchangeTicker>(StringComparer.OrdinalIgnoreCase); JToken token = JToken.Parse(msg.UTF8String()); token = token[0]; var channel = token["channel"].ToStringInvariant(); if (channel.EqualsWithOption("addChannel")) { return; } var sArray = channel.Split('_'); var marketName = sArray[3] + "_" + sArray[4]; var tickData = token["data"]; DateTime timestamp = CryptoUtility.UnixTimeStampToDateTimeMilliseconds(tickData["timestamp"].ConvertInvariant <long>()); decimal last = tickData["last"].ConvertInvariant <decimal>(); decimal volume = tickData["vol"].ConvertInvariant <decimal>(); var t = new ExchangeTicker { Last = last, Volume = new ExchangeVolume { ConvertedVolume = volume, ConvertedSymbol = sArray[4].ToUpperInvariant(), BaseSymbol = sArray[3].ToUpperInvariant(), Timestamp = timestamp } }; freshTickers[marketName] = t; callback(freshTickers); } catch { } }, (_socket) => { var symbols = GetSymbols().ToArray(); foreach (string symbol in symbols) { string normalizedSymbol = NormalizeSymbol(symbol); string channel = $"ok_sub_spot_{normalizedSymbol}_ticker"; string msg = $"{{\'event\':\'addChannel\',\'channel\':\'{channel}\'}}"; _socket.SendMessage(msg); } })); }
/// <summary> /// Get a string for this trade /// </summary> /// <returns>String</returns> public override string ToString() { return(CryptoUtility.UnixTimeStampToDateTimeMilliseconds(Ticks).ToLocalTime() + ": " + Amount + " at " + Price); }
protected override async Task OnGetHistoricalTradesAsync(Func <IEnumerable <ExchangeTrade>, bool> callback, string symbol, DateTime?startDate = null, DateTime?endDate = null) { const int maxCount = 100; symbol = NormalizeSymbol(symbol); string baseUrl = "/trades/t" + symbol + "/hist?sort=" + (startDate == null ? "-1" : "1") + "&limit=" + maxCount; string url; List <ExchangeTrade> trades = new List <ExchangeTrade>(); decimal[][] tradeChunk; while (true) { url = baseUrl; if (startDate != null) { url += "&start=" + (long)CryptoUtility.UnixTimestampFromDateTimeMilliseconds(startDate.Value); } tradeChunk = await MakeJsonRequestAsync <decimal[][]>(url); if (tradeChunk == null || tradeChunk.Length == 0) { break; } if (startDate != null) { startDate = CryptoUtility.UnixTimeStampToDateTimeMilliseconds((double)tradeChunk[tradeChunk.Length - 1][1]); } foreach (decimal[] tradeChunkPiece in tradeChunk) { trades.Add(new ExchangeTrade { Amount = Math.Abs(tradeChunkPiece[2]), IsBuy = tradeChunkPiece[2] > 0m, Price = tradeChunkPiece[3], Timestamp = CryptoUtility.UnixTimeStampToDateTimeMilliseconds((double)tradeChunkPiece[1]), Id = (long)tradeChunkPiece[0] }); } trades.Sort((t1, t2) => t1.Timestamp.CompareTo(t2.Timestamp)); if (!callback(trades)) { break; } trades.Clear(); if (tradeChunk.Length < maxCount || startDate == null) { break; } await Task.Delay(5000); } }
protected override IWebSocket OnGetTickersWebSocket(Action <IReadOnlyCollection <KeyValuePair <string, ExchangeTicker> > > callback) { if (callback == null) { return(null); } void innerCallback(string json) { #region sample json /* * { * Nonce : int, * Deltas : * [ * { * MarketName : string, * High : decimal, * Low : decimal, * Volume : decimal, * Last : decimal, * BaseVolume : decimal, * TimeStamp : date, * Bid : decimal, * Ask : decimal, * OpenBuyOrders : int, * OpenSellOrders : int, * PrevDay : decimal, * Created : date * } * ] * } */ #endregion var freshTickers = new Dictionary <string, ExchangeTicker>(StringComparer.OrdinalIgnoreCase); JToken token = JToken.Parse(json); token = token["D"]; foreach (JToken ticker in token) { string marketName = ticker["M"].ToStringInvariant(); decimal last = ticker["l"].ConvertInvariant <decimal>(); decimal ask = ticker["A"].ConvertInvariant <decimal>(); decimal bid = ticker["B"].ConvertInvariant <decimal>(); decimal volume = ticker["V"].ConvertInvariant <decimal>(); decimal baseVolume = ticker["m"].ConvertInvariant <decimal>(); DateTime timestamp = CryptoUtility.UnixTimeStampToDateTimeMilliseconds(ticker["T"].ConvertInvariant <long>()); var t = new ExchangeTicker { Ask = ask, Bid = bid, Last = last, Volume = new ExchangeVolume { ConvertedVolume = volume, ConvertedSymbol = marketName.Split('-')[0], BaseVolume = baseVolume, BaseSymbol = marketName.Split('-')[1], Timestamp = timestamp } }; freshTickers[marketName] = t; } callback(freshTickers); } var client = SocketManager; return(client.SubscribeToSummaryDeltas(innerCallback)); }