using Binance.TradeRobot.Business.Extensions; 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 Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.Data.Common; using System.Linq; using Yitter.IdGenerator; namespace Binance.TradeRobot.Business { [BatchRegistration(ServiceLifetime.Singleton, RegistrationType.Self)] public class RobotBusiness : BaseBusiness { private GlobalContext globalContext; public RobotBusiness(IFreeSql fsql, NLogManager logManager, IIdGenerator idGenerator, IMemoryCache memoryCache, GlobalContext globalContext) : base(fsql, logManager, idGenerator, memoryCache) { this.globalContext = globalContext; } /// /// 检查机器人注册条件 /// /// /// /// private void CheckRobotRegister(AddRobotRequest addRobotRequest, out ExchangeAPIKey exchangeAPIKey) { exchangeAPIKey = null; if (string.IsNullOrEmpty(addRobotRequest.Symbol) || addRobotRequest.ExchangeAPIKeyId == 0) throw new BusinessException("参数不全"); exchangeAPIKey = fsql.Select(addRobotRequest.ExchangeAPIKeyId).ToOne(); if (exchangeAPIKey == null) throw new BusinessException("选择的APIKey不存在"); if (exchangeAPIKey.RobotId != null) throw new BusinessException("APIKey已被其他机器人使用"); var accountId = exchangeAPIKey.AccountId; if (fsql.Select().InnerJoin((ea, ek, r) => ea.Id == ek.AccountId) .LeftJoin((ea, ek, r) => ek.RobotId == r.Id) .Where((ea, ek, r) => ea.Id == accountId && r.Symbol == addRobotRequest.Symbol).Any()) throw new BusinessException("同一个交易所账号下只允许存在一个交易对"); } public void StartRobot(long robotId) { fsql.Update(robotId).Set(r => r.State, Enums.RobotState.Runing).ExecuteAffrows(); var robot = GetRobotList(robotId).FirstOrDefault(); //监听K线和订单 globalContext.SubscribeKLine(robot); globalContext.SubscribeOrderPublish(robot); } public void StopRobot(long robotId) { var robot = GetRobotList(robotId).FirstOrDefault(); fsql.Update(robotId).Set(r => r.State, Enums.RobotState.Stop).ExecuteAffrows(); var sameRunningCount = GetRobotList(symbol: robot.Symbol, robotState: Enums.RobotState.Runing, exchange: robot.ExchangeId).Count(); if (sameRunningCount == 0) { //取消监听K线和订单 globalContext.UnSubscribeKLine(robot); } } /// /// 添加机器人和账户 /// /// /// /// 机器人Id private long AddRobotWithTran(AddRobotRequest addRobotRequest, DbTransaction tran) { var robotId = idGenerator.NewLong(); fsql.Insert(new Robot() { Id = robotId, Symbol = addRobotRequest.Symbol.ToUpper(), TradePolicy = addRobotRequest.TradePolicy, BusinessType = addRobotRequest.TradePolicy.GetBusinessType(), ExchangeId = addRobotRequest.ExchangeId, CreateTime = DateTime.Now, RunningTime = 0, State = Enums.RobotState.Stop }).WithTransaction(tran).ExecuteAffrows(); fsql.Insert(new RobotAccount() { Id = idGenerator.NewLong(), RobotId = robotId }).WithTransaction(tran).ExecuteAffrows(); fsql.Update(addRobotRequest.ExchangeAPIKeyId).WithTransaction(tran).Set(ek => ek.RobotId, robotId).ExecuteAffrows(); return robotId; } /// /// 添加金字塔策略机器人 /// /// public void AddPyramidPolicyRobot(AddRobotRequest addRobotRequest) { CheckRobotRegister(addRobotRequest, out ExchangeAPIKey exchangeAPIKey); var pyramidPolicy = new PyramidPolicy(); pyramidPolicy.Id = idGenerator.NewLong(); fsql.Transaction(() => { var tran = fsql.Ado.TransactionCurrentThread; pyramidPolicy.RobotId = AddRobotWithTran(addRobotRequest, tran); fsql.Insert(pyramidPolicy).ExecuteAffrows(); }); //调整仓位杠杆倍数 } /// /// 添加动2.1策略机器人 /// /// public void AddD21PolicyRobot(AddRobotRequest addRobotRequest) { addRobotRequest.TradePolicy = Enums.TradePolicy.D21; CheckRobotRegister(addRobotRequest, out _); var d21Policy = new D21Policy() { Id = idGenerator.NewLong(), CreateTime = DateTime.Now, ExecutionMode = Enums.ExecutionMode.Both, IsEnabledIncreasePurchase = true, IsEnableRemedyForErrorCrossSignal = true }; fsql.Transaction(() => { var tran = fsql.Ado.TransactionCurrentThread; d21Policy.RobotId = AddRobotWithTran(addRobotRequest, tran); fsql.Insert(d21Policy).ExecuteAffrows(); }); } /// /// 查询机器人基本信息 /// /// 如果robotId有值,将忽略其他条件 /// /// /// /// public IList GetRobotList(long? robotId = null, string symbol = "", Enums.RobotState? robotState = null, Enums.Exchange? exchange = null) { var select = fsql.Select().InnerJoin((r, e) => r.Id == e.RobotId); if (robotId != null) select = select.Where((r, e) => r.Id == robotId); else select = select.WhereIf(!string.IsNullOrEmpty(symbol), (r, e) => r.Symbol == symbol) .WhereIf(robotState != null, (r, e) => r.State == robotState) .WhereIf(exchange != null, (r, e) => r.ExchangeId == exchange); return select.ToList((r, e) => new Robot() { Id = r.Id, BusinessType = r.BusinessType, ExchangeId = r.ExchangeId, Symbol = r.Symbol, State = r.State, RunningTime = r.RunningTime, CreateTime = r.CreateTime, TradePolicy = r.TradePolicy, ExchangeAccountId = e.AccountId, ExchangeAPIKey = e.APIKey, ExchangeSecretKey = e.SecretKey }).Map>(); } /// /// 获取动2.1策略机器人列表 /// /// 机器人状态 /// 信号周期 /// 交易对 /// 是否加载近期交易利润,默认true /// 是否加载机器人绑定的APIKey,默认false /// public IList GetD21PolicyRobotList(Enums.RobotState? robotState = null, Enums.SignalPeriod? signalPeriod = null, string symbol = "", bool isLoadRecentTradeProfit = true, bool isLoadAPIKey = false) { var robotList = fsql.Select().InnerJoin((r, ra, d, e) => r.Id == ra.RobotId) .InnerJoin((r, ra, d, e) => r.Id == d.RobotId) .InnerJoin((r, ra, d, e) => r.Id == e.RobotId) .WhereIf(robotState != null, (r, ra, d, e) => r.State == robotState) .WhereIf(signalPeriod != null, (r, ra, d, e) => d.PeriodicSignal == signalPeriod) .WhereIf(!string.IsNullOrEmpty(symbol), (r, ra, d, e) => r.Symbol == symbol) .Where((r, ra, d, e) => r.TradePolicy == Enums.TradePolicy.D21) .ToList((r, ra, d, e) => new Robot { Id = r.Id, BusinessType = r.BusinessType, ExchangeId = r.ExchangeId, Symbol = r.Symbol, State = r.State, RunningTime = r.RunningTime, CreateTime = r.CreateTime, TradePolicy = r.TradePolicy, //SymbolId = s.Id, //SymbolSaleQuantityAccuracy = s.SaleQuantityAccuracy, RobotAccountId = ra.Id, ClosePositionCount = ra.ClosePositionCount, WinCount = ra.WinCount, LoanAmount = ra.LoanAmount, SoptCurrentcyAmount = ra.SoptCurrentcyAmount, SpotCurrencyQuantity = ra.SpotCurrencyQuantity, TotalProfit = ra.TotalProfit, ExchangeAccountId = e.AccountId, ExchangeAPIKey = e.APIKey, ExchangeSecretKey = e.SecretKey, D21ExecutionMode = d.ExecutionMode, D21IsEnabledIncreasePurchase = d.IsEnabledIncreasePurchase, D21IsEnableRemedyForErrorCrossSignal = d.IsEnableRemedyForErrorCrossSignal, D21MaxFollowPurchaseRatio = d.MaxFollowPurchaseRatio, D21PeriodicSignal = d.PeriodicSignal, D21PolicyId = d.Id, D21Position = d.Position, D21Assets = d.Assets, D21Level1PositionStopLossRatio = d.Level1PositionStopLossRatio, D21Level1PriceStopLossRatio = d.Level1PriceStopLossRatio, D21Level2PositionStopLossRatio = d.Level2PositionStopLossRatio, D21Level2PriceStopLossRatio = d.Level2PriceStopLossRatio, D21MaxExchangeLoanRatio = d.MaxExchangeLoanRatio, D21MaxSystemLoanRatio = d.MaxSystemLoanRatio, D21CreateTime = d.CreateTime }).Map>(); if (isLoadRecentTradeProfit) { //统计近期订单利润 } if (!isLoadAPIKey) { foreach (var r in robotList) r.ExchangeAPIKey = null; } return robotList; } } }