Browse Source

市价止损 市价卖出取消止损

master
shanji 3 years ago
parent
commit
44dbcf18cd
  1. 10
      Binance.TradeRobot.API/Binance.TradeRobot.API.xml
  2. 2
      Binance.TradeRobot.API/Controllers/RobotController.cs
  3. 5
      Binance.TradeRobot.Business/Binance.TradeRobot.Business.xml
  4. 20
      Binance.TradeRobot.Business/Business/OrderPublishBusiness/Spot/BaseSpotOrderPublishBusiness.cs
  5. 126
      Binance.TradeRobot.Business/Business/OrderPublishBusiness/Spot/D21OrderPublishBusiness.cs
  6. 5
      Binance.TradeRobot.Model/Binance.TradeRobot.Model.xml
  7. 11
      SDKAdapter/APIClient/BaseAPIClient.cs
  8. 5
      SDKAdapter/APIClient/BinanceAPIClient.cs

10
Binance.TradeRobot.API/Binance.TradeRobot.API.xml

@ -74,6 +74,11 @@
</summary>
<param name="robotId"></param>
</member>
<member name="M:Binance.TradeRobot.API.Controllers.RobotController.RefreshRobotRuningTime">
<summary>
刷新机器人运行时长
</summary>
</member>
<member name="M:Binance.TradeRobot.API.Controllers.RobotController.AddPyramidPolicyRobot(Binance.TradeRobot.Model.Dto.AddRobotRequest)">
<summary>
创建金字塔策略机器人
@ -92,6 +97,11 @@
</summary>
<returns></returns>
</member>
<member name="M:Binance.TradeRobot.API.Controllers.RobotController.D21Remedy">
<summary>
D21补救检查
</summary>
</member>
<member name="M:Binance.TradeRobot.API.Controllers.SingalController.D21Singal(Binance.TradeRobot.Model.Dto.D21SingalRequest)">
<summary>
D21杠杆/合约信号接口

2
Binance.TradeRobot.API/Controllers/RobotController.cs

@ -41,6 +41,7 @@ namespace Binance.TradeRobot.API.Controllers
/// 刷新机器人运行时长
/// </summary>
[HttpPost]
[AllowAnonymous]
public void RefreshRobotRuningTime()
{
robotBusiness.RefreshRobotRuningTime();
@ -80,6 +81,7 @@ namespace Binance.TradeRobot.API.Controllers
/// D21补救检查
/// </summary>
[HttpPost]
[AllowAnonymous]
public void D21Remedy()
{
robotBusiness.D21Remedy();

5
Binance.TradeRobot.Business/Binance.TradeRobot.Business.xml

@ -27,6 +27,11 @@
<param name="exchangeAPIKey"></param>
<exception cref="T:Binance.TradeRobot.Model.Base.BusinessException"></exception>
</member>
<member name="M:Binance.TradeRobot.Business.RobotBusiness.RefreshRobotRuningTime">
<summary>
刷新机器人运行时长
</summary>
</member>
<member name="M:Binance.TradeRobot.Business.RobotBusiness.AddRobotWithTran(Binance.TradeRobot.Model.Dto.AddRobotRequest,System.Data.Common.DbTransaction)">
<summary>
添加机器人和账户

20
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;
}
/// <summary>
@ -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}");
}
/// <summary>
/// 创建客户端订单号
/// </summary>
/// <param name="robotId"></param>
/// <param name="tradePolicy"></param>
/// <returns></returns>
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}";
}
}
}

126
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<SpotOrder> updateSpotOrder = fsql.Update<SpotOrder>(spotOrderPublishInfo.OrderId).Set(o => o.State, spotOrderPublishInfo.SpotOrderState);
@ -44,6 +49,7 @@ namespace Binance.TradeRobot.Business
IList<IUpdate<User>> updateUserList = null;
List<UserAccountProfitLossRecord> insertUserAccountProfitLossRecordList = null;
IUpdate<D21Policy> updateD21Policy = null;
List<SpotOrder> 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<SpotOrder>();
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);
}
}
/// <summary>
/// 挂止损单
/// </summary>
/// <param name="d21Robot"></param>
/// <param name="symbolInfo"></param>
/// <param name="avgTradePrice"></param>
/// <param name="buyQuantity"></param>
/// <param name="insertStopLossOrderList"></param>
/// <param name="logList"></param>
/// <param name="baseAPIClient"></param>
/// <param name="isFirstStopLoss"></param>
private void StopLossOrderPlace(D21PolicyRobotResponse d21Robot,
SymbolInfo symbolInfo,
decimal avgTradePrice,
decimal buyQuantity,
IList<SpotOrder> insertStopLossOrderList,
IList<ExecutionLog> 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<SpotOrder>().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);
}
}
}

5
Binance.TradeRobot.Model/Binance.TradeRobot.Model.xml

@ -749,11 +749,6 @@
运行时长(s)
</summary>
</member>
<member name="P:Binance.TradeRobot.Model.Dto.RobotResponse.SymbolInfo">
<summary>
订单推送日志Key
</summary>
</member>
<member name="P:Binance.TradeRobot.Model.Dto.RobotResponse.RobotAccount">
<summary>
机器人账户对象

11
SDKAdapter/APIClient/BaseAPIClient.cs

@ -92,5 +92,16 @@ namespace SDKAdapter.APIClient
{
throw new NotImplementedException();
}
/// <summary>
/// 取消逐仓杠杆订单
/// </summary>
/// <param name="symbol"></param>
/// <param name="orderId"></param>
/// <exception cref="NotImplementedException"></exception>
public virtual void CancelIsolateMarginOrder(string symbol, long orderId)
{
throw new NotImplementedException();
}
}
}

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

Loading…
Cancel
Save