14 changed files with 265 additions and 140 deletions
@ -0,0 +1,20 @@ |
|||
using Microsoft.Extensions.Caching.Memory; |
|||
using SDKAdapter.Model; |
|||
using System; |
|||
using Yitter.IdGenerator; |
|||
|
|||
namespace Binance.TradeRobot.Business |
|||
{ |
|||
public class BaseSpotOrderPublishTradeBusiness : BaseBusiness |
|||
{ |
|||
public BaseSpotOrderPublishTradeBusiness(IFreeSql fsql, |
|||
NLogManager logManager, |
|||
IIdGenerator idGenerator, |
|||
IMemoryCache memoryCache) : base(fsql, logManager, idGenerator, memoryCache) { } |
|||
|
|||
public virtual void OnSpotOrderPublish(SpotOrderTradePublishInfo spotOrderTradePublishInfo) |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,10 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
|
|||
namespace Binance.TradeRobot.Business.Business.OrderPublishBusiness.Spot |
|||
{ |
|||
internal class D21OrderPublishTradeBusiness |
|||
{ |
|||
} |
|||
} |
@ -0,0 +1,183 @@ |
|||
using Binance.Net.Clients; |
|||
using Binance.Net.Objects; |
|||
using Binance.TradeRobot.Model.Base; |
|||
using CryptoExchange.Net.Authentication; |
|||
using Newtonsoft.Json; |
|||
using SDKAdapter.Model; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
using System.Text.RegularExpressions; |
|||
using System.Threading; |
|||
|
|||
namespace SDKAdapter.WebSockets.Order.Spot |
|||
{ |
|||
public class BinanceSpotOrderWebSocketClient : SpotOrderWebSocketClient |
|||
{ |
|||
private BinanceSocketClient binanceSocketClient; |
|||
private BinanceClient binanceClient; |
|||
private CancellationTokenSource cancellationTokenSource; |
|||
private string listenKey; |
|||
private IList<Binance.Net.Enums.OrderStatus> ignoreOrderStateList; |
|||
|
|||
public BinanceSpotOrderWebSocketClient(Enums.BusinessType businessType, |
|||
long accountId, |
|||
string apiKey, |
|||
string secret, |
|||
NLog.ILogger logger, |
|||
Action<SpotOrderTradePublishInfo> onOrderUpdated) : base(businessType, |
|||
accountId, |
|||
apiKey, |
|||
secret, |
|||
logger, |
|||
onOrderUpdated) |
|||
{ |
|||
var spotClientOption = new BinanceApiClientOptions() |
|||
{ |
|||
BaseAddress = "https://api.binance.com", |
|||
ApiCredentials = new ApiCredentials(apiKey, secret) |
|||
}; |
|||
//var usdFuturesClientOption = new BinanceApiClientOptions()
|
|||
//{
|
|||
// BaseAddress = "https://fapi.binance.com",
|
|||
// ApiCredentials = new ApiCredentials(apiKey, secret)
|
|||
//};
|
|||
binanceClient = new BinanceClient(new BinanceClientOptions() |
|||
{ |
|||
//UsdFuturesApiOptions = usdFuturesClientOption,
|
|||
SpotApiOptions = spotClientOption |
|||
}); |
|||
binanceSocketClient = new BinanceSocketClient(); |
|||
listenKey = string.Empty; |
|||
ignoreOrderStateList = new List<Binance.Net.Enums.OrderStatus>() |
|||
{ |
|||
Binance.Net.Enums.OrderStatus.New, |
|||
Binance.Net.Enums.OrderStatus.PendingCancel, |
|||
Binance.Net.Enums.OrderStatus.Insurance, |
|||
Binance.Net.Enums.OrderStatus.Adl |
|||
}; |
|||
} |
|||
|
|||
public override void Start(string symbol = "") |
|||
{ |
|||
if (IsConnected) |
|||
return; |
|||
IsConnected = true; |
|||
cancellationTokenSource = new CancellationTokenSource(); |
|||
var getListenKeyResponse = binanceClient.SpotApi.Account.StartIsolatedMarginUserStreamAsync(symbol).Result; |
|||
if (!getListenKeyResponse.Success) |
|||
throw new Exception(getListenKeyResponse.Error?.Message ?? ""); |
|||
listenKey = getListenKeyResponse.Data; |
|||
_ = binanceSocketClient.SpotStreams.SubscribeToUserDataUpdatesAsync(listenKey, |
|||
(e) => |
|||
{ |
|||
try |
|||
{ |
|||
var originData = new StringBuilder(); |
|||
var isStop = false; |
|||
if (ignoreOrderStateList.Contains(e.Data.Status)) |
|||
{ |
|||
originData.Append($"不支持的订单状态{e.Data.Status}"); |
|||
isStop = true; |
|||
} |
|||
|
|||
else if (string.IsNullOrEmpty(e.Data.ClientOrderId)) |
|||
{ |
|||
originData.Append($"缺少ClientOrderId"); |
|||
isStop = true; |
|||
} |
|||
|
|||
long? robotId = null; |
|||
Enums.TradePolicy? tradePolicy = null; |
|||
|
|||
if (!isStop) |
|||
{ |
|||
var match = Regex.Match(e.Data.ClientOrderId, @"^([a-z0-9]{5})_(\d{15,})_(\d{1,2})$"); |
|||
if (!match.Success) |
|||
{ |
|||
originData.Append($"非机器人交易的ClientOrderId"); |
|||
isStop = true; |
|||
} |
|||
else |
|||
{ |
|||
robotId = long.Parse(match.Groups[2].Value); |
|||
tradePolicy = (Enums.TradePolicy)int.Parse(match.Groups[3].Value); |
|||
} |
|||
} |
|||
originData.Append($" {JsonConvert.SerializeObject(e.Data)}"); |
|||
logger.Info(originData); |
|||
if (isStop) |
|||
return; |
|||
|
|||
var orderState = Enums.SpotOrderState.Unknow; |
|||
switch (e.Data.Status) |
|||
{ |
|||
case Binance.Net.Enums.OrderStatus.PartiallyFilled: |
|||
case Binance.Net.Enums.OrderStatus.Filled: |
|||
case Binance.Net.Enums.OrderStatus.Canceled: |
|||
orderState = (Enums.SpotOrderState)(int)e.Data.Status; |
|||
break; |
|||
case Binance.Net.Enums.OrderStatus.Rejected: |
|||
orderState = Enums.SpotOrderState.Rejected; |
|||
break; |
|||
case Binance.Net.Enums.OrderStatus.Expired: |
|||
orderState = Enums.SpotOrderState.Expired; |
|||
break; |
|||
} |
|||
|
|||
OnOrderUpdated?.Invoke(new SpotOrderTradePublishInfo() |
|||
{ |
|||
OrderId = e.Data.Id, |
|||
RobotId = robotId.Value, |
|||
TradePolicy = tradePolicy.Value, |
|||
Symbol = e.Data.Symbol, |
|||
AccountId = this.AccountId, |
|||
OrderType = (Enums.OrderType)(int)e.Data.Type, |
|||
SpotOrderState = orderState, |
|||
TradeDirection = (Enums.TradeDirection)(int)e.Data.Side, |
|||
ClientOrderId = e.Data.ClientOrderId, |
|||
CummulativeTradeAmount = e.Data.QuoteQuantityFilled, |
|||
CummulativeTradeQuantity = e.Data.QuantityFilled, |
|||
Exchange = Enums.Exchange.Binance, |
|||
Fee = e.Data.Fee, |
|||
FeeUnit = e.Data.FeeAsset, |
|||
LastTradeAmount = e.Data.LastQuoteQuantity, |
|||
LastTradePrice = e.Data.LastPriceFilled, |
|||
LastTradeQuantity = e.Data.LastQuantityFilled, |
|||
LastTradeTime = e.Data.UpdateTime, |
|||
CreateTime = e.Data.CreateTime |
|||
}); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
logger.Error(ex); |
|||
} |
|||
}, |
|||
(e) => |
|||
{ |
|||
|
|||
}, |
|||
(e) => |
|||
{ |
|||
|
|||
}, |
|||
(e) => |
|||
{ |
|||
|
|||
}, |
|||
cancellationTokenSource.Token); |
|||
} |
|||
|
|||
public override void Stop(string symbol = "") |
|||
{ |
|||
if (!IsConnected) |
|||
return; |
|||
IsConnected = false; |
|||
cancellationTokenSource.Cancel(); |
|||
binanceSocketClient.SpotStreams.Dispose(); |
|||
cancellationTokenSource = null; |
|||
_ = binanceClient.SpotApi.Account.CloseIsolatedMarginUserStreamAsync(symbol, listenKey).Result; |
|||
listenKey = string.Empty; |
|||
} |
|||
} |
|||
} |
@ -1,112 +0,0 @@ |
|||
using Binance.Net.Clients; |
|||
using Binance.Net.Objects; |
|||
using Binance.TradeRobot.Model.Base; |
|||
using CryptoExchange.Net.Authentication; |
|||
using Newtonsoft.Json; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading; |
|||
|
|||
namespace SDKAdapter.WebSockets.Order.SpotOrder |
|||
{ |
|||
public class BinanceSpotOrderWebSocketClient : SpotOrderWebSocketClient |
|||
{ |
|||
private BinanceSocketClient binanceSocketClient; |
|||
private BinanceClient binanceClient; |
|||
private CancellationTokenSource cancellationTokenSource; |
|||
private string listenKey; |
|||
private IList<Binance.Net.Enums.OrderStatus> unSupportStateList; |
|||
|
|||
public BinanceSpotOrderWebSocketClient(Enums.BusinessType businessType, long accountId, string apiKey, string secret, NLog.ILogger logger) |
|||
: base(businessType, accountId, apiKey, secret, logger) |
|||
{ |
|||
var spotClientOption = new BinanceApiClientOptions() |
|||
{ |
|||
BaseAddress = "https://api.binance.com", |
|||
ApiCredentials = new ApiCredentials(apiKey, secret) |
|||
}; |
|||
//var usdFuturesClientOption = new BinanceApiClientOptions()
|
|||
//{
|
|||
// BaseAddress = "https://fapi.binance.com",
|
|||
// ApiCredentials = new ApiCredentials(apiKey, secret)
|
|||
//};
|
|||
binanceClient = new BinanceClient(new BinanceClientOptions() |
|||
{ |
|||
//UsdFuturesApiOptions = usdFuturesClientOption,
|
|||
SpotApiOptions = spotClientOption |
|||
}); |
|||
binanceSocketClient = new BinanceSocketClient(); |
|||
listenKey = string.Empty; |
|||
unSupportStateList = new List<Binance.Net.Enums.OrderStatus>() |
|||
{ |
|||
Binance.Net.Enums.OrderStatus.PendingCancel, |
|||
Binance.Net.Enums.OrderStatus.Insurance, |
|||
Binance.Net.Enums.OrderStatus.Adl |
|||
}; |
|||
} |
|||
|
|||
public override void Start(string symbol = "") |
|||
{ |
|||
if (IsConnected) |
|||
return; |
|||
IsConnected = true; |
|||
cancellationTokenSource = new CancellationTokenSource(); |
|||
var getListenKeyResponse = binanceClient.SpotApi.Account.StartIsolatedMarginUserStreamAsync(symbol).Result; |
|||
if (!getListenKeyResponse.Success) |
|||
throw new Exception(getListenKeyResponse.Error?.Message ?? ""); |
|||
listenKey = getListenKeyResponse.Data; |
|||
binanceSocketClient.SpotStreams.SubscribeToUserDataUpdatesAsync(listenKey, |
|||
(e) => |
|||
{ |
|||
logger.Info(JsonConvert.SerializeObject(e.Data)); |
|||
if (unSupportStateList.Contains(e.Data.Status)) |
|||
return; |
|||
OnOrderUpdated?.Invoke(new Model.SpotOrderTradePublishInfo() |
|||
{ |
|||
OrderId = e.Data.Id, |
|||
Symbol = e.Data.Symbol, |
|||
AccountId = this.AccountId, |
|||
OrderType = (Enums.OrderType)(int)e.Data.Type, |
|||
SpotOrderState = (Enums.SpotOrderState)(int)e.Data.Status, |
|||
TradeDirection = (Enums.TradeDirection)(int)e.Data.Side, |
|||
ClientOrderId = e.Data.ClientOrderId, |
|||
CummulativeTradeAmount = e.Data.QuoteQuantityFilled, |
|||
CummulativeTradeQuantity = e.Data.QuantityFilled, |
|||
Exchange = Enums.Exchange.Binance, |
|||
Fee = e.Data.Fee, |
|||
FeeUnit = e.Data.FeeAsset, |
|||
LastTradeAmount = e.Data.LastQuoteQuantity, |
|||
LastTradePrice = e.Data.LastPriceFilled, |
|||
LastTradeQuantity = e.Data.LastQuantityFilled, |
|||
LastTradeTime = e.Data.UpdateTime, |
|||
CreateTime = e.Data.CreateTime |
|||
}); |
|||
}, |
|||
(e) => |
|||
{ |
|||
|
|||
}, |
|||
(e) => |
|||
{ |
|||
|
|||
}, |
|||
(e) => |
|||
{ |
|||
|
|||
}, |
|||
cancellationTokenSource.Token); |
|||
} |
|||
|
|||
public override void Stop(string symbol = "") |
|||
{ |
|||
if (!IsConnected) |
|||
return; |
|||
IsConnected = false; |
|||
cancellationTokenSource.Cancel(); |
|||
binanceSocketClient.SpotStreams.Dispose(); |
|||
cancellationTokenSource = null; |
|||
_ = binanceClient.SpotApi.Account.CloseIsolatedMarginUserStreamAsync(symbol, listenKey).Result; |
|||
listenKey = string.Empty; |
|||
} |
|||
} |
|||
} |
Loading…
Reference in new issue