using Newtonsoft.Json; using System; using System.Collections.Generic; using WebSocket.Interfaces; using System.Linq; using System.IO; using System.IO.Compression; using System.Text; namespace WebSocket.Clients { public class HUOBIClient : IWebClient { #region Members internal class HUOBIResponse { [JsonProperty(PropertyName = "ts")] public long Timestamp { get; set; } public HUOBIMarket Tick { get; set; } [JsonProperty(PropertyName = "ch")] public string Name { get; set; } public string Pair { get { var array = this.Name.Split('.'); return array.Length > 1 ? array[1].ToUpper() : string.Empty; } set { } } } internal class HUOBIMarket { [JsonProperty(PropertyName = "open")] public decimal Open { get; set; } [JsonProperty(PropertyName = "close")] public decimal Close { get; set; } [JsonProperty(PropertyName = "low")] public decimal Low { get; set; } [JsonProperty(PropertyName = "high")] public decimal High { get; set; } [JsonProperty(PropertyName = "vol")] public decimal Volume { get; set; } //ts":1535719364915, //"tick":{"id":1535719320,"open":0.000029570000000000,"close":0.000029630000000000, // "low":0.000029570000000000,"high":0.000029630000000000, // "amount":16.450000000000000000,"vol":0.000487268300000000000000000000000000,"count":2}} } private IWebSocketForClient server; private Dictionary> CommandAnswers = new Dictionary>(); #endregion /// /// ctor /// /// public HUOBIClient(IWebSocketForClient server) { this.server = server; Register(); } public void Connected() { //SendAuth(); //wait connected message? } public void StartRequest(string[] pairs) { Send(new { sub = $"market.{pairs[0].ToLower()}.kline.1min", id = $"id{1}" }); //Send(new { // req = $"\"market.ethbtc.kline.1min\"", // id = $"\"id10\"" //}); //server.Send($"{{\"sub\":\"market.{pairs[0].ToLower()}.kline.1min\", \"id\":\"id10\"}}"); //{ // "req": "market.ethbtc.kline.1min", // "id": "id10" //} } private void Register() { On("connected", (c, obj) => Connected()); On("ping", (c, obj) => SendPong()); //On("ohlcv1m", (c, obj) => Update(c.E, c, obj, typeof(Summary))); } public void Message(string message) { var parse = JsonConvert.DeserializeObject(message, GetSettings()); if (parse.Oid != null && CommandAnswers.ContainsKey(parse.E + parse.Oid)) { CommandAnswers[parse.E + parse.Oid](parse, message); } if (CommandAnswers.ContainsKey(parse.E)) { CommandAnswers[parse.E](parse, message); } /* // response { "status": "ok", "rep": "market.btccny.kline.1min", "tick": [ { "amount": 1.6206, "count": 3, "id": 1494465840, "open": 9887.00, "close": 9885.00, "low": 9885.00, "high": 9887.00, "vol": 16021.632026 }, { "amount": 2.2124, "count": 6, "id": 1494465900, "open": 9885.00, "close": 9880.00, "low": 9880.00, "high": 9885.00, "vol": 21859.023500 } ] } */ } public void Tick() { //'ticker' or 'get-balance' } public void Data(byte[] data) { using (var compressedStream = new MemoryStream(data)) using (var zipStream = new GZipStream(compressedStream, CompressionMode.Decompress)) using (var resultStream = new MemoryStream()) { zipStream.CopyTo(resultStream); var tickData = JsonConvert.DeserializeObject(Encoding.Default.GetString(resultStream.ToArray()), typeof(HUOBIResponse), GetSettings()) as HUOBIResponse; if (tickData.Tick != null) { //this.server.updateData.Invoke(server.ExchangeId, "HUOBI", GetMarketOHLCVData(new Dictionary { { tickData.Pair, tickData } })); this.server.DataChanged("HUOBI", GetMarketOHLCVData(new Dictionary { { tickData.Pair, tickData } })); } } } public void Data(Dictionary data) { } public void Closed(bool byUser, string reason) { //{"unsub": "market.btccny.trade.detail", "id": "id4"} } public void Error(Exception ex) { } public void Error(string reason) { } public void SendFailed(string data, Exception ex) { } private void Send(object obj) { server.Send(JsonConvert.SerializeObject(obj, GetSettings())); } private void SendPong() { Send(new Command() { E = "pong" }); } private void On(string name, Action command) { CommandAnswers[name] = command; } private void Off(string name) { if (CommandAnswers.ContainsKey(name)) { CommandAnswers.Remove(name); } } public Dictionary GetMarketOHLCVData(Dictionary data) { return data.Select(x => { var item = x.Value as HUOBIResponse; return new MarketOHLCVData() { PairSymbol = item.Pair, HighPrice = item.Tick.High, LowPrice = item.Tick.Low, OpenPrice = item.Tick.Open, ClosePrice = item.Tick.Close, Volume = item.Tick.Volume, TimeStamp = ConvertFromLong(item.Timestamp), } as IMarketOHLCVData; }).ToDictionary(x => x.PairSymbol); } #region Helpers private DateTime _1970Time = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); private long ConvertToLong(DateTime time) { return (long)(time - _1970Time).TotalMilliseconds; } private DateTime ConvertFromLong(long ms) { return _1970Time.AddMilliseconds(ms); } private JsonSerializerSettings GetSettings() { var settings = new JsonSerializerSettings() { ContractResolver = new LowerCaseUnderscoreContractResolver() //Formatting = Formatting.Indented }; settings.Converters.Add(new Newtonsoft.Json.Converters.UnixDateTimeConverter()); return settings; } #endregion } }