diff --git a/Binance.TradeRobot.API/Startup.cs b/Binance.TradeRobot.API/Startup.cs
index 46d507d..1238fa8 100644
--- a/Binance.TradeRobot.API/Startup.cs
+++ b/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);
+ }
}
}
}
diff --git a/Binance.TradeRobot.Business/Binance.TradeRobot.Business.csproj b/Binance.TradeRobot.Business/Binance.TradeRobot.Business.csproj
index 2050c2c..2f34003 100644
--- a/Binance.TradeRobot.Business/Binance.TradeRobot.Business.csproj
+++ b/Binance.TradeRobot.Business/Binance.TradeRobot.Business.csproj
@@ -8,6 +8,7 @@
+
@@ -20,6 +21,7 @@
+
diff --git a/Binance.TradeRobot.Business/Binance.TradeRobot.Business.xml b/Binance.TradeRobot.Business/Binance.TradeRobot.Business.xml
index e83cd9e..2daae90 100644
--- a/Binance.TradeRobot.Business/Binance.TradeRobot.Business.xml
+++ b/Binance.TradeRobot.Business/Binance.TradeRobot.Business.xml
@@ -40,6 +40,16 @@
+
+
+ 查询机器人基本信息
+
+ 如果robotId有值,将忽略其他条件
+
+
+
+
+
获取动2.1策略机器人列表
@@ -81,5 +91,29 @@
比例乘100
+
+
+ 订阅K线
+
+
+
+
+
+ 订阅订单推送
+
+
+
+
+
+ 取消订阅K线
+
+
+
+
+
+ 取消订阅订单推送
+
+
+
diff --git a/Binance.TradeRobot.Business/Business/RobotBusiness.cs b/Binance.TradeRobot.Business/Business/RobotBusiness.cs
index 9602550..186baa2 100644
--- a/Binance.TradeRobot.Business/Business/RobotBusiness.cs
+++ b/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;
}
///
@@ -49,15 +52,23 @@ namespace Binance.TradeRobot.Business
public void StartRobot(long robotId)
{
fsql.Update(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(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);
+ }
}
///
@@ -135,6 +146,44 @@ namespace Binance.TradeRobot.Business
});
}
+ ///
+ /// 查询机器人基本信息
+ ///
+ /// 如果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策略机器人列表
///
diff --git a/Binance.TradeRobot.Business/GlobalContext.cs b/Binance.TradeRobot.Business/GlobalContext.cs
index 5c66ea7..fbcec25 100644
--- a/Binance.TradeRobot.Business/GlobalContext.cs
+++ b/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 spotMarketWebSocketClientDictionary;
+
+ public GlobalContext(NLogManager logManager)
+ {
+ this.logManager = logManager;
+ spotMarketWebSocketClientDictionary = new Dictionary();
+ }
+
+ ///
+ /// 订阅K线
+ ///
+ ///
+ 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();
+ }
+
+ ///
+ /// 订阅订单推送
+ ///
+ ///
+ public void SubscribeOrderPublish(RobotResponse robot)
+ {
+
+ }
+
+ ///
+ /// 取消订阅K线
+ ///
+ ///
+ public void UnSubscribeKLine(RobotResponse robot)
+ {
+ //停止订阅k线
+ if (spotMarketWebSocketClientDictionary.TryGetValue(robot.KLineKey, out SpotMarketWebSocketClient spotMarketWebSocketClient))
+ spotMarketWebSocketClient.Stop();
+ }
+
+ ///
+ /// 取消订阅订单推送
+ ///
+ ///
+ public void UnSubscribeOrderPublish(RobotResponse robot)
+ {
+
}
}
}
diff --git a/Binance.TradeRobot.Model/Dto/Response/Robot/RobotResponse.cs b/Binance.TradeRobot.Model/Dto/Response/Robot/RobotResponse.cs
index 29d80ad..96618d0 100644
--- a/Binance.TradeRobot.Model/Dto/Response/Robot/RobotResponse.cs
+++ b/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}"; }}
+
///
/// 机器人账户对象
///
diff --git a/SDKAdapter/SDKAdapter.csproj b/SDKAdapter/SDKAdapter.csproj
index ca327b0..8f07c50 100644
--- a/SDKAdapter/SDKAdapter.csproj
+++ b/SDKAdapter/SDKAdapter.csproj
@@ -10,7 +10,12 @@
+
+
+
+
+
diff --git a/SDKAdapter/WebSockets/Market/BinanceSpotMarketWebSocketClient.cs b/SDKAdapter/WebSockets/Market/BinanceSpotMarketWebSocketClient.cs
new file mode 100644
index 0000000..687c518
--- /dev/null
+++ b/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;
+ }
+ }
+}
diff --git a/SDKAdapter/WebSockets/Market/GateIOSpotMarketWebSocketClient.cs b/SDKAdapter/WebSockets/Market/GateIOSpotMarketWebSocketClient.cs
new file mode 100644
index 0000000..497bb14
--- /dev/null
+++ b/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)
+ {
+
+ }
+ }
+}
diff --git a/SDKAdapter/WebSockets/Market/SpotMarketWebSocketClient.cs b/SDKAdapter/WebSockets/Market/SpotMarketWebSocketClient.cs
index b33a71b..8c275d4 100644
--- a/SDKAdapter/WebSockets/Market/SpotMarketWebSocketClient.cs
+++ b/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
///
/// 最新成交价
///
- public decimal NewestPrice { get; private set; }
+ public decimal NewestPrice { get; protected set; }
/// 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;
+ }
}
}