Browse Source

多交叉信号处理

master
shanji 3 years ago
parent
commit
72e35dec58
  1. 3
      .editorconfig
  2. 29
      Binance.TradeRobot.Business/Binance.TradeRobot.Business.xml
  3. 32
      Binance.TradeRobot.Business/Business/DingBusiness.cs
  4. 3
      Binance.TradeRobot.Business/Business/SpotPolicyBusiness.cs
  5. 114
      Binance.TradeRobot.Business/Business/TradeBusiness/D21TradeBusiness.cs
  6. 27
      Binance.TradeRobot.Business/Business/TradeBusiness/ITradeBusiness.cs
  7. 74
      Binance.TradeRobot.Business/Extensions/KIDExtension.cs
  8. 12
      Binance.TradeRobot.Business/GlobalContext.cs
  9. 17
      Binance.TradeRobot.Model/RuningInfo/D21RuningInfo.cs

3
.editorconfig

@ -8,3 +8,6 @@ dotnet_diagnostic.CS1591.severity = none
# CS8625: 无法将 null 字面量转换为非 null 的引用类型。 # CS8625: 无法将 null 字面量转换为非 null 的引用类型。
dotnet_diagnostic.CS8625.severity = none dotnet_diagnostic.CS8625.severity = none
# CS8602: 解引用可能出现空引用。
dotnet_diagnostic.CS8602.severity = none

29
Binance.TradeRobot.Business/Binance.TradeRobot.Business.xml

@ -66,6 +66,35 @@
现货策略 现货策略
</summary> </summary>
</member> </member>
<member name="M:Binance.TradeRobot.Business.ITradeBusiness.TrendChanged``2(``0,``1)">
<summary>
趋势变化
</summary>
<typeparam name="T"></typeparam>
<typeparam name="T1"></typeparam>
<param name="singalRequest"></param>
<param name="robot"></param>
</member>
<member name="M:Binance.TradeRobot.Business.ITradeBusiness.LongCross``2(``0,``1,System.Boolean)">
<summary>
多交叉
</summary>
<typeparam name="T"></typeparam>
<typeparam name="T1"></typeparam>
<param name="singalRequest"></param>
<param name="robot"></param>
<param name="isRemedy">是否为补救信号</param>
</member>
<member name="M:Binance.TradeRobot.Business.ITradeBusiness.ShortCross``2(``0,``1,System.Boolean)">
<summary>
空交叉
</summary>
<typeparam name="T"></typeparam>
<typeparam name="T1"></typeparam>
<param name="singalRequest"></param>
<param name="robot"></param>
<param name="isRemedy">是否为补救信号</param>
</member>
<member name="M:Binance.TradeRobot.Business.UserBusiness.OneWayAssetChange(System.Int64,System.Decimal,System.Int64,Binance.TradeRobot.Model.Base.Enums.CapitalChangeType,System.String)"> <member name="M:Binance.TradeRobot.Business.UserBusiness.OneWayAssetChange(System.Int64,System.Decimal,System.Int64,Binance.TradeRobot.Model.Base.Enums.CapitalChangeType,System.String)">
<summary> <summary>
单向资产变更 单向资产变更

32
Binance.TradeRobot.Business/Business/DingBusiness.cs

@ -0,0 +1,32 @@
using Binance.TradeRobot.Common.DI;
using Binance.TradeRobot.Common.Http;
using Microsoft.Extensions.DependencyInjection;
namespace Binance.TradeRobot.Business
{
[BatchRegistration(ServiceLifetime.Singleton, RegistrationType.Self)]
public class DingBusiness
{
private RestApiService restApiService;
public DingBusiness(RestApiService restApiService)
{
this.restApiService = restApiService;
}
public void Send(string content)
{
try
{
restApiService.SendRequest("https://oapi.dingtalk.com/robot/send", "?access_token=be2f574475269e83584fa3ef1a93ef68e28c15402afa1d193aa82a1a51164850", new
{
msgtype = "text",
text = new
{
content
}
}, null, System.Net.Http.HttpMethod.Post);
}
catch { }
}
}
}

3
Binance.TradeRobot.Business/Business/SpotPolicyBusiness.cs

@ -5,9 +5,6 @@ using Binance.TradeRobot.Model.Db;
using Binance.TradeRobot.Model.Dto; using Binance.TradeRobot.Model.Dto;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using Yitter.IdGenerator; using Yitter.IdGenerator;
namespace Binance.TradeRobot.Business namespace Binance.TradeRobot.Business

114
Binance.TradeRobot.Business/Business/TradeBusiness/D21TradeBusiness.cs

