|
|
@ -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<ExecutionLog>(); |
|
|
|
try |
|
|
|
{ |
|
|
|
//step = "检查订单是否入库";
|
|
|
|
CheckOrderExists(spotOrderPublishInfo.OrderId); |
|
|
|
|
|
|
|
//step = "查询订单所属机器人";
|
|
|
|
var robot = robotBusiness.GetD21PolicyRobotList(spotOrderPublishInfo.RobotId, isLoadRecentTradeProfit: false, isLoadAPIKey: true).FirstOrDefault(); |
|
|
|
if (robot == null) |
|
|
|
throw new BusinessException($"未找到机器人"); |
|
|
|
|
|
|
|
IUpdate<SpotOrder> updateSpotOrder = fsql.Update<SpotOrder>(spotOrderPublishInfo.OrderId).Set(o => o.State, spotOrderPublishInfo.SpotOrderState); |
|
|
|
IUpdate<RobotAccount> updateRobotAccount = null; |
|
|
|
IList<IUpdate<User>> updateUserList = null; |
|
|
|
List<UserAccountProfitLossRecord> 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<RobotAccount>(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<IUpdate<User>>(); |
|
|
|
insertUserAccountProfitLossRecordList = new List<UserAccountProfitLossRecord>(); |
|
|
|
|
|
|
|
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<RobotAccount>(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>(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) |
|
|
|
{ |
|
|
|