protected override async Task <IEnumerable <ExchangeOrderResult> > OnGetOpenOrderDetailsAsync(string symbol = null) { List <ExchangeOrderResult> orders = new List <ExchangeOrderResult>(); // { "SELL": [{ "oid": "59e59b279bd8d31d093d956e", "type": "SELL", "userOid": null, "coinType": "KCS", "coinTypePair": "BTC", "direction": "SELL","price": 0.1,"dealAmount": 0,"pendingAmount": 100, "createdAt": 1508219688000, "updatedAt": 1508219688000 } ... ], // "BUY": [{ "oid": "59e42bf09bd8d374c9956caa", "type": "BUY", "userOid": null, "coinType": "KCS", "coinTypePair": "BTC", "direction": "BUY", "price": 0.00009727,"dealAmount": 31.14503, "pendingAmount": 16.94827, "createdAt": 1508125681000, "updatedAt": 1508125681000 } ... ] var payload = await OnGetNoncePayloadAsync(); if (symbol != null) { payload["symbol"] = symbol; } JToken token = await MakeJsonRequestAsync <JToken>("/order/active-map?" + CryptoUtility.GetFormForPayload(payload, false), null, payload); if (token != null && token.HasValues) { foreach (JToken order in token["BUY"]) { orders.Add(ParseOpenOrder(order)); } foreach (JToken order in token["SELL"]) { orders.Add(ParseOpenOrder(order)); } } return(orders); }
protected override async Task ProcessRequestAsync(HttpWebRequest request, Dictionary <string, object> payload) { if (CanMakeAuthenticatedRequest(payload)) { request.Headers.Add("KC-API-KEY", PublicApiKey.ToUnsecureString()); request.Headers.Add("KC-API-NONCE", payload["nonce"].ToStringInvariant()); var endpoint = request.RequestUri.AbsolutePath; var message = string.Format("{0}/{1}/{2}", endpoint, payload["nonce"], CryptoUtility.GetFormForPayload(payload, false)); var sig = CryptoUtility.SHA256Sign(Convert.ToBase64String(Encoding.UTF8.GetBytes(message)), PrivateApiKey.ToUnsecureString()); request.Headers.Add("KC-API-SIGNATURE", sig); if (request.Method == "POST") { string msg = CryptoUtility.GetFormForPayload(payload, false); using (Stream stream = await request.GetRequestStreamAsync()) { byte[] content = Encoding.UTF8.GetBytes(msg); stream.Write(content, 0, content.Length); } } } }
protected override async Task <IEnumerable <ExchangeTransaction> > OnGetDepositHistoryAsync(string symbol) { symbol = NormalizeSymbol(symbol); List <ExchangeTransaction> deposits = new List <ExchangeTransaction>(); var payload = await OnGetNoncePayloadAsync(); payload.Add("start", DateTime.UtcNow.AddYears(-1).UnixTimestampFromDateTimeMilliseconds()); // required. Arbitrarily going with 1 year payload.Add("end", DateTime.UtcNow.UnixTimestampFromDateTimeMilliseconds()); // also required payload.Add("types", "DEPOSIT,WITHDRAWAL"); // opting to return both deposits and withdraws. // We can also include trades and orders with this call (which makes 3 ways to return the same data) JToken token = await MakeJsonRequestAsync <JToken>("/exchange/payment/history/transactions?" + CryptoUtility.GetFormForPayload(payload, false), null, await OnGetNoncePayloadAsync()); foreach (JToken tx in token) { deposits.Add(ParseTransaction(tx)); } return(deposits); }
/// <summary> /// This is a private call on Kucoin and therefore requires an API Key + API Secret. Calling this without authorization will cause an exception /// </summary> /// <param name="symbol"></param> /// <param name="periodSeconds"></param> /// <param name="startDate"></param> /// <param name="endDate"></param> /// <param name="limit"></param> /// <returns></returns> protected override async Task <IEnumerable <MarketCandle> > OnGetCandlesAsync(string symbol, int periodSeconds, DateTime?startDate = null, DateTime?endDate = null, int?limit = null) { List <MarketCandle> candles = new List <MarketCandle>(); string periodString; if (periodSeconds <= 60) { periodString = "1"; periodSeconds = 60; } else if (periodSeconds <= 300) { periodString = "5"; periodSeconds = 300; } else if (periodSeconds <= 900) { periodString = "15"; periodSeconds = 900; } else if (periodSeconds <= 1800) { periodString = "30"; periodSeconds = 1800; } else if (periodSeconds <= 3600) { periodString = "60"; periodSeconds = 3600; } else if (periodSeconds <= 86400) { periodString = "D"; periodSeconds = 86400; } else { periodString = "W"; periodSeconds = 604800; } endDate = endDate ?? DateTime.UtcNow; startDate = startDate ?? DateTime.UtcNow.AddDays(-1); // this is a little tricky. The call is private, but not a POST. We need the payload for the sig, but also for the uri // so, we'll do both... This is the only ExchangeAPI public call (private on Kucoin) like this. var payload = await OnGetNoncePayloadAsync(); payload.Add("symbol", symbol); payload.Add("resolution", periodString); payload.Add("from", (long)startDate.Value.UnixTimestampFromDateTimeSeconds()); // the nonce is milliseconds, this is seconds without decimal payload.Add("to", (long)endDate.Value.UnixTimestampFromDateTimeSeconds()); // the nonce is milliseconds, this is seconds without decimal var addPayload = CryptoUtility.GetFormForPayload(payload, false); // The results of this Kucoin API call are also a mess. 6 different arrays (c,t,v,h,l,o) with the index of each shared for the candle values // It doesn't use their standard error format... JToken token = await MakeJsonRequestAsync <JToken>("/open/chart/history?" + addPayload, null, payload); if (token != null && token.HasValues && token["s"].ToStringInvariant() == "ok") { int childCount = token["c"].Count(); for (int i = 0; i < childCount; i++) { candles.Add(new MarketCandle { ExchangeName = this.Name, Name = symbol, PeriodSeconds = periodSeconds, Timestamp = DateTimeOffset.FromUnixTimeSeconds(token["t"][i].ConvertInvariant <long>()).DateTime, ClosePrice = token["c"][i].ConvertInvariant <decimal>(), HighPrice = token["h"][i].ConvertInvariant <decimal>(), LowPrice = token["l"][i].ConvertInvariant <decimal>(), OpenPrice = token["o"][i].ConvertInvariant <decimal>(), ConvertedVolume = token["v"][i].ConvertInvariant <decimal>(), BaseVolume = token["v"][i].ConvertInvariant <decimal>() * token["c"][i].ConvertInvariant <decimal>() }); } } return(candles); }
/// <summary> /// Limited to the last 100 open orders /// </summary> /// <param name="symbol"></param> /// <returns></returns> protected override async Task <IEnumerable <ExchangeOrderResult> > OnGetOpenOrderDetailsAsync(string symbol = null) { symbol = NormalizeSymbol(symbol); List <ExchangeOrderResult> orders = new List <ExchangeOrderResult>(); var payload = await OnGetNoncePayloadAsync(); payload.Add("openClosed", "OPEM"); if (symbol != null) { payload.Add("currencyPair", symbol); } JToken token = await MakeJsonRequestAsync <JToken>("/exchange/client_orders?" + CryptoUtility.GetFormForPayload(payload, false), null, await OnGetNoncePayloadAsync()); foreach (JToken order in token) { orders.Add(ParseClientOrder(order)); } return(orders); }
protected override async Task <IEnumerable <ExchangeOrderResult> > OnGetCompletedOrderDetailsAsync(string symbol = null, DateTime?afterDate = null) { symbol = NormalizeSymbol(symbol); // We can increase the number of orders returned by including a limit parameter if desired List <ExchangeOrderResult> orders = new List <ExchangeOrderResult>(); var payload = await OnGetNoncePayloadAsync(); payload.Add("openClosed", "CLOSED"); // returns both closed and cancelled if (symbol != null) { payload.Add("currencyPair", symbol); } if (afterDate != null) { payload.Add("issuedFrom", ((DateTime)afterDate).UnixTimestampFromDateTimeMilliseconds()); } JToken token = await MakeJsonRequestAsync <JToken>("/exchange/client_orders?" + CryptoUtility.GetFormForPayload(payload, false), null, await OnGetNoncePayloadAsync()); foreach (JToken order in token) { orders.Add(ParseClientOrder(order)); } return(orders); }
/// <summary> /// Update the trade info via API /// </summary> public void Update() { Ticker = ExchangeInfo.API.GetTicker(Symbol); RecentTrades = ExchangeInfo.API.GetRecentTrades(Symbol).ToArray(); if (RecentTrades.Length == 0) { Trade = new Trade(); } else { Trade = new Trade { Amount = (float)RecentTrades[RecentTrades.Length - 1].Amount, Price = (float)RecentTrades[RecentTrades.Length - 1].Price, Ticks = (long)CryptoUtility.UnixTimestampFromDateTimeMilliseconds(RecentTrades[RecentTrades.Length - 1].Timestamp) }; } Orders = ExchangeInfo.API.GetOrderBook(Symbol); }
/// <summary> /// Return a rounded amount if needed /// </summary> /// <returns>Rounded amount or amount if no rounding is needed</returns> public decimal RoundAmount() { return(ShouldRoundAmount ? CryptoUtility.RoundAmount(Amount) : Amount); }
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)); }