币安量化交易
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

181 lines
11 KiB

using Binance.TradeRobot.Common.DI;
using Binance.TradeRobot.Model.Base;
using Binance.TradeRobot.Model.Db;
using FreeSql;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using SDKAdapter.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using Yitter.IdGenerator;
namespace Binance.TradeRobot.Business
{
[BatchRegistration(ServiceLifetime.Singleton, RegistrationType.Interface)]
internal class D21OrderPublishBusiness : BaseSpotOrderPublishBusiness, ISpotOrderPublishBusiness
{
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 void OnSpotOrderPublish(SpotOrderPublishInfo spotOrderPublishInfo)
{
//var logger = logManager.GetLogger(spotOrderPublishInfo.LoggerName);
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 ||
spotOrderPublishInfo.SpotOrderState == Enums.SpotOrderState.Canceled)
{
logList.Add(new ExecutionLog()
{
Id = idGenerator.NewLong(),
CreateTime = DateTime.Now,
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}" : string.Empty)}"
});
}
if (spotOrderPublishInfo.SpotOrderState == Enums.SpotOrderState.Filled)
{
var avgTradePrice = spotOrderPublishInfo.CummulativeTradeAmount / spotOrderPublishInfo.CummulativeTradeQuantity; //计算成交均价
logList.Add(new ExecutionLog()
{
Id = idGenerator.NewLong(),
CreateTime = DateTime.Now,
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}"
});
//更新交易信息
updateSpotOrder = updateSpotOrder.Set(o => o.TradeAmount, spotOrderPublishInfo.CummulativeTradeAmount)
.Set(o => o.TradeQuantity, spotOrderPublishInfo.CummulativeTradeQuantity)
.Set(o => o.TradePrice, avgTradePrice)
.Set(o => o.TradeFee, spotOrderPublishInfo.Fee)
.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)
{
HandleError(ex, logList, spotOrderPublishInfo.LoggerName, spotOrderPublishInfo.RobotId, spotOrderPublishInfo.OrderId, step);
}
}
}
}