From a5897c28a4a33fa2c987306d63d03e6a53e2ec4d Mon Sep 17 00:00:00 2001
From: shanj <18996038927@163.com>
Date: Wed, 18 May 2022 03:28:03 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=9B=9E=E8=B0=83?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Binance.TradeRobot.Business.xml | 7 ++
.../Spot/BaseSpotOrderPublishBusiness.cs | 5 +-
.../Spot/D21OrderPublishBusiness.cs | 116 ++++++++++++++++--
.../Business/RobotBusiness.cs | 2 +-
.../Business/UserBusiness.cs | 52 ++++----
.../Base/MappingProfiles.cs | 2 +-
.../Binance.TradeRobot.Model.xml | 12 +-
Binance.TradeRobot.Model/Db/Robot/Robot.cs | 2 +-
.../Db/Robot/RobotAccount.cs | 4 +-
.../Dto/Response/User/UserResponse.cs | 40 +++++-
10 files changed, 200 insertions(+), 42 deletions(-)
diff --git a/Binance.TradeRobot.Business/Binance.TradeRobot.Business.xml b/Binance.TradeRobot.Business/Binance.TradeRobot.Business.xml
index 1d25885..f1e2e7c 100644
--- a/Binance.TradeRobot.Business/Binance.TradeRobot.Business.xml
+++ b/Binance.TradeRobot.Business/Binance.TradeRobot.Business.xml
@@ -12,6 +12,13 @@
+
+
+ 检查订单是否存在
+
+
+ 订单不存在异常
+
检查机器人注册条件
diff --git a/Binance.TradeRobot.Business/Business/OrderPublishBusiness/Spot/BaseSpotOrderPublishBusiness.cs b/Binance.TradeRobot.Business/Business/OrderPublishBusiness/Spot/BaseSpotOrderPublishBusiness.cs
index 7684f1e..4310a8a 100644
--- a/Binance.TradeRobot.Business/Business/OrderPublishBusiness/Spot/BaseSpotOrderPublishBusiness.cs
+++ b/Binance.TradeRobot.Business/Business/OrderPublishBusiness/Spot/BaseSpotOrderPublishBusiness.cs
@@ -13,16 +13,19 @@ namespace Binance.TradeRobot.Business
{
protected DingBusiness dingBusiness;
protected RobotBusiness robotBusiness;
+ protected UserBusiness userBusiness;
public BaseSpotOrderPublishBusiness(IFreeSql fsql,
NLogManager logManager,
IIdGenerator idGenerator,
IMemoryCache memoryCache,
DingBusiness dingBusiness,
- RobotBusiness robotBusiness) : base(fsql, logManager, idGenerator, memoryCache)
+ RobotBusiness robotBusiness,
+ UserBusiness userBusiness) : base(fsql, logManager, idGenerator, memoryCache)
{
this.dingBusiness = dingBusiness;
this.robotBusiness = robotBusiness;
+ this.userBusiness = userBusiness;
}
///
diff --git a/Binance.TradeRobot.Business/Business/OrderPublishBusiness/Spot/D21OrderPublishBusiness.cs b/Binance.TradeRobot.Business/Business/OrderPublishBusiness/Spot/D21OrderPublishBusiness.cs
index ba6bd25..d48e7c2 100644
--- a/Binance.TradeRobot.Business/Business/OrderPublishBusiness/Spot/D21OrderPublishBusiness.cs
+++ b/Binance.TradeRobot.Business/Business/OrderPublishBusiness/Spot/D21OrderPublishBusiness.cs
@@ -17,7 +17,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) : base(fsql, logManager, idGenerator, memoryCache, dingBusiness, robotBusiness)
+ public D21OrderPublishBusiness(IFreeSql fsql, NLogManager logManager, IIdGenerator idGenerator, IMemoryCache memoryCache, DingBusiness dingBusiness, RobotBusiness robotBusiness, UserBusiness userBusiness) : base(fsql, logManager, idGenerator, memoryCache, dingBusiness, robotBusiness, userBusiness)
{
}
@@ -26,19 +26,27 @@ namespace Binance.TradeRobot.Business
public void OnSpotOrderPublish(SpotOrderPublishInfo spotOrderPublishInfo)
{
//var logger = logManager.GetLogger(spotOrderPublishInfo.LoggerName);
- var step = "";
+ var step = string.Empty;
var logList = new List();
try
{
+ //step = "检查订单是否入库";
CheckOrderExists(spotOrderPublishInfo.OrderId);
+ //step = "查询订单所属机器人";
var robot = robotBusiness.GetD21PolicyRobotList(spotOrderPublishInfo.RobotId, isLoadRecentTradeProfit: false, isLoadAPIKey: true).FirstOrDefault();
if (robot == null)
throw new BusinessException($"未找到机器人");
IUpdate updateSpotOrder = fsql.Update(spotOrderPublishInfo.OrderId).Set(o => o.State, spotOrderPublishInfo.SpotOrderState);
+ IUpdate updateRobotAccount = null;
+ IList> updateUserList = null;
+ List insertUserAccountProfitLossRecordList = null;
- if (spotOrderPublishInfo.SpotOrderState == Enums.SpotOrderState.Rejected || spotOrderPublishInfo.SpotOrderState == Enums.SpotOrderState.Expired)
+
+ if (spotOrderPublishInfo.SpotOrderState == Enums.SpotOrderState.Rejected ||
+ spotOrderPublishInfo.SpotOrderState == Enums.SpotOrderState.Expired ||
+ spotOrderPublishInfo.SpotOrderState == Enums.SpotOrderState.Canceled)
{
logList.Add(new ExecutionLog()
{
@@ -47,12 +55,14 @@ namespace Binance.TradeRobot.Business
OrderId = spotOrderPublishInfo.OrderId,
RobotId = spotOrderPublishInfo.RobotId,
SourceSingal = Enums.SingalType.订单推送,
- Content = $"收到订单推送,订单号:{spotOrderPublishInfo.OrderId},订单方向:{spotOrderPublishInfo.TradeDirection},订单类型:{spotOrderPublishInfo.OrderType},订单状态:{spotOrderPublishInfo.SpotOrderState}{(spotOrderPublishInfo.SpotOrderState == Enums.SpotOrderState.Rejected ? spotOrderPublishInfo.RejectedReason : "")}"
+ Content = $"收到订单推送,订单号:{spotOrderPublishInfo.OrderId},订单方向:{spotOrderPublishInfo.TradeDirection},订单类型:{spotOrderPublishInfo.OrderType},订单状态:{spotOrderPublishInfo.SpotOrderState}{(spotOrderPublishInfo.SpotOrderState == Enums.SpotOrderState.Rejected ? $",拒绝原因:{spotOrderPublishInfo.RejectedReason}" : string.Empty)}"
});
}
if (spotOrderPublishInfo.SpotOrderState == Enums.SpotOrderState.Filled)
{
+
+ var avgTradePrice = spotOrderPublishInfo.CummulativeTradeAmount / spotOrderPublishInfo.CummulativeTradeQuantity; //计算成交均价
logList.Add(new ExecutionLog()
{
Id = idGenerator.NewLong(),
@@ -60,15 +70,107 @@ namespace Binance.TradeRobot.Business
OrderId = spotOrderPublishInfo.OrderId,
RobotId = spotOrderPublishInfo.RobotId,
SourceSingal = Enums.SingalType.订单推送,
- Content = $"收到订单推送,订单号:{spotOrderPublishInfo.OrderId},订单方向:{spotOrderPublishInfo.TradeDirection},订单类型:{spotOrderPublishInfo.OrderType},订单状态:{spotOrderPublishInfo.SpotOrderState},成交额:{spotOrderPublishInfo.LastTradeAmount},成交量:{spotOrderPublishInfo.LastTradeQuantity},成交价:{spotOrderPublishInfo.LastTradePrice},手续费({spotOrderPublishInfo.FeeUnit}):{spotOrderPublishInfo.Fee}"
+ Content = $"收到订单" +
+ $"推送,订单号:{spotOrderPublishInfo.OrderId},订单方向:{spotOrderPublishInfo.TradeDirection},订单类型:{spotOrderPublishInfo.OrderType},订单状态:{spotOrderPublishInfo.SpotOrderState},成交额:{spotOrderPublishInfo.LastTradeAmount},成交量:{spotOrderPublishInfo.LastTradeQuantity},成交价:{spotOrderPublishInfo.LastTradePrice},手续费({spotOrderPublishInfo.FeeUnit}):{spotOrderPublishInfo.Fee}"
});
+ //更新交易信息
updateSpotOrder = updateSpotOrder.Set(o => o.TradeAmount, spotOrderPublishInfo.CummulativeTradeAmount)
.Set(o => o.TradeQuantity, spotOrderPublishInfo.CummulativeTradeQuantity)
- .Set(o => o.TradePrice, spotOrderPublishInfo.CummulativeTradeAmount / spotOrderPublishInfo.CummulativeTradeQuantity)
+ .Set(o => o.TradePrice, avgTradePrice)
.Set(o => o.TradeFee, spotOrderPublishInfo.Fee)
- .Set(o => o.TradeFeeUnit, spotOrderPublishInfo.FeeUnit);
+ .Set(o => o.TradeFeeUnit, spotOrderPublishInfo.FeeUnit)
+ .Set(o => o.LastTradeTime, spotOrderPublishInfo.LastTradeTime);
+
+ if (spotOrderPublishInfo.TradeDirection == Enums.TradeDirection.Buy)
+ {
+ var quantity = spotOrderPublishInfo.CummulativeTradeQuantity - spotOrderPublishInfo.Fee; //扣除基础币手续费,得到真实购买数量
+ updateRobotAccount = fsql.Update(robot.RobotAccount.Id).Set(ra => ra.SpotCurrencyQuantity + quantity)
+ .Set(ra => ra.SpotCurrencyAmount + spotOrderPublishInfo.CummulativeTradeAmount);
+
+ if (spotOrderPublishInfo.OrderType == Enums.OrderType.MARKET)
+ {
+ //市价买单完全成交,根据策略挂止损单
+
+ }
+ }
+ else if (spotOrderPublishInfo.TradeDirection == Enums.TradeDirection.Sell)
+ {
+ updateUserList = new List>();
+ insertUserAccountProfitLossRecordList = new List();
+
+ if (spotOrderPublishInfo.OrderType == Enums.OrderType.MARKET)
+ {
+ //市价卖单完全成交,取消尚未触发的限价止损单
+
+ }
+
+ var interest = 0M; //借币利息
+ var loanAmount = robot.RobotAccount.LoanAmount; //借币金额
+ if (loanAmount > 0M)
+ {
+ //还币
+ var apiClient = GetBaseAPIClient(robot.ExchangeId, robot.ExchangeAPIKey.AccountId, robot.ExchangeAPIKey.APIKey, robot.ExchangeAPIKey.SecretKey);
+ interest = apiClient.IsolatedMarginRepay(robot.Symbol, loanAmount);
+ }
+
+
+ var buyAmount = spotOrderPublishInfo.CummulativeTradeQuantity * robot.RobotAccount.SpotCurrencyAvgPrice; //本次卖出对应的持仓金额
+ var profit = spotOrderPublishInfo.CummulativeTradeQuantity * (avgTradePrice - robot.RobotAccount.SpotCurrencyAvgPrice) - spotOrderPublishInfo.Fee - interest; //计算利润
+
+
+ updateSpotOrder = updateSpotOrder.SetIf(interest > 0M, o => o.LoanInterest, interest)
+ .Set(o => o.Profit, profit)
+ .Set(o => o.HistoryTotalProfit, robot.RobotAccount.TotalProfit + profit);
+
+ updateRobotAccount = fsql.Update(robot.RobotAccount.Id).Set(ra => ra.SpotCurrencyQuantity - spotOrderPublishInfo.CummulativeTradeQuantity)
+ .Set(ra => ra.SpotCurrencyAmount - buyAmount)
+ .Set(ra => ra.TotalProfit + profit)
+ .Set(ra => ra.ClosePositionCount + 1)
+ .SetIf(profit > 0M, ra => ra.WinCount + 1)
+ .SetIf(interest > 0M, ra => ra.LoanAmount - loanAmount);
+
+ var capitalChangeType = profit > 0M ? Enums.CapitalChangeType.Add : Enums.CapitalChangeType.Reduce;
+ var userList = userBusiness.GetUserList(multiplyBy100: false);
+ foreach (var user in userList)
+ {
+ var changeAmount = profit * user.DividendRatio; //根据用户分红比例计算本次分红或亏损
+
+ user.ChangeAmount(capitalChangeType, Math.Abs(changeAmount), false);
+
+
+ var updateUser = fsql.Update(user.Id).Set(u => u.CostAmount, user.CostAmount)
+ .Set(u => u.Profit, user.Profit);
+ updateUserList.Add(updateUser);
+ insertUserAccountProfitLossRecordList.Add(new UserAccountProfitLossRecord()
+ {
+ Id = idGenerator.NewLong(),
+ BusinessType = robot.BusinessType,
+ ChangeAmount = changeAmount,
+ CreateTime = DateTime.Now,
+ ExchangeId = robot.ExchangeId,
+ OrderId = spotOrderPublishInfo.OrderId,
+ OrderProfit = profit,
+ UserId = user.Id,
+ RobotId = robot.Id,
+ DividendRatio = user.DividendRatio,
+ UserProfit = user.Profit
+ });
+ }
+ }
}
+ fsql.Transaction(() =>
+ {
+ fsql.Insert(logList).ExecuteAffrows();
+ updateSpotOrder.ExecuteAffrows();
+ updateRobotAccount?.ExecuteAffrows();
+ if (insertUserAccountProfitLossRecordList != null && insertUserAccountProfitLossRecordList.Count() > 0)
+ fsql.Insert(insertUserAccountProfitLossRecordList).ExecuteAffrows();
+ if (updateUserList != null && updateUserList.Count() > 0)
+ foreach (var u in updateUserList)
+ u.ExecuteAffrows();
+ });
+
}
catch (Exception ex)
{
diff --git a/Binance.TradeRobot.Business/Business/RobotBusiness.cs b/Binance.TradeRobot.Business/Business/RobotBusiness.cs
index 2d02513..5ffe730 100644
--- a/Binance.TradeRobot.Business/Business/RobotBusiness.cs
+++ b/Binance.TradeRobot.Business/Business/RobotBusiness.cs
@@ -248,7 +248,7 @@ namespace Binance.TradeRobot.Business
ClosePositionCount = ra.ClosePositionCount,
WinCount = ra.WinCount,
LoanAmount = ra.LoanAmount,
- SoptCurrentcyAmount = ra.SoptCurrentcyAmount,
+ SpotCurrencyAmount = ra.SpotCurrencyAmount,
SpotCurrencyQuantity = ra.SpotCurrencyQuantity,
TotalProfit = ra.TotalProfit,
diff --git a/Binance.TradeRobot.Business/Business/UserBusiness.cs b/Binance.TradeRobot.Business/Business/UserBusiness.cs
index 8f1c32d..161341a 100644
--- a/Binance.TradeRobot.Business/Business/UserBusiness.cs
+++ b/Binance.TradeRobot.Business/Business/UserBusiness.cs
@@ -58,7 +58,7 @@ namespace Binance.TradeRobot.Business
};
}
- public IList GetUserList()
+ public IList GetUserList(bool multiplyBy100 = true)
{
var userList = fsql.Select().ToList(u => new UserResponse()
{
@@ -70,7 +70,7 @@ namespace Binance.TradeRobot.Business
UserName = u.UserName,
WithdrawAmount = u.WithdrawAmount
});
- userList.CalculateRatio();
+ userList.CalculateRatio(multiplyBy100);
return userList;
}
@@ -102,30 +102,30 @@ namespace Binance.TradeRobot.Business
//if (totalBalance < changeAmount)
// throw new BusinessException("交易所总余额小于减持资金,不能提现");
}
-
- if (capitalChangeType == Enums.CapitalChangeType.Add)
- {
- changeUser.CostAmount += changeAmount;
- }
- else if (capitalChangeType == Enums.CapitalChangeType.Reduce)
- {
- if (changeUser.Profit > 0)
- {
- if (changeUser.Profit >= changeAmount)
- changeUser.Profit -= changeAmount; //收益足够提现,只扣收益
- else
- {
- var lessChangeAmount = changeAmount; //收益不足提现,先扣收益,不足部分再扣本金
- lessChangeAmount -= changeUser.Profit;
- changeUser.Profit = 0;
- changeUser.CostAmount -= lessChangeAmount;
- }
- }
- else
- {
- changeUser.CostAmount -= changeAmount;
- }
- }
+ changeUser.ChangeAmount(capitalChangeType, changeAmount, true);
+ //if (capitalChangeType == Enums.CapitalChangeType.Add)
+ //{
+ // changeUser.CostAmount += changeAmount;
+ //}
+ //else if (capitalChangeType == Enums.CapitalChangeType.Reduce)
+ //{
+ // if (changeUser.Profit > 0)
+ // {
+ // if (changeUser.Profit >= changeAmount)
+ // changeUser.Profit -= changeAmount; //收益足够提现,只扣收益
+ // else
+ // {
+ // var lessChangeAmount = changeAmount; //收益不足提现,先扣收益,不足部分再扣本金
+ // lessChangeAmount -= changeUser.Profit;
+ // changeUser.Profit = 0;
+ // changeUser.CostAmount -= lessChangeAmount;
+ // }
+ // }
+ // else
+ // {
+ // changeUser.CostAmount -= changeAmount;
+ // }
+ //}
fsql.Transaction(() =>
{
diff --git a/Binance.TradeRobot.Model/Base/MappingProfiles.cs b/Binance.TradeRobot.Model/Base/MappingProfiles.cs
index 036b463..b7fa0db 100644
--- a/Binance.TradeRobot.Model/Base/MappingProfiles.cs
+++ b/Binance.TradeRobot.Model/Base/MappingProfiles.cs
@@ -18,7 +18,7 @@ namespace Binance.TradeRobot.Model.Base
CreateMap().ForPath(t => t.RobotAccount.Id, opt => opt.MapFrom(f => f.RobotAccountId))
.ForPath(t => t.RobotAccount.RobotId, opt => opt.MapFrom(f => f.Id))
- .ForPath(t => t.RobotAccount.SoptCurrentcyAmount, opt => opt.MapFrom(f => f.SoptCurrentcyAmount))
+ .ForPath(t => t.RobotAccount.SpotCurrencyAmount, opt => opt.MapFrom(f => f.SpotCurrencyAmount))
.ForPath(t => t.RobotAccount.SpotCurrencyQuantity, opt => opt.MapFrom(f => f.SpotCurrencyQuantity))
.ForPath(t => t.RobotAccount.ClosePositionCount, opt => opt.MapFrom(f => f.ClosePositionCount))
.ForPath(t => t.RobotAccount.LoanAmount, opt => opt.MapFrom(f => f.LoanAmount))
diff --git a/Binance.TradeRobot.Model/Binance.TradeRobot.Model.xml b/Binance.TradeRobot.Model/Binance.TradeRobot.Model.xml
index 6ccf878..b87ee4a 100644
--- a/Binance.TradeRobot.Model/Binance.TradeRobot.Model.xml
+++ b/Binance.TradeRobot.Model/Binance.TradeRobot.Model.xml
@@ -354,7 +354,7 @@
平仓次数
-
+
现货/杠杆持仓金额
@@ -449,7 +449,7 @@
平仓次数
-
+
现货/杠杆持仓金额
@@ -790,6 +790,14 @@
分红比例
+
+
+ 用户资金改变算法
+
+
+
+ true:优先增加本金 false:优先增加利润
+
最近一次小趋势信号
diff --git a/Binance.TradeRobot.Model/Db/Robot/Robot.cs b/Binance.TradeRobot.Model/Db/Robot/Robot.cs
index bfa2d91..3d1c4f4 100644
--- a/Binance.TradeRobot.Model/Db/Robot/Robot.cs
+++ b/Binance.TradeRobot.Model/Db/Robot/Robot.cs
@@ -62,7 +62,7 @@ namespace Binance.TradeRobot.Model.Db
/// 现货/杠杆持仓金额
///
[Column(IsIgnore = true)]
- public decimal SoptCurrentcyAmount { get; set; } = 0.0M;
+ public decimal SpotCurrencyAmount { get; set; } = 0.0M;
///
/// 现货/杠杆持仓数量
diff --git a/Binance.TradeRobot.Model/Db/Robot/RobotAccount.cs b/Binance.TradeRobot.Model/Db/Robot/RobotAccount.cs
index d1830d3..2763474 100644
--- a/Binance.TradeRobot.Model/Db/Robot/RobotAccount.cs
+++ b/Binance.TradeRobot.Model/Db/Robot/RobotAccount.cs
@@ -23,7 +23,7 @@ namespace Binance.TradeRobot.Model.Db
/// 现货/杠杆持仓金额
///
[Column(DbType = "decimal(18,8)")]
- public decimal SoptCurrentcyAmount { get; set; } = 0.0M;
+ public decimal SpotCurrencyAmount { get; set; } = 0.0M;
///
/// 现货/杠杆持仓数量
@@ -57,7 +57,7 @@ namespace Binance.TradeRobot.Model.Db
{
get
{
- return SpotCurrencyQuantity == 0M ? 0M : SoptCurrentcyAmount / SpotCurrencyQuantity;
+ return SpotCurrencyQuantity == 0M ? 0M : SpotCurrencyAmount / SpotCurrencyQuantity;
}
}
}
diff --git a/Binance.TradeRobot.Model/Dto/Response/User/UserResponse.cs b/Binance.TradeRobot.Model/Dto/Response/User/UserResponse.cs
index ad3ff46..11836ce 100644
--- a/Binance.TradeRobot.Model/Dto/Response/User/UserResponse.cs
+++ b/Binance.TradeRobot.Model/Dto/Response/User/UserResponse.cs
@@ -1,4 +1,6 @@
-namespace Binance.TradeRobot.Model.Dto
+using Binance.TradeRobot.Model.Base;
+
+namespace Binance.TradeRobot.Model.Dto
{
public class UserResponse : Db.User
{
@@ -16,5 +18,41 @@
/// 分红比例
///
public decimal DividendRatio { get; set; }
+
+ ///
+ /// 用户资金改变算法
+ ///
+ ///
+ ///
+ /// true:优先增加本金 false:优先增加利润
+ public void ChangeAmount(Enums.CapitalChangeType capitalChangeType, decimal changeAmount, bool priorityAddCost)
+ {
+ if (capitalChangeType == Enums.CapitalChangeType.Add)
+ {
+ if (priorityAddCost)
+ CostAmount += changeAmount;
+ else
+ Profit += changeAmount;
+ }
+ else if (capitalChangeType == Enums.CapitalChangeType.Reduce)
+ {
+ if (Profit > 0)
+ {
+ if (Profit >= changeAmount)
+ Profit -= changeAmount; //收益足够提现,只扣收益
+ else
+ {
+ var lessChangeAmount = changeAmount; //收益不足提现,先扣收益,不足部分再扣本金
+ lessChangeAmount -= Profit;
+ Profit = 0;
+ CostAmount -= lessChangeAmount;
+ }
+ }
+ else
+ {
+ CostAmount -= changeAmount;
+ }
+ }
+ }
}
}