Knocks/BackEnd/WebSocket.Clients/Clients/BinanceClient.cs

262 lines
9.3 KiB
C#

//using Cex.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Generic;
using System.Text;
using WebSocket.Interfaces;
using System.Linq;
using System.Threading.Tasks;
using System.Globalization;
using System.Text.RegularExpressions;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Linq;
using System.IO;
namespace WebSocket.Clients
{
public class LowerCaseUnderscoreContractResolver : DefaultContractResolver
{
private Regex regex = new Regex("(?!(^[A-Z]))([A-Z])");
protected override string ResolvePropertyName(string propertyName)
{
return regex.Replace(propertyName, "_$2"); //.ToLower();
}
}
public class MicrosoftSecondsDateTimeConverter : DateTimeConverterBase
{
private static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var token = JToken.Load(reader);
if (token.Type == JTokenType.Integer)
{
var dt = epoch.AddMilliseconds((long)token);
return dt;
}
// Not a Microsoft date.
return new JsonSerializer().Deserialize(token.CreateReader(), objectType);
}
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
public class BinanceStreamModel
{
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string e { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string E { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string s { get; set; }
[JsonProperty("k", NullValueHandling = NullValueHandling.Ignore)]
public BinanceTickerData Data { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string Ok { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string Error { get; set; }
}
public class BinanceTickerData
{
[JsonProperty("t", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(MicrosoftSecondsDateTimeConverter))]
public DateTime StartTime { get; set; } // : 123400000, // Kline start time
[JsonProperty("T", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(MicrosoftSecondsDateTimeConverter))]
public DateTime CloseTime { get; set; } //"T": 123460000, // Kline close time
[JsonProperty("s", NullValueHandling = NullValueHandling.Ignore)]
public string Symbol { get; set; } // "s": "BNBBTC", // Symbol
[JsonProperty("o", NullValueHandling = NullValueHandling.Ignore)]
public decimal OpenPrice { get; set; } // "o": "0.0010", // Open price
[JsonProperty("c", NullValueHandling = NullValueHandling.Ignore)]
public decimal ClosePrice { get; set; } // "c": "0.0020", // Close price
[JsonProperty("h", NullValueHandling = NullValueHandling.Ignore)]
public decimal HighPrice { get; set; } // "h": "0.0025", // High price
[JsonProperty("l", NullValueHandling = NullValueHandling.Ignore)]
public decimal LowPrice { get; set; } // "l": "0.0015", // Low price
[JsonProperty("v", NullValueHandling = NullValueHandling.Ignore)]
public decimal Volume { get; set; } // "v": "1000", // Base asset volume
// "i": "1m", // Interval
// "f": 100, // First trade ID
// "L": 200, // Last trade ID
// "n": 100, // Number of trades
// "x": false, // Is this kline closed?
// "q": "1.0000", // Quote asset volume
// "V": "500", // Taker buy base asset volume
// "Q": "0.500", // Taker buy quote asset volume
// "B": "123456" // Ignore
// }
}
public class BinanceModel: Command
{
public string stream { get; set; }
public BinanceStreamModel data { get; set; }
//"e": "kline", // Event type
//"E": 123456789, // Event time
//"s": "BNBBTC", // Symbol
//"k": {
// "t": 123400000, // Kline start time
// "T": 123460000, // Kline close time
// "s": "BNBBTC", // Symbol
// "i": "1m", // Interval
// "f": 100, // First trade ID
// "L": 200, // Last trade ID
// "o": "0.0010", // Open price
// "c": "0.0020", // Close price
// "h": "0.0025", // High price
// "l": "0.0015", // Low price
// "v": "1000", // Base asset volume
// "n": 100, // Number of trades
// "x": false, // Is this kline closed?
// "q": "1.0000", // Quote asset volume
// "V": "500", // Taker buy base asset volume
// "Q": "0.500", // Taker buy quote asset volume
// "B": "123456" // Ignore
// }
}
public class BinanceClient : IWebClient
{
#region Members
//private Dictionary<string, object> data = new Dictionary<string, object>();
private Dictionary<string, Action<Command, string>> CommandAnswers = new Dictionary<string, Action<Command, string>>();
private IWebSocketForClient server;
#endregion
/// <summary>
/// ctor
/// </summary>
/// <param name="server"></param>
public BinanceClient(IWebSocketForClient server)
{
this.server = server;
Register();
}
public void Connected()
{
//SendAuth();
//wait connected message?
}
private void Update(string name, Command command, string message, Type dataType) {
var data = new Dictionary<string, object>();
data[name]= JsonConvert.DeserializeObject(message, dataType, GetSettings());
this.server.DataChanged("Binance", GetMarketOHLCVData(data));
//this.server.updateData.Invoke(this.server.ExchangeId, "Binance", GetMarketOHLCVData(data));
}
private void Register()
{
On("kline", (c, obj) => Update(((BinanceModel)c).stream, c, obj, typeof(BinanceModel)));
//On("connected", (c, obj) => SendAuth());
//On("auth", (c, obj) => { if (c.Ok != null) { SetSubscribes(); } });
On("ping", (c, obj) => SendPong());
}
public void Message(string message)
{
var parse = JsonConvert.DeserializeObject<BinanceModel>(message, GetSettings());
//var arg = ((BinanceModel)parse);
if (parse.data != null && CommandAnswers.ContainsKey(parse.data.e))
{
CommandAnswers[parse.data.e](parse, message);
}
}
public void Tick()
{
//'ticker' or 'get-balance'
}
public void Data(byte[] data)
{
}
public void Data(Dictionary<string, object> data)
{
}
public void Closed(bool byUser, string reason)
{
//subscribed = false;
}
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, string> command)
{
CommandAnswers[name] = command;
}
private void Off(string name)
{
if (CommandAnswers.ContainsKey(name))
{
CommandAnswers.Remove(name);
}
}
public Dictionary<string, IMarketOHLCVData> GetMarketOHLCVData(Dictionary<string, object> data)
{
return data.Select(x => new MarketOHLCVData()
{
PairSymbol = ((BinanceModel)x.Value).data.s,
HighPrice = ((BinanceModel)x.Value).data.Data.HighPrice,
LowPrice = ((BinanceModel)x.Value).data.Data.LowPrice,
OpenPrice = ((BinanceModel)x.Value).data.Data.OpenPrice,
ClosePrice = ((BinanceModel)x.Value).data.Data.ClosePrice,
Volume = ((BinanceModel)x.Value).data.Data.Volume,
TimeStamp = ((BinanceModel)x.Value).data.Data.CloseTime
} as IMarketOHLCVData).ToDictionary(x => x.PairSymbol);
}
private JsonSerializerSettings GetSettings()
{
var settings = new JsonSerializerSettings()
{
ContractResolver = new LowerCaseUnderscoreContractResolver()
//Formatting = Formatting.Indented
};
//settings.Converters.Add(new MicrosoftSecondsDateTimeConverter());
return settings;
}
}
}