21 changed files with 470 additions and 125 deletions
@ -0,0 +1,44 @@ |
|||
using Binance.TradeRobot.Model.Base; |
|||
using Binance.TradeRobot.Model.Db; |
|||
using Binance.TradeRobot.Model.Dto; |
|||
using Microsoft.Extensions.Caching.Memory; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
using Yitter.IdGenerator; |
|||
|
|||
namespace Binance.TradeRobot.Business |
|||
{ |
|||
public class BaseTradeBusiness : BaseBusiness |
|||
{ |
|||
|
|||
protected DingBusiness dingBusiness { get; private set; } |
|||
protected GlobalContext globalContext { get; private set; } |
|||
|
|||
public BaseTradeBusiness(IFreeSql fsql, NLogManager logManager, IIdGenerator idGenerator, IMemoryCache memoryCache, DingBusiness dingBusiness, GlobalContext globalContext) : base(fsql, logManager, idGenerator, memoryCache) |
|||
{ |
|||
this.dingBusiness = dingBusiness; |
|||
this.globalContext = globalContext; |
|||
} |
|||
|
|||
public void HandleError(Exception ex, |
|||
Enums.SingalType singalType, |
|||
List<ExecutionLog> logList, |
|||
RobotResponse robot, |
|||
string step) |
|||
{ |
|||
logList.Add(new ExecutionLog() |
|||
{ |
|||
Id = idGenerator.NewLong(), |
|||
SourceSingal = singalType, |
|||
RobotId = robot.Id, |
|||
CreateTime = DateTime.Now, |
|||
Content = ex.Message |
|||
}); |
|||
try { fsql.Insert(logList).ExecuteAffrows(); } catch { } |
|||
var errorMsg = $"交易警报,{singalType},{robot.ExecuteKey},{robot.Id},{step}"; |
|||
logManager.GetLogger(robot.ExecuteKey).Error(ex, errorMsg); |
|||
dingBusiness.Send($"{errorMsg} {ex.Message}"); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,44 @@ |
|||
using Binance.TradeRobot.Model.Base; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
|
|||
namespace SDKAdapter.Model |
|||
{ |
|||
public class SpotOrderTradePublishInfo |
|||
{ |
|||
public Enums.Exchange Exchange { get; set; } |
|||
|
|||
public long AccountId { get; set; } |
|||
|
|||
public long OrderId { get; set; } |
|||
|
|||
public string ClientOrderId { get; set; } |
|||
|
|||
public string Symbol { get; set; } |
|||
|
|||
public Enums.TradeDirection TradeDirection { get; set; } |
|||
|
|||
public Enums.OrderType OrderType { get; set; } |
|||
|
|||
public Enums.SpotOrderState SpotOrderState { get; set; } |
|||
|
|||
public decimal LastTradePrice { get; set; } |
|||
|
|||
public decimal LastTradeAmount { get; set; } |
|||
|
|||
public decimal LastTradeQuantity { get; set; } |
|||
|
|||
public decimal Fee { get; set; } |
|||
|
|||
public string FeeUnit { get; set; } |
|||
|
|||
public decimal CummulativeTradeAmount { get; set; } |
|||
|
|||
public decimal CummulativeTradeQuantity { get; set; } |
|||
|
|||
public DateTime CreateTime { get; set; } |
|||
|
|||
public DateTime LastTradeTime { get; set; } |
|||
} |
|||
} |
@ -0,0 +1,112 @@ |
|||
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; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,45 @@ |
|||
using Binance.TradeRobot.Model.Base; |
|||
using SDKAdapter.Model; |
|||
using System; |
|||
|
|||
namespace SDKAdapter.WebSockets.Order.SpotOrder |
|||
{ |
|||
public class SpotOrderWebSocketClient |
|||
{ |
|||
protected long AccountId { get; private set; } |
|||
protected string ApiKey { get; private set; } |
|||
protected string Secret { get; private set; } |
|||
protected NLog.ILogger logger { get; private set; } |
|||
protected bool IsConnected { get; set; } |
|||
protected Enums.BusinessType BusinessType { get; private set; } |
|||
|
|||
public Action<SpotOrderTradePublishInfo> OnOrderUpdated { get; private set; } |
|||
|
|||
|
|||
public static SpotOrderWebSocketClient Create(Enums.BusinessType businessType, Enums.Exchange exchange, long accountId, string apiKey, string secret, NLog.ILogger logger, Action<SpotOrderTradePublishInfo> onOrderUpdated) |
|||
{ |
|||
if (exchange == Enums.Exchange.Binance) |
|||
return new BinanceSpotOrderWebSocketClient(businessType, accountId, apiKey, secret, logger); |
|||
return null; |
|||
} |
|||
|
|||
public SpotOrderWebSocketClient(Enums.BusinessType businessType, long accountId, string apiKey, string secret, NLog.ILogger logger) |
|||
{ |
|||
this.BusinessType = businessType; |
|||
this.AccountId = accountId; |
|||
this.ApiKey = apiKey; |
|||
this.Secret = secret; |
|||
this.logger = logger; |
|||
} |
|||
|
|||
public virtual void Start(string symbol = "") |
|||
{ |
|||
|
|||
} |
|||
|
|||
public virtual void Stop(string symbol = "") |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
@ -0,0 +1,14 @@ |
|||
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
|||
<targets> |
|||
<target name="errorFile" xsi:type="File" fileName="${basedir}/logs/${logger}/error/${shortdate}.txt" |
|||
layout="${longdate} | ${level:uppercase=false} ${newline}${message} ${newline}${onexception:${exception:format=tostring} ${newline}${stacktrace} ${newline}${newline}" |
|||
autoFlush="true"/> |
|||
<target name="infoFile" xsi:type="File" fileName="${basedir}/logs/${logger}/info/${shortdate}.txt" |
|||
layout="${longdate} | ${level:uppercase=false} ${newline}${message} ${newline}" |
|||
autoFlush="true"/> |
|||
</targets> |
|||
<rules> |
|||
<logger name="*" level="Error" writeTo="errorFile"/> |
|||
<logger name="*" level="Info" writeTo="infoFile" /> |
|||
</rules> |
|||
</nlog> |
Loading…
Reference in new issue