@ -1,4 +1,5 @@
using Binance.TradeRobot.Common.DI; using Binance.TradeRobot.Business.Extensions;
using Binance.TradeRobot.Common.DI;
using Binance.TradeRobot.Model.Base; using Binance.TradeRobot.Model.Base;
using Binance.TradeRobot.Model.Db; using Binance.TradeRobot.Model.Db;
using Binance.TradeRobot.Model.Dto; using Binance.TradeRobot.Model.Dto;
@ -7,7 +8,9 @@ using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic;
using System.Text; using System.Text;
using System.Threading;
using Yitter.IdGenerator; using Yitter.IdGenerator;
namespace Binance.TradeRobot.Business namespace Binance.TradeRobot.Business
@ -15,13 +18,22 @@ namespace Binance.TradeRobot.Business
[BatchRegistration(ServiceLifetime.Singleton, RegistrationType.Interface)] [BatchRegistration(ServiceLifetime.Singleton, RegistrationType.Interface)]
public class D21TradeBusiness : BaseBusiness, ITradeBusiness public class D21TradeBusiness : BaseBusiness, ITradeBusiness
{ {
public D21TradeBusiness(IFreeSql fsql, NLogManager logManager, IIdGenerator idGenerator, IMemoryCache memoryCache) : base(fsql, logManager, idGenerator, memoryCache) private DingBusiness dingBusiness;
{ private GlobalContext globalContext;
}
public Enums.TradePolicy TradePolicy => Enums.TradePolicy.D21; 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;
}
public void TrendChanged<T, T1>(T singalRequest, T1 robot) where T : BaseSingalRequest where T1 : RobotResponse public void TrendChanged<T, T1>(T singalRequest, T1 robot) where T : BaseSingalRequest where T1 : RobotResponse
{ {
try try
@ -32,12 +44,10 @@ namespace Binance.TradeRobot.Business
RobotId = robot.Id, RobotId = robot.Id,
CreateTime = DateTime.Now, CreateTime = DateTime.Now,
SourceSingal = singalRequest.SingalType, SourceSingal = singalRequest.SingalType,
Content = $"收到趋势信号{singalRequest.SingalType}" Content = $"收到信号{singalRequest.SingalType}"
}; };
fsql.Insert(executionLog).ExecuteAffrows(); fsql.Insert(executionLog).ExecuteAffrows();
var d21RuningInfo = RedisHelper.Get<D21RuningInfo>(robot.Id.ToString()); var d21RuningInfo = RedisHelper.Get<D21RuningInfo>(robot.Id.ToString()) ?? new D21RuningInfo() { RobotId = robot.Id };
if (d21RuningInfo == null)
d21RuningInfo = new D21RuningInfo() { RobotId = robot.Id };
d21RuningInfo.RecentSmallTrendSingal = singalRequest.SingalType; d21RuningInfo.RecentSmallTrendSingal = singalRequest.SingalType;
RedisHelper.Set(robot.Id.ToString(), d21RuningInfo); RedisHelper.Set(robot.Id.ToString(), d21RuningInfo);
} }
@ -50,18 +60,88 @@ namespace Binance.TradeRobot.Business
} }
} }
public void LongCross<T, T1>(T singalRequest, T1 robot, decimal newestPrice, bool isRemedy) public void LongCross<T, T1>(T singalRequest, T1 robot, bool isRemedy) where T : BaseSingalRequest where T1 : RobotResponse
where T : BaseSingalRequest
where T1 : RobotResponse
{ {
throw new NotImplementedException(); 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
}
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, decimal newestPrice, bool isRemedy) public void ShortCross<T, T1>(T singalRequest, T1 robot, bool isRemedy) where T : BaseSingalRequest where T1 : RobotResponse
where T : BaseSingalRequest
where T1 : RobotResponse
{ {
throw new NotImplementedException();
} }
} }
} }

27
Binance.TradeRobot.Business/Business/TradeBusiness/ITradeBusiness.cs

@ -7,10 +7,33 @@ namespace Binance.TradeRobot.Business
{ {
Enums.TradePolicy TradePolicy { get; } Enums.TradePolicy TradePolicy { get; }
/// <summary>
/// 趋势变化
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="T1"></typeparam>
/// <param name="singalRequest"></param>
/// <param name="robot"></param>
void TrendChanged<T, T1>(T singalRequest, T1 robot) where T : BaseSingalRequest where T1 : RobotResponse; void TrendChanged<T, T1>(T singalRequest, T1 robot) where T : BaseSingalRequest where T1 : RobotResponse;
void LongCross<T, T1>(T singalRequest, T1 robot, decimal newestPrice,bool isRemedy) where T : BaseSingalRequest where T1 : RobotResponse; /// <summary>
/// 多交叉
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="T1"></typeparam>
/// <param name="singalRequest"></param>
/// <param name="robot"></param>
/// <param name="isRemedy">是否为补救信号</param>
void LongCross<T, T1>(T singalRequest, T1 robot, bool isRemedy) where T : BaseSingalRequest where T1 : RobotResponse;
void ShortCross<T, T1>(T singalRequest, T1 robot, decimal newestPrice, bool isRemedy) where T : BaseSingalRequest where T1 : RobotResponse; /// <summary>
/// 空交叉
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="T1"></typeparam>
/// <param name="singalRequest"></param>
/// <param name="robot"></param>
/// <param name="isRemedy">是否为补救信号</param>
void ShortCross<T, T1>(T singalRequest, T1 robot, bool isRemedy) where T : BaseSingalRequest where T1 : RobotResponse;
} }
} }

74
Binance.TradeRobot.Business/Extensions/KIDExtension.cs

@ -0,0 +1,74 @@
using Binance.TradeRobot.Common.Extensions;
using Binance.TradeRobot.Model.Base;
using System;
namespace Binance.TradeRobot.Business.Extensions
{
public static class KIDExtension
{
public static long GetKID(this DateTime datetime, Enums.SignalPeriod kLinePeriodic, bool isPrevious)
{
DateTime dt = datetime.AddSeconds(datetime.Second * -1).AddMilliseconds(datetime.Millisecond * -1);
if (kLinePeriodic == Enums.SignalPeriod._1m)
{
if (isPrevious)
dt = dt.AddMinutes(-1);
}
else if (kLinePeriodic == Enums.SignalPeriod._5m)
{
var fiveMinCount = dt.Minute / 5; //5分钟的次数
dt = dt.AddMinutes(dt.Minute * -1).AddMinutes(fiveMinCount * 5);
if (isPrevious)
dt = dt.AddMinutes(-5);
}
else if (kLinePeriodic == Enums.SignalPeriod._15m)
{
var fifteenMinCount = dt.Minute / 15; //15分钟次数
dt = dt.AddMinutes(dt.Minute * -1).AddMinutes(fifteenMinCount * 15);
if (isPrevious)
dt = dt.AddMinutes(-15);
}
else if (kLinePeriodic == Enums.SignalPeriod._30m)
{
var fifteenMinCount = dt.Minute / 30; //30分钟次数
dt = dt.AddMinutes(dt.Minute * -1).AddMinutes(fifteenMinCount * 30);
if (isPrevious)
dt = dt.AddMinutes(-30);
}
else if (kLinePeriodic == Enums.SignalPeriod._1h)
{
dt = dt.AddMinutes(dt.Minute * -1);
if (isPrevious)
dt = dt.AddHours(-1);
}
else if (kLinePeriodic == Enums.SignalPeriod._4h)
{
var hCount = dt.Hour / 4; //4小时的次数
dt = dt.AddMinutes(dt.Minute * -1).AddHours(dt.Hour * -1).AddHours(hCount * 4);
if (isPrevious)
dt = dt.AddHours(-4);
}
else if (kLinePeriodic == Enums.SignalPeriod._1d)
{
dt = dt.AddMinutes(dt.Minute * -1).AddHours(dt.Hour * -1);
if (isPrevious)
dt = dt.AddDays(-1);
}
else if (kLinePeriodic == Enums.SignalPeriod._1w)
{
var week = dt.DayOfWeek;
dt = dt.AddMinutes(dt.Minute * -1).AddHours(dt.Hour * -1).AddDays((int)week * -1);
if (isPrevious)
dt = dt.AddDays(-7);
}
else if (kLinePeriodic == Enums.SignalPeriod._1M)
{
dt = dt.AddMinutes(dt.Minute * -1).AddHours(dt.Hour * -1).AddDays((dt.Day - 1) * -1);
if (isPrevious)
dt = dt.AddMonths(-1);
}
Console.WriteLine(dt);
return dt.DateTimeToStamp(len13: false);
}
}
}

12
Binance.TradeRobot.Business/GlobalContext.cs

@ -62,5 +62,17 @@ namespace Binance.TradeRobot.Business
{ {
} }
/// <summary>
/// 获取指定交易对现货最新成交价
/// </summary>
/// <param name="symbol"></param>
/// <returns></returns>
public decimal? GetSpotNewestPrice(string key)
{
if (spotMarketWebSocketClientDictionary.TryGetValue(key, out SpotMarketWebSocketClient spotMarketWebSocketClient))
return spotMarketWebSocketClient.NewestPrice;
return null;
}
} }
} }

17
Binance.TradeRobot.Model/RuningInfo/D21RuningInfo.cs

@ -9,6 +9,21 @@ namespace Binance.TradeRobot.Model.RuningInfo
/// <summary> /// <summary>
/// 最近一次小趋势信号 /// 最近一次小趋势信号
/// </summary> /// </summary>
public Enums.SingalType RecentSmallTrendSingal { get; set; } public Enums.SingalType? RecentSmallTrendSingal { get; set; }
/// <summary>
/// 错误的交叉信号
/// </summary>
public Enums.SingalType? ErrorCrossSingal { get; set; }
/// <summary>
/// 错误交叉信号的K线时间戳
/// </summary>
public long ErrorCrossSingalTime { get; set; }
/// <summary>
/// 最近一次空交叉时的成交价
/// </summary>
public decimal? RecentShortCrossSignalTradePrice { get; set; }
} }
} }

Loading…
Cancel
Save