From 44dbcf18cd34ed25cbe76ae38045e362bf55a1ef Mon Sep 17 00:00:00 2001 From: shanj <18996038927@163.com> Date: Tue, 24 May 2022 06:07:57 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B8=82=E4=BB=B7=E6=AD=A2=E6=8D=9F=20?= =?UTF-8?q?=E5=B8=82=E4=BB=B7=E5=8D=96=E5=87=BA=E5=8F=96=E6=B6=88=E6=AD=A2?= =?UTF-8?q?=E6=8D=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Binance.TradeRobot.API.xml | 10 ++ .../Controllers/RobotController.cs | 2 + .../Binance.TradeRobot.Business.xml | 5 + .../Spot/BaseSpotOrderPublishBusiness.cs | 20 ++- .../Spot/D21OrderPublishBusiness.cs | 126 +++++++++++++++++- .../Binance.TradeRobot.Model.xml | 5 - SDKAdapter/APIClient/BaseAPIClient.cs | 11 ++ SDKAdapter/APIClient/BinanceAPIClient.cs | 5 + 8 files changed, 170 insertions(+), 14 deletions(-) diff --git a/Binance.TradeRobot.API/Binance.TradeRobot.API.xml b/Binance.TradeRobot.API/Binance.TradeRobot.API.xml index 0f8a81d..7550e80 100644 --- a/Binance.TradeRobot.API/Binance.TradeRobot.API.xml +++ b/Binance.TradeRobot.API/Binance.TradeRobot.API.xml @@ -74,6 +74,11 @@ + + + 刷新机器人运行时长 + + 创建金字塔策略机器人 @@ -92,6 +97,11 @@ + + + D21补救检查 + + D21杠杆/合约信号接口 diff --git a/Binance.TradeRobot.API/Controllers/RobotController.cs b/Binance.TradeRobot.API/Controllers/RobotController.cs index a228733..8a2a4f0 100644 --- a/Binance.TradeRobot.API/Controllers/RobotController.cs +++ b/Binance.TradeRobot.API/Controllers/RobotController.cs @@ -41,6 +41,7 @@ namespace Binance.TradeRobot.API.Controllers /// 刷新机器人运行时长 /// [HttpPost] + [AllowAnonymous] public void RefreshRobotRuningTime() { robotBusiness.RefreshRobotRuningTime(); @@ -80,6 +81,7 @@ namespace Binance.TradeRobot.API.Controllers /// D21补救检查 /// [HttpPost] + [AllowAnonymous] public void D21Remedy() { robotBusiness.D21Remedy(); diff --git a/Binance.TradeRobot.Business/Binance.TradeRobot.Business.xml b/Binance.TradeRobot.Business/Binance.TradeRobot.Business.xml index f1e2e7c..c1905ef 100644 --- a/Binance.TradeRobot.Business/Binance.TradeRobot.Business.xml +++ b/Binance.TradeRobot.Business/Binance.TradeRobot.Business.xml @@ -27,6 +27,11 @@ + + + 刷新机器人运行时长 + + 添加机器人和账户 diff --git a/Binance.TradeRobot.Business/Business/OrderPublishBusiness/Spot/BaseSpotOrderPublishBusiness.cs b/Binance.TradeRobot.Business/Business/OrderPublishBusiness/Spot/BaseSpotOrderPublishBusiness.cs index 4310a8a..1342fe9 100644 --- a/Binance.TradeRobot.Business/Business/OrderPublishBusiness/Spot/BaseSpotOrderPublishBusiness.cs +++ b/Binance.TradeRobot.Business/Business/OrderPublishBusiness/Spot/BaseSpotOrderPublishBusiness.cs @@ -14,6 +14,7 @@ namespace Binance.TradeRobot.Business protected DingBusiness dingBusiness; protected RobotBusiness robotBusiness; protected UserBusiness userBusiness; + protected ExchangeBusiness exchangeBusiness; public BaseSpotOrderPublishBusiness(IFreeSql fsql, NLogManager logManager, @@ -21,11 +22,13 @@ namespace Binance.TradeRobot.Business IMemoryCache memoryCache, DingBusiness dingBusiness, RobotBusiness robotBusiness, - UserBusiness userBusiness) : base(fsql, logManager, idGenerator, memoryCache) + UserBusiness userBusiness, + ExchangeBusiness exchangeBusiness) : base(fsql, logManager, idGenerator, memoryCache) { this.dingBusiness = dingBusiness; this.robotBusiness = robotBusiness; this.userBusiness = userBusiness; + this.exchangeBusiness = exchangeBusiness; } /// @@ -42,7 +45,7 @@ namespace Binance.TradeRobot.Business if (!isOrderExists) { tryCount--; - Thread.Sleep(1000); + Thread.Sleep(3000); continue; } return; @@ -71,5 +74,18 @@ namespace Binance.TradeRobot.Business logManager.GetLogger(loggerName).Error(ex, errorMsg); dingBusiness.Send($"{errorMsg} {ex.Message}"); } + + /// + /// 创建客户端订单号 + /// + /// + /// + /// + protected string CreateClientOrderId(long robotId, Enums.TradePolicy tradePolicy) + { + var guid = Guid.NewGuid(); + var random = new Random(guid.GetHashCode()); + return $"{Convert.ToChar(random.Next(97, 123))}{guid.ToString().Substring(0, 4)}_{robotId}_{(int)tradePolicy}"; + } } } diff --git a/Binance.TradeRobot.Business/Business/OrderPublishBusiness/Spot/D21OrderPublishBusiness.cs b/Binance.TradeRobot.Business/Business/OrderPublishBusiness/Spot/D21OrderPublishBusiness.cs index 9a458b0..25d0758 100644 --- a/Binance.TradeRobot.Business/Business/OrderPublishBusiness/Spot/D21OrderPublishBusiness.cs +++ b/Binance.TradeRobot.Business/Business/OrderPublishBusiness/Spot/D21OrderPublishBusiness.cs @@ -1,9 +1,12 @@ using Binance.TradeRobot.Common.DI; +using Binance.TradeRobot.Common.Extensions; using Binance.TradeRobot.Model.Base; using Binance.TradeRobot.Model.Db; +using Binance.TradeRobot.Model.Dto; using FreeSql; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; +using SDKAdapter.APIClient; using SDKAdapter.Model; using System; using System.Collections.Generic; @@ -17,7 +20,7 @@ namespace Binance.TradeRobot.Business { public Enums.TradePolicy TradePolicy => Enums.TradePolicy.D21; - public D21OrderPublishBusiness(IFreeSql fsql, NLogManager logManager, IIdGenerator idGenerator, IMemoryCache memoryCache, DingBusiness dingBusiness, RobotBusiness robotBusiness, UserBusiness userBusiness) : base(fsql, logManager, idGenerator, memoryCache, dingBusiness, robotBusiness, userBusiness) + public D21OrderPublishBusiness(IFreeSql fsql, NLogManager logManager, IIdGenerator idGenerator, IMemoryCache memoryCache, DingBusiness dingBusiness, RobotBusiness robotBusiness, UserBusiness userBusiness, ExchangeBusiness exchangeBusiness) : base(fsql, logManager, idGenerator, memoryCache, dingBusiness, robotBusiness, userBusiness, exchangeBusiness) { } @@ -37,6 +40,8 @@ namespace Binance.TradeRobot.Business if (robot == null) throw new BusinessException($"未找到机器人"); + var symbolInfo = exchangeBusiness.GetSymbol(spotOrderPublishInfo.Exchange, spotOrderPublishInfo.Symbol); + var apiClient = GetBaseAPIClient(robot.ExchangeId, robot.ExchangeAPIKey.AccountId, robot.ExchangeAPIKey.APIKey, robot.ExchangeAPIKey.SecretKey); IUpdate updateSpotOrder = fsql.Update(spotOrderPublishInfo.OrderId).Set(o => o.State, spotOrderPublishInfo.SpotOrderState); @@ -44,6 +49,7 @@ namespace Binance.TradeRobot.Business IList> updateUserList = null; List insertUserAccountProfitLossRecordList = null; IUpdate updateD21Policy = null; + List insertStopLossOrderList = null; if (spotOrderPublishInfo.SpotOrderState == Enums.SpotOrderState.Rejected || @@ -97,8 +103,30 @@ namespace Binance.TradeRobot.Business if (spotOrderPublishInfo.OrderType == Enums.OrderType.MARKET) { - //市价买单完全成交,根据策略挂止损单 - + #region 市价买单挂止损 + insertStopLossOrderList = new List(); + try + { + if (robot.D21Policy.Level1PositionStopLossRatio > 0 && robot.D21Policy.Level1PriceStopLossRatio > 0) + StopLossOrderPlace(robot, symbolInfo, avgTradePrice, quantity, insertStopLossOrderList, logList, apiClient, true); + + if (robot.D21Policy.Level2PositionStopLossRatio > 0 && + robot.D21Policy.Level2PriceStopLossRatio > 0 && + robot.D21Policy.Level2PositionStopLossRatio + robot.D21Policy.Level1PositionStopLossRatio == 100) + StopLossOrderPlace(robot, symbolInfo, avgTradePrice, quantity, insertStopLossOrderList, logList, apiClient, false); + } + catch (Exception ex) + { + logList.Add(new ExecutionLog() + { + Id = idGenerator.NewLong(), + SourceSingal = Enums.SingalType.订单推送, + RobotId = robot.Id, + CreateTime = DateTime.Now, + Content = $"止损单挂单失败,{ex.Message}" + }); + } + #endregion } } else if (spotOrderPublishInfo.TradeDirection == Enums.TradeDirection.Sell) @@ -109,7 +137,21 @@ namespace Binance.TradeRobot.Business if (spotOrderPublishInfo.OrderType == Enums.OrderType.MARKET) { //市价卖单完全成交,取消尚未触发的限价止损单 - + try + { + CancelStopLossOrder(robot, apiClient); + } + catch (Exception ex) + { + logList.Add(new ExecutionLog() + { + Id = idGenerator.NewLong(), + SourceSingal = Enums.SingalType.订单推送, + RobotId = robot.Id, + CreateTime = DateTime.Now, + Content = $"取消止损单失败,{ex.Message}" + }); + } } var interest = 0M; //借币利息 @@ -173,9 +215,6 @@ namespace Binance.TradeRobot.Business }); } } - - - } fsql.Transaction(() => @@ -189,6 +228,8 @@ namespace Binance.TradeRobot.Business if (updateUserList != null && updateUserList.Count() > 0) foreach (var u in updateUserList) u.ExecuteAffrows(); + if (insertStopLossOrderList != null && insertStopLossOrderList.Count() > 0) + fsql.Insert(insertStopLossOrderList).ExecuteAffrows(); }); } @@ -197,5 +238,76 @@ namespace Binance.TradeRobot.Business HandleError(ex, logList, spotOrderPublishInfo.LoggerName, spotOrderPublishInfo.RobotId, spotOrderPublishInfo.OrderId, step); } } + + /// + /// 挂止损单 + /// + /// + /// + /// + /// + /// + /// + /// + /// + private void StopLossOrderPlace(D21PolicyRobotResponse d21Robot, + SymbolInfo symbolInfo, + decimal avgTradePrice, + decimal buyQuantity, + IList insertStopLossOrderList, + IList logList, + BaseAPIClient baseAPIClient, + bool isFirstStopLoss) + { + var positionStopLossRatio = (isFirstStopLoss ? d21Robot.D21Policy.Level1PositionStopLossRatio : d21Robot.D21Policy.Level2PositionStopLossRatio) / 100; + var priceStopLossRatio = (isFirstStopLoss ? d21Robot.D21Policy.Level1PriceStopLossRatio : d21Robot.D21Policy.Level2PriceStopLossRatio) / 100; + + var stopPrice = avgTradePrice - avgTradePrice * priceStopLossRatio; + var stopQuantity = (buyQuantity * positionStopLossRatio).CutDecimal(symbolInfo.SaleQuantityAccuracy); + var stopLossClientOrderId = CreateClientOrderId(d21Robot.Id, d21Robot.TradePolicy); + var stopOrderId = baseAPIClient.IsolatedMarginPlaceOrder(d21Robot.Symbol, + Enums.TradeDirection.Sell, + Enums.OrderType.STOP_LOSS_LIMIT, + stopPrice: stopPrice, + price: stopPrice, + quantity: stopQuantity, + newClientOrderId: stopLossClientOrderId); + var stopLossOrder = new SpotOrder() + { + Id = stopOrderId, + CreateTime = DateTime.Now, + ExchangeId = d21Robot.ExchangeId, + LoanAmount = 0M, + OrderType = Enums.OrderType.STOP_LOSS_LIMIT, + PolicyType = Enums.TradePolicy.D21, + RobotId = d21Robot.Id, + State = Enums.SpotOrderState.Created, + Symbol = d21Robot.Symbol, + TradeDirection = Enums.TradeDirection.Sell + }; + insertStopLossOrderList.Add(stopLossOrder); + + logList.Add(new ExecutionLog() + { + Id = idGenerator.NewLong(), + SourceSingal = Enums.SingalType.订单推送, + RobotId = d21Robot.Id, + OrderId = stopOrderId, + CreateTime = DateTime.Now, + Content = $"{(isFirstStopLoss ? 1 : 2)}级止损挂单成功,订单号:{stopOrderId},挂单数量:{stopQuantity}" + }); + } + + private void CancelStopLossOrder(D21PolicyRobotResponse d21Robot, BaseAPIClient baseAPIClient) + { + var stopLossOrderIdList = fsql.Select().Where(o => o.OrderType == Enums.OrderType.STOP_LOSS_LIMIT && + o.State == Enums.SpotOrderState.Created && + o.RobotId == d21Robot.Id).ToList(o => o.Id); + if (stopLossOrderIdList == null || stopLossOrderIdList.Count() == 0) + return; + + foreach (var stopLossOrderId in stopLossOrderIdList) + baseAPIClient.CancelIsolateMarginOrder(d21Robot.Symbol, stopLossOrderId); + } } } diff --git a/Binance.TradeRobot.Model/Binance.TradeRobot.Model.xml b/Binance.TradeRobot.Model/Binance.TradeRobot.Model.xml index 9330602..a6d83c9 100644 --- a/Binance.TradeRobot.Model/Binance.TradeRobot.Model.xml +++ b/Binance.TradeRobot.Model/Binance.TradeRobot.Model.xml @@ -749,11 +749,6 @@ 运行时长(s) - - - 订单推送日志Key - - 机器人账户对象 diff --git a/SDKAdapter/APIClient/BaseAPIClient.cs b/SDKAdapter/APIClient/BaseAPIClient.cs index c9715bb..1b920c5 100644 --- a/SDKAdapter/APIClient/BaseAPIClient.cs +++ b/SDKAdapter/APIClient/BaseAPIClient.cs @@ -92,5 +92,16 @@ namespace SDKAdapter.APIClient { throw new NotImplementedException(); } + + /// + /// 取消逐仓杠杆订单 + /// + /// + /// + /// + public virtual void CancelIsolateMarginOrder(string symbol, long orderId) + { + throw new NotImplementedException(); + } } } diff --git a/SDKAdapter/APIClient/BinanceAPIClient.cs b/SDKAdapter/APIClient/BinanceAPIClient.cs index 9d1da6c..ed4570b 100644 --- a/SDKAdapter/APIClient/BinanceAPIClient.cs +++ b/SDKAdapter/APIClient/BinanceAPIClient.cs @@ -134,5 +134,10 @@ namespace SDKAdapter.APIClient throw new Exception($"下单失败 {orderType} {tradeDirection} {r.Error?.Message}"); return r.Data.Id; } + + public override void CancelIsolateMarginOrder(string symbol, long orderId) + { + _ = binanceClient.SpotApi.Trading.CancelMarginOrderAsync(symbol, orderId, isIsolated: true); + } } }