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);
+ }
}
}