Browse Source

订阅K线

master
shanji 3 years ago
parent
commit
a720d88847
  1. 9
      Binance.TradeRobot.API/Startup.cs
  2. 2
      Binance.TradeRobot.Business/Binance.TradeRobot.Business.csproj
  3. 34
      Binance.TradeRobot.Business/Binance.TradeRobot.Business.xml
  4. 59
      Binance.TradeRobot.Business/Business/RobotBusiness.cs
  5. 58
      Binance.TradeRobot.Business/GlobalContext.cs
  6. 4
      Binance.TradeRobot.Model/Dto/Response/Robot/RobotResponse.cs
  7. 5
      SDKAdapter/SDKAdapter.csproj
  8. 36
      SDKAdapter/WebSockets/Market/BinanceSpotMarketWebSocketClient.cs
  9. 14
      SDKAdapter/WebSockets/Market/GateIOSpotMarketWebSocketClient.cs
  10. 20
      SDKAdapter/WebSockets/Market/SpotMarketWebSocketClient.cs

9
Binance.TradeRobot.API/Startup.cs

@ -95,7 +95,7 @@ namespace Binance.TradeRobot.API
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, RobotBusiness robotBusiness, GlobalContext globalContext)
{
app.UseSwagger(c => c.SerializeAsV2 = true)
.UseSwaggerUI(c =>
@ -117,7 +117,12 @@ namespace Binance.TradeRobot.API
endpoints.MapControllers();
});
//websocket
var robotList = robotBusiness.GetRobotList(robotState: Enums.RobotState.Runing);
foreach (var robot in robotList)
{
globalContext.SubscribeKLine(robot);
globalContext.SubscribeOrderPublish(robot);
}
}
}
}

2
Binance.TradeRobot.Business/Binance.TradeRobot.Business.csproj

@ -8,6 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Binance.Net" Version="8.0.13" />
<PackageReference Include="CSRedisCore" Version="3.6.9" />
<PackageReference Include="FreeSql" Version="3.0.100" />
<PackageReference Include="FreeSql.Provider.MySql" Version="3.0.100" />
@ -20,6 +21,7 @@
<ItemGroup>
<ProjectReference Include="..\Binance.TradeRobot.Common\Binance.TradeRobot.Common.csproj" />
<ProjectReference Include="..\Binance.TradeRobot.Model\Binance.TradeRobot.Model.csproj" />
<ProjectReference Include="..\SDKAdapter\SDKAdapter.csproj" />
</ItemGroup>
</Project>

34
Binance.TradeRobot.Business/Binance.TradeRobot.Business.xml

@ -40,6 +40,16 @@
</summary>
<param name="addRobotRequest"></param>
</member>
<member name="M:Binance.TradeRobot.Business.RobotBusiness.GetRobotList(System.Nullable{System.Int64},System.String,System.Nullable{Binance.TradeRobot.Model.Base.Enums.RobotState},System.Nullable{Binance.TradeRobot.Model.Base.Enums.Exchange})">
<summary>
查询机器人基本信息
</summary>
<param name="robotId">如果robotId有值,将忽略其他条件</param>
<param name="symbol"></param>
<param name="robotState"></param>
<param name="exchange"></param>
<returns></returns>
</member>
<member name="M:Binance.TradeRobot.Business.RobotBusiness.GetD21PolicyRobotList(System.Nullable{Binance.TradeRobot.Model.Base.Enums.RobotState},System.Nullable{Binance.TradeRobot.Model.Base.Enums.SignalPeriod},System.String,System.Boolean,System.Boolean)">
<summary>
获取动2.1策略机器人列表
@ -81,5 +91,29 @@
<param name="userList"></param>
<param name="multiplyBy100">比例乘100</param>
</member>
<member name="M:Binance.TradeRobot.Business.GlobalContext.SubscribeKLine(Binance.TradeRobot.Model.Dto.RobotResponse)">
<summary>
订阅K线
</summary>
<param name="robot"></param>
</member>
<member name="M:Binance.TradeRobot.Business.GlobalContext.SubscribeOrderPublish(Binance.TradeRobot.Model.Dto.RobotResponse)">
<summary>
订阅订单推送
</summary>
<param name="robot"></param>
</member>
<member name="M:Binance.TradeRobot.Business.GlobalContext.UnSubscribeKLine(Binance.TradeRobot.Model.Dto.RobotResponse)">
<summary>
取消订阅K线
</summary>
<param name="robot"></param>
</member>
<member name="M:Binance.TradeRobot.Business.GlobalContext.UnSubscribeOrderPublish(Binance.TradeRobot.Model.Dto.RobotResponse)">
<summary>
取消订阅订单推送
</summary>
<param name="robot"></param>
</member>
</members>
</doc>

59
Binance.TradeRobot.Business/Business/RobotBusiness.cs

@ -9,6 +9,7 @@ using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using Yitter.IdGenerator;
namespace Binance.TradeRobot.Business
@ -16,9 +17,11 @@ namespace Binance.TradeRobot.Business
[BatchRegistration(ServiceLifetime.Singleton, RegistrationType.Self)]
public class RobotBusiness : BaseBusiness
{
public RobotBusiness(IFreeSql fsql, NLogManager logManager, IIdGenerator idGenerator, IMemoryCache memoryCache) : base(fsql, logManager, idGenerator, memoryCache)
{
private GlobalContext globalContext;
public RobotBusiness(IFreeSql fsql, NLogManager logManager, IIdGenerator idGenerator, IMemoryCache memoryCache, GlobalContext globalContext) : base(fsql, logManager, idGenerator, memoryCache)
{
this.globalContext = globalContext;
}
/// <summary>
@ -49,15 +52,23 @@ namespace Binance.TradeRobot.Business
public void StartRobot(long robotId)
{
fsql.Update<Robot>(robotId).Set(r => r.State, Enums.RobotState.Runing).ExecuteAffrows();
//监听K线和订单
var robot = GetRobotList(robotId).FirstOrDefault();
}
//监听K线和订单
globalContext.SubscribeKLine(robot);
}
public void StopRobot(long robotId)
{
var robot = GetRobotList(robotId).FirstOrDefault();
fsql.Update<Robot>(robotId).Set(r => r.State, Enums.RobotState.Stop).ExecuteAffrows();
//取消监听K线和订单
var sameRunningCount = GetRobotList(symbol: robot.Symbol, robotState: Enums.RobotState.Runing, exchange: robot.ExchangeId).Count();
if (sameRunningCount == 0)
{
//取消监听K线和订单
globalContext.UnSubscribeKLine(robot);
}
}
/// <summary>
@ -135,6 +146,44 @@ namespace Binance.TradeRobot.Business
});
}
/// <summary>
/// 查询机器人基本信息
/// </summary>
/// <param name="robotId">如果robotId有值,将忽略其他条件</param>
/// <param name="symbol"></param>
/// <param name="robotState"></param>
/// <param name="exchange"></param>
/// <returns></returns>
public IList<RobotResponse> GetRobotList(long? robotId = null,
string symbol = "",
Enums.RobotState? robotState = null,
Enums.Exchange? exchange = null)
{
var select = fsql.Select<Robot, ExchangeAPIKey>().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<IList<RobotResponse>>();
}
/// <summary>
/// 获取动2.1策略机器人列表
/// </summary>

58
Binance.TradeRobot.Business/GlobalContext.cs

@ -1,14 +1,66 @@
using Binance.TradeRobot.Common.DI;
using Binance.TradeRobot.Model.Dto;
using Microsoft.Extensions.DependencyInjection;
using SDKAdapter.WebSockets.Market;
using System.Collections.Generic;
namespace Binance.TradeRobot.Business
{
[BatchRegistration(ServiceLifetime.Singleton, RegistrationType.Self)]
public class GlobalContext
{
public GlobalContext()
{
private NLogManager logManager;
private IDictionary<string, SpotMarketWebSocketClient> spotMarketWebSocketClientDictionary;
public GlobalContext(NLogManager logManager)
{
this.logManager = logManager;
spotMarketWebSocketClientDictionary = new Dictionary<string, SpotMarketWebSocketClient>();
}
/// <summary>
/// 订阅K线
/// </summary>
/// <param name="robot"></param>
public void SubscribeKLine(RobotResponse robot)
{
if (!spotMarketWebSocketClientDictionary.TryGetValue(robot.KLineKey, out SpotMarketWebSocketClient spotMarketWebSocketClient))
{
var loggerName = $"SpotKLine-{robot.ExchangeId}-{robot.Symbol}";
spotMarketWebSocketClient = SpotMarketWebSocketClient.Create(robot.ExchangeId, robot.Symbol, logManager.GetLogger(loggerName));
spotMarketWebSocketClientDictionary.TryAdd(robot.KLineKey, spotMarketWebSocketClient);
}
if (!spotMarketWebSocketClient.IsConnected)
spotMarketWebSocketClient.Start();
}
/// <summary>
/// 订阅订单推送
/// </summary>
/// <param name="robot"></param>
public void SubscribeOrderPublish(RobotResponse robot)
{
}
/// <summary>
/// 取消订阅K线
/// </summary>
/// <param name="robot"></param>
public void UnSubscribeKLine(RobotResponse robot)
{
//停止订阅k线
if (spotMarketWebSocketClientDictionary.TryGetValue(robot.KLineKey, out SpotMarketWebSocketClient spotMarketWebSocketClient))
spotMarketWebSocketClient.Stop();
}
/// <summary>
/// 取消订阅订单推送
/// </summary>
/// <param name="robot"></param>
public void UnSubscribeOrderPublish(RobotResponse robot)
{
}
}
}

4
Binance.TradeRobot.Model/Dto/Response/Robot/RobotResponse.cs

@ -22,6 +22,10 @@ namespace Binance.TradeRobot.Model.Dto
public Enums.Exchange ExchangeId { get; set; }
public string ExecuteLogKey { get { return $"Execute-{ExchangeId}-{TradePolicy}-{Symbol}"; } }
public string KLineKey { get { return $"KLine-{ExchangeId}-{Symbol}"; }}
/// <summary>
/// 机器人账户对象
/// </summary>

5
SDKAdapter/SDKAdapter.csproj

@ -10,7 +10,12 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Binance.Net" Version="8.0.13" />
<PackageReference Include="NLog" Version="4.7.13" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Binance.TradeRobot.Model\Binance.TradeRobot.Model.csproj" />
</ItemGroup>
</Project>

36
SDKAdapter/WebSockets/Market/BinanceSpotMarketWebSocketClient.cs

@ -0,0 +1,36 @@
using Binance.Net.Clients;
using Binance.Net.Enums;
using System.Threading;
namespace SDKAdapter.WebSockets.Market
{
public class BinanceSpotMarketWebSocketClient : SpotMarketWebSocketClient
{
private BinanceSocketClient client;
private CancellationTokenSource cancellationTokenSource;
public BinanceSpotMarketWebSocketClient(string symbol, NLog.ILogger logger) : base(symbol, logger)
{
client = new BinanceSocketClient();
}
public override void Start()
{
cancellationTokenSource = new CancellationTokenSource();
client.SpotStreams.SubscribeToKlineUpdatesAsync(Symbol, KlineInterval.OneMinute, (e) =>
{
base.OnReceived(e.Data.Data.ClosePrice);
}, cancellationTokenSource.Token);
base.Start();
}
public override void Stop()
{
cancellationTokenSource.Cancel();
client.SpotStreams.Dispose();
base.Stop();
cancellationTokenSource = null;
}
}
}

14
SDKAdapter/WebSockets/Market/GateIOSpotMarketWebSocketClient.cs

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SDKAdapter.WebSockets.Market
{
public class GateIOSpotMarketWebSocketClient : SpotMarketWebSocketClient
{
public GateIOSpotMarketWebSocketClient(string symbol, NLog.ILogger logger) : base(symbol, logger)
{
}
}
}

20
SDKAdapter/WebSockets/Market/SpotMarketWebSocketClient.cs

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
using Binance.TradeRobot.Model.Base;
using System;
namespace SDKAdapter.WebSockets.Market
{
@ -19,7 +18,7 @@ namespace SDKAdapter.WebSockets.Market
/// <summary>
/// 最新成交价
/// </summary>
public decimal NewestPrice { get; private set; }
public decimal NewestPrice { get; protected set; }
/// <summary>r
/// 上一次价格更新时间
@ -28,6 +27,8 @@ namespace SDKAdapter.WebSockets.Market
public NLog.ILogger logger { get; private set; }
public bool IsConnected { get; protected set; }
public SpotMarketWebSocketClient(string symbol, NLog.ILogger logger)
{
this.Symbol = symbol;
@ -36,12 +37,12 @@ namespace SDKAdapter.WebSockets.Market
public virtual void Start()
{
IsConnected = true;
}
public virtual void Stop()
{
IsConnected = false;
}
protected virtual void OnReceived(decimal newestPrice)
@ -53,5 +54,12 @@ namespace SDKAdapter.WebSockets.Market
LastUpdateTime = DateTime.Now;
}
}
public static SpotMarketWebSocketClient Create(Enums.Exchange exchange, string symbol, NLog.ILogger logger)
{
if (exchange == Enums.Exchange.Binance)
return new BinanceSpotMarketWebSocketClient(symbol, logger);
return null;
}
}
}

Loading…
Cancel
Save