币安量化交易
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.

163 lines
7.7 KiB

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<Enums.SpotOrderState> 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>()
{
Enums.SpotOrderState.Filled,
Enums.SpotOrderState.PartiallyFilled,
Enums.SpotOrderState.Expired
};
}
public void TrendChanged<T, T1>(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<D21RuningInfo>(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, T1>(T singalRequest, T1 robot, bool isRemedy) where T : BaseSingalRequest where T1 : RobotResponse
{
string step = string.Empty;
var logList = new List<ExecutionLog>();
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<D21RuningInfo>(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<D21RuningInfo>(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 计算下单数量
var recentSellOrder = fsql.Select<SpotOrder>().Where(o => o.RobotId == robot.Id &&
o.TradeDirection == Enums.TradeDirection.Sell &&
validStateList.Contains(o.State))
.OrderByDescending(o => o.LastTradeTime)
.ToOne();
#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, T1>(T singalRequest, T1 robot, bool isRemedy) where T : BaseSingalRequest where T1 : RobotResponse
{
}
}
}