using Binance.TradeRobot.Business.Extensions; using Binance.TradeRobot.Common.DI; using Binance.TradeRobot.Model.Base; using Binance.TradeRobot.Model.Db; using Binance.TradeRobot.Model.Dto; using Binance.TradeRobot.Model.RuningInfo; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Text; using System.Threading; using Yitter.IdGenerator; namespace Binance.TradeRobot.Business { [BatchRegistration(ServiceLifetime.Singleton, RegistrationType.Interface)] public class D21TradeBusiness : BaseBusiness, ITradeBusiness { private DingBusiness dingBusiness; private GlobalContext globalContext; private IList validStateList; public Enums.TradePolicy TradePolicy => Enums.TradePolicy.D21; public D21TradeBusiness(IFreeSql fsql, NLogManager logManager, IIdGenerator idGenerator, IMemoryCache memoryCache, DingBusiness dingBusiness, GlobalContext globalContext) : base(fsql, logManager, idGenerator, memoryCache) { this.dingBusiness = dingBusiness; this.globalContext = globalContext; validStateList = new List() { Enums.SpotOrderState.Filled, Enums.SpotOrderState.PartiallyFilled, Enums.SpotOrderState.Expired }; } public void TrendChanged(T singalRequest, T1 robot) where T : BaseSingalRequest where T1 : RobotResponse { try { var executionLog = new ExecutionLog() { Id = idGenerator.NewLong(), RobotId = robot.Id, CreateTime = DateTime.Now, SourceSingal = singalRequest.SingalType, Content = $"收到信号{singalRequest.SingalType}" }; fsql.Insert(executionLog).ExecuteAffrows(); var d21RuningInfo = RedisHelper.Get(robot.Id.ToString()) ?? new D21RuningInfo() { RobotId = robot.Id }; d21RuningInfo.RecentSmallTrendSingal = singalRequest.SingalType; RedisHelper.Set(robot.Id.ToString(), d21RuningInfo); } catch (Exception ex) { var stringBuilder = new StringBuilder("TrendChanged"); stringBuilder.AppendLine($"SingalRequest {JsonConvert.SerializeObject(singalRequest)}"); stringBuilder.AppendLine($"Robot {JsonConvert.SerializeObject(robot)}"); logManager.GetLogger(robot.ExecuteLogKey).Error(ex, stringBuilder.ToString()); } } public void LongCross(T singalRequest, T1 robot, bool isRemedy) where T : BaseSingalRequest where T1 : RobotResponse { string step = string.Empty; var logList = new List(); logList.Add(new ExecutionLog() { Id = idGenerator.NewLong(), SourceSingal = Enums.SingalType.多交叉, RobotId = robot.Id, CreateTime = DateTime.Now, Content = $"收到信号{singalRequest.SingalType}{(isRemedy ? "(补救)" : string.Empty)}" }); try { var d21RuningInfo = RedisHelper.Get(robot.Id.ToString()) ?? new D21RuningInfo() { RobotId = robot.Id }; #region 验证信号 step = "验证信号"; if (!isRemedy) { if (d21RuningInfo.ErrorCrossSingal != null) { d21RuningInfo.ErrorCrossSingal = null; d21RuningInfo.ErrorCrossSingalTime = 0; RedisHelper.Set(robot.Id.ToString(), d21RuningInfo); throw new BusinessException("前一个信号错误,终止多交叉信号执行"); } if (d21RuningInfo.RecentSmallTrendSingal == null) throw new BusinessException("缺少小趋势,终止多交叉信号执行"); if (d21RuningInfo.RecentSmallTrendSingal == Enums.SingalType.小趋势看空) { var errorTimeStamp = DateTime.Now.GetKID(singalRequest.KLinePeriodic, false); Thread.Sleep(5000); //防止多交叉和小趋势看多同时接收造成误判 d21RuningInfo = RedisHelper.Get(robot.Id.ToString()) ?? new D21RuningInfo() { RobotId = robot.Id }; if (d21RuningInfo.RecentSmallTrendSingal == Enums.SingalType.小趋势看空) { d21RuningInfo.ErrorCrossSingal = singalRequest.SingalType; d21RuningInfo.ErrorCrossSingalTime = errorTimeStamp; RedisHelper.Set(robot.Id.ToString(), d21RuningInfo); throw new BusinessException("小趋势看空,终止多交叉信号执行"); } } } #endregion #region 限制追高 var d21Robot = robot as D21PolicyRobotResponse; var newestPrice = globalContext.GetSpotNewestPrice(robot.KLineKey) ?? singalRequest.ClosePrice; step = "限制追高"; if (d21RuningInfo.RecentShortCrossSignalTradePrice != null && newestPrice > d21RuningInfo.RecentShortCrossSignalTradePrice) { var diffRatio = Math.Round((newestPrice / d21RuningInfo.RecentShortCrossSignalTradePrice.Value - 1) * 100, 2); if (diffRatio > d21Robot.D21Policy.MaxFollowPurchaseRatio) { throw new BusinessException($"触发限制追高,最近空交叉成交价{d21RuningInfo.RecentShortCrossSignalTradePrice},当前价格{newestPrice},追高比例{d21Robot.D21Policy.MaxFollowPurchaseRatio}%,当前比例{diffRatio}%,终止多交叉信号执行"); } } #endregion #region 获取账户余额 #endregion #region 计算下单数量 var previewTradeAmount = d21Robot.D21Policy.Position; //预估交易额 #endregion } catch (Exception ex) { logList.Add(new ExecutionLog() { Id = idGenerator.NewLong(), SourceSingal = Enums.SingalType.多交叉, RobotId = robot.Id, CreateTime = DateTime.Now, Content = ex.Message }); try { fsql.Insert(logList).ExecuteAffrows(); } catch { } var errorMsg = $"交易警报 {robot.ExecuteLogKey} {robot.Id} {step}"; logManager.GetLogger(robot.ExecuteLogKey).Error(ex, errorMsg); dingBusiness.Send($"{errorMsg} {ex.Message}"); } } public void ShortCross(T singalRequest, T1 robot, bool isRemedy) where T : BaseSingalRequest where T1 : RobotResponse { } } }