From e191b6606d81862e1754618122020cf0eec20bab Mon Sep 17 00:00:00 2001 From: shanj <18996038927@163.com> Date: Sun, 15 May 2022 01:08:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=B9=E6=8E=A5=E4=BA=A4=E6=98=93=E6=89=80?= =?UTF-8?q?=E4=BA=A4=E6=98=93=E5=AF=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 6 ++ .../Binance.TradeRobot.API.xml | 19 +++- .../Controllers/ExchangeAccountController.cs | 31 +++++++ .../Controllers/SingalController.cs | 4 +- .../Business/ExchangeBusiness.cs | 56 ++++++++++- .../Business/RobotBusiness.cs | 92 ++++++++++--------- .../Business/SingalBusiness.cs | 2 +- .../Http/RestAPIService.cs | 65 +++++++++---- .../Base/MappingProfiles.cs | 6 +- .../Binance.TradeRobot.Model.xml | 10 ++ .../Db/Exchange/SymbolInfo.cs | 32 +++++++ Binance.TradeRobot.Model/Db/Robot/Robot.cs | 11 +++ .../Db/代码生成/__重新生成.bat | 2 +- .../Response/Exchange/SymbolInfoResponse.cs | 8 ++ .../Dto/Response/Robot/RobotResponse.cs | 2 + 15 files changed, 275 insertions(+), 71 deletions(-) create mode 100644 Binance.TradeRobot.Model/Db/Exchange/SymbolInfo.cs create mode 100644 Binance.TradeRobot.Model/Dto/Response/Exchange/SymbolInfoResponse.cs diff --git a/.editorconfig b/.editorconfig index 9405a89..43784d5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,3 +14,9 @@ dotnet_diagnostic.CS8602.severity = none # CS8603: 可能返回 null 引用。 dotnet_diagnostic.CS8603.severity = none + +# CS8600: 将 null 字面量或可能为 null 的值转换为非 null 类型。 +dotnet_diagnostic.CS8600.severity = none + +# CS8601: 引用类型赋值可能为 null。 +dotnet_diagnostic.CS8601.severity = none diff --git a/Binance.TradeRobot.API/Binance.TradeRobot.API.xml b/Binance.TradeRobot.API/Binance.TradeRobot.API.xml index 4ea2d4d..6283bb2 100644 --- a/Binance.TradeRobot.API/Binance.TradeRobot.API.xml +++ b/Binance.TradeRobot.API/Binance.TradeRobot.API.xml @@ -4,6 +4,23 @@ Binance.TradeRobot.API + + + 同步币安交易对 + + + + + 同步Gate.IO交易对 + + + + + 获取交易对列表 + + + + 添加交易所账号 @@ -61,7 +78,7 @@ - + D21杠杆/合约信号接口 diff --git a/Binance.TradeRobot.API/Controllers/ExchangeAccountController.cs b/Binance.TradeRobot.API/Controllers/ExchangeAccountController.cs index 416783f..8caef1a 100644 --- a/Binance.TradeRobot.API/Controllers/ExchangeAccountController.cs +++ b/Binance.TradeRobot.API/Controllers/ExchangeAccountController.cs @@ -18,6 +18,37 @@ namespace Binance.TradeRobot.API.Controllers this.exchangeBusiness = exchangeBusiness; } + /// + /// 同步币安交易对 + /// + [HttpPost] + [AllowAnonymous] + public void SyncBinanceSymbol() + { + exchangeBusiness.SyncBinanceSymbol(); + } + + /// + /// 同步Gate.IO交易对 + /// + [HttpPost] + [AllowAnonymous] + public void SyncGateIOSymbol() + { + exchangeBusiness.SyncGateIOSymbol(); + } + + /// + /// 获取交易对列表 + /// + /// + /// + [HttpGet("{exchange}")] + public IList GetSymbolList(Enums.Exchange exchange) + { + return exchangeBusiness.GetSymbolList(exchange); + } + /// /// 添加交易所账号 /// diff --git a/Binance.TradeRobot.API/Controllers/SingalController.cs b/Binance.TradeRobot.API/Controllers/SingalController.cs index b0fd552..36b46a5 100644 --- a/Binance.TradeRobot.API/Controllers/SingalController.cs +++ b/Binance.TradeRobot.API/Controllers/SingalController.cs @@ -18,9 +18,9 @@ namespace Binance.TradeRobot.API.Controllers /// /// [HttpPost] - public void D21Singnal([FromBody] D21SingalRequest d21SingalRequest) + public void D21Singal([FromBody] D21SingalRequest d21SingalRequest) { - singalBusiness.D21Singnal(d21SingalRequest); + singalBusiness.D21Singal(d21SingalRequest); } } } diff --git a/Binance.TradeRobot.Business/Business/ExchangeBusiness.cs b/Binance.TradeRobot.Business/Business/ExchangeBusiness.cs index b476e30..7360e7c 100644 --- a/Binance.TradeRobot.Business/Business/ExchangeBusiness.cs +++ b/Binance.TradeRobot.Business/Business/ExchangeBusiness.cs @@ -1,14 +1,17 @@ using Binance.TradeRobot.Business.Extensions; using Binance.TradeRobot.Common.DI; using Binance.TradeRobot.Common.Extensions; +using Binance.TradeRobot.Common.Http; using Binance.TradeRobot.Model.Base; using Binance.TradeRobot.Model.Db; using Binance.TradeRobot.Model.Dto; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Yitter.IdGenerator; @@ -18,7 +21,58 @@ namespace Binance.TradeRobot.Business.Exchange [BatchRegistration(ServiceLifetime.Singleton, RegistrationType.Self)] public class ExchangeBusiness : BaseBusiness { - public ExchangeBusiness(IFreeSql fsql, NLogManager logManager, IIdGenerator idGenerator, IMemoryCache memoryCache) : base(fsql, logManager, idGenerator, memoryCache) { } + private RestApiService restApiService; + + public ExchangeBusiness(IFreeSql fsql, + NLogManager logManager, + IIdGenerator idGenerator, + IMemoryCache memoryCache, + RestApiService restApiService) : base(fsql, logManager, idGenerator, memoryCache) + { + this.restApiService = restApiService; + } + + public void SyncBinanceSymbol() + { + var apiResult = restApiService.SendRequest("https://api.binance.com/", "api/v3/exchangeInfo", null, null, HttpMethod.Get); + if (apiResult.StatusCode != System.Net.HttpStatusCode.OK) + throw new BusinessException($"同步币安交易对失败 StatusCode {apiResult.StatusCode} {apiResult.Content}"); + var jobject = JObject.Parse(apiResult.Content); + var jarray_symbols = (JArray)jobject["symbols"]; + var symbolList = new List(); + foreach (JToken jtoken_symbol in jarray_symbols) + { + var symbol = jtoken_symbol.Value("symbol").ToUpper(); + if (!symbol.EndsWith("USDT")) + continue; + var stepSize = jtoken_symbol["filters"]?.FirstOrDefault(jtoken_filters => jtoken_filters.Value("filterType") == "LOT_SIZE")?.Value("stepSize") ?? 0M; + var saleAccuracy = stepSize != 0 ? (1 / stepSize).ToString().Length - 1 : 0; + var symbolInfo = new SymbolInfo() + { + Id = idGenerator.NewLong(), + ExchangeId = Enums.Exchange.Binance, + CreateTime = DateTime.Now, + Symbol = symbol, + SaleQuantityAccuracy = saleAccuracy + }; + symbolList.Add(symbolInfo); + } + fsql.Transaction(() => + { + fsql.Delete().Where(s => s.ExchangeId == Enums.Exchange.Binance).ExecuteAffrows(); + fsql.Insert(symbolList).ExecuteAffrows(); + }); + } + + public void SyncGateIOSymbol() + { + + } + + public IList GetSymbolList(Enums.Exchange exchange) + { + return fsql.Select().Where(s => s.ExchangeId == exchange).ToList(); + } public void AddExchangeAccount(AddExchangeAccountRequest addExchangeAccountRequest) { diff --git a/Binance.TradeRobot.Business/Business/RobotBusiness.cs b/Binance.TradeRobot.Business/Business/RobotBusiness.cs index 067809a..20ac87d 100644 --- a/Binance.TradeRobot.Business/Business/RobotBusiness.cs +++ b/Binance.TradeRobot.Business/Business/RobotBusiness.cs @@ -56,7 +56,7 @@ namespace Binance.TradeRobot.Business //监听K线和订单 globalContext.SubscribeKLine(robot); - } + } public void StopRobot(long robotId) { @@ -199,52 +199,56 @@ namespace Binance.TradeRobot.Business bool isLoadRecentTradeProfit = true, bool isLoadAPIKey = false) { - var robotList = fsql.Select().InnerJoin((r, ra, d, e) => r.Id == ra.RobotId) - .InnerJoin((r, ra, d, e) => r.Id == d.RobotId) - .InnerJoin((r, ra, d, e) => r.Id == e.RobotId) - .WhereIf(robotState != null, (r, ra, d, e) => r.State == robotState) - .WhereIf(signalPeriod != null, (r, ra, d, e) => d.PeriodicSignal == signalPeriod) - .WhereIf(!string.IsNullOrEmpty(symbol), (r, ra, d, e) => r.Symbol == symbol) - .Where((r, ra, d, e) => r.TradePolicy == Enums.TradePolicy.D21) - .ToList((r, ra, d, 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, + var robotList = fsql.Select().InnerJoin((r, s, ra, d, e) => r.Id == ra.RobotId) + .InnerJoin((r, s, ra, d, e) => r.Symbol == s.Symbol && r.ExchangeId == s.ExchangeId) + .InnerJoin((r, s, ra, d, e) => r.Id == d.RobotId) + .InnerJoin((r, s, ra, d, e) => r.Id == e.RobotId) + .WhereIf(robotState != null, (r, s, ra, d, e) => r.State == robotState) + .WhereIf(signalPeriod != null, (r, s, ra, d, e) => d.PeriodicSignal == signalPeriod) + .WhereIf(!string.IsNullOrEmpty(symbol), (r, s, ra, d, e) => r.Symbol == symbol) + .Where((r, s, ra, d, e) => r.TradePolicy == Enums.TradePolicy.D21) + .ToList((r, s, ra, d, 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, + + SymbolId = s.Id, + SymbolSaleQuantityAccuracy = s.SaleQuantityAccuracy, - RobotAccountId = ra.Id, - ClosePositionCount = ra.ClosePositionCount, - WinCount = ra.WinCount, - LoanAmount = ra.LoanAmount, - SoptCurrentcyAmount = ra.SoptCurrentcyAmount, - SpotCurrencyQuantity = ra.SpotCurrencyQuantity, - TotalProfit = ra.TotalProfit, + RobotAccountId = ra.Id, + ClosePositionCount = ra.ClosePositionCount, + WinCount = ra.WinCount, + LoanAmount = ra.LoanAmount, + SoptCurrentcyAmount = ra.SoptCurrentcyAmount, + SpotCurrencyQuantity = ra.SpotCurrencyQuantity, + TotalProfit = ra.TotalProfit, - ExchangeAccountId = e.AccountId, - ExchangeAPIKey = e.APIKey, - ExchangeSecretKey = e.SecretKey, + ExchangeAccountId = e.AccountId, + ExchangeAPIKey = e.APIKey, + ExchangeSecretKey = e.SecretKey, - D21ExecutionMode = d.ExecutionMode, - D21IsEnabledIncreasePurchase = d.IsEnabledIncreasePurchase, - D21IsEnableRemedyForErrorCrossSignal = d.IsEnableRemedyForErrorCrossSignal, - D21MaxFollowPurchaseRatio = d.MaxFollowPurchaseRatio, - D21PeriodicSignal = d.PeriodicSignal, - D21PolicyId = d.Id, - D21Position = d.Position, - D21Assets = d.Assets, - D21Level1PositionStopLossRatio = d.Level1PositionStopLossRatio, - D21Level1PriceStopLossRatio = d.Level1PriceStopLossRatio, - D21Level2PositionStopLossRatio = d.Level2PositionStopLossRatio, - D21Level2PriceStopLossRatio = d.Level2PriceStopLossRatio, - D21MaxExchangeLoanRatio = d.MaxExchangeLoanRatio, - D21MaxSystemLoanRatio = d.MaxSystemLoanRatio, - D21CreateTime = d.CreateTime - }).Map>(); + D21ExecutionMode = d.ExecutionMode, + D21IsEnabledIncreasePurchase = d.IsEnabledIncreasePurchase, + D21IsEnableRemedyForErrorCrossSignal = d.IsEnableRemedyForErrorCrossSignal, + D21MaxFollowPurchaseRatio = d.MaxFollowPurchaseRatio, + D21PeriodicSignal = d.PeriodicSignal, + D21PolicyId = d.Id, + D21Position = d.Position, + D21Assets = d.Assets, + D21Level1PositionStopLossRatio = d.Level1PositionStopLossRatio, + D21Level1PriceStopLossRatio = d.Level1PriceStopLossRatio, + D21Level2PositionStopLossRatio = d.Level2PositionStopLossRatio, + D21Level2PriceStopLossRatio = d.Level2PriceStopLossRatio, + D21MaxExchangeLoanRatio = d.MaxExchangeLoanRatio, + D21MaxSystemLoanRatio = d.MaxSystemLoanRatio, + D21CreateTime = d.CreateTime + }).Map>(); if (isLoadRecentTradeProfit) { //统计近期订单利润 diff --git a/Binance.TradeRobot.Business/Business/SingalBusiness.cs b/Binance.TradeRobot.Business/Business/SingalBusiness.cs index a0f0631..8c24e5e 100644 --- a/Binance.TradeRobot.Business/Business/SingalBusiness.cs +++ b/Binance.TradeRobot.Business/Business/SingalBusiness.cs @@ -27,7 +27,7 @@ namespace Binance.TradeRobot.Business.Business this.tradeBusinessList = tradeBusinessList; } - public void D21Singnal(D21SingalRequest d21SingalRequest) + public void D21Singal(D21SingalRequest d21SingalRequest) { //logManager.GetLogger("D21").Info(JsonConvert.SerializeObject(d21SingalRequest)); var robotList = robotBusiness.GetD21PolicyRobotList(Enums.RobotState.Runing, d21SingalRequest.KLinePeriodic, d21SingalRequest.Symbol, false, true); diff --git a/Binance.TradeRobot.Common/Http/RestAPIService.cs b/Binance.TradeRobot.Common/Http/RestAPIService.cs index 9184d8a..8ee735e 100644 --- a/Binance.TradeRobot.Common/Http/RestAPIService.cs +++ b/Binance.TradeRobot.Common/Http/RestAPIService.cs @@ -2,7 +2,9 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; +using System.Net; using System.Net.Http; +using System.Net.Http.Headers; using System.Text; namespace Binance.TradeRobot.Common.Http @@ -26,27 +28,34 @@ namespace Binance.TradeRobot.Common.Http /// /// /// - /// + /// /// /// /// - /// + /// + /// + /// + /// /// - public string SendRequest(string apiHost, - string apiPath, - object param, - IDictionary headers, - HttpMethod httpMethod, - string contentType = ContentType_Json, - ParamPosition paramPosition = ParamPosition.Body, - bool enableRandomTimeStamp = false) + public RestApiResult SendRequest(string apiHost, + string apiPath, + object param, + IDictionary requestHeaders, + HttpMethod httpMethod, + string contentType = ContentType_Json, + ParamPosition paramPosition = ParamPosition.Body, + bool useRandomTimeStamp = false, + bool getResponseHeader = false, + HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead, + string httpClientName = "") { //Get和Delete强制使用QueryString形式传参 if (httpMethod == HttpMethod.Get || httpMethod == HttpMethod.Delete) paramPosition = ParamPosition.Query; //拼接Url - var url = $"{apiHost}{(apiHost.EndsWith("/") ? string.Empty : "/")}{(apiPath.StartsWith("/") ? apiPath.Substring(1) : apiPath)}"; + var url = string.IsNullOrEmpty(apiPath) ? apiHost : + $"{apiHost.TrimEnd('/')}/{apiPath.TrimStart('/')}"; var isCombineParam = false; if (paramPosition == ParamPosition.Query && param != null) { @@ -55,8 +64,8 @@ namespace Binance.TradeRobot.Common.Http } //使用时间戳绕过CDN - if (enableRandomTimeStamp) - url = $"{url}{(isCombineParam ? "&" : "?")}t={DateTime.Now.DateTimeToStamp()}"; + if (useRandomTimeStamp) + url = $"{url}{(isCombineParam ? "&" : "?")}t={DateTime.Now.ToFileTime()}"; using (var httpClient = httpClientFactory.CreateClient()) @@ -64,22 +73,38 @@ namespace Binance.TradeRobot.Common.Http httpClient.Timeout = TimeOut; using (var request = new HttpRequestMessage(httpMethod, url)) { - if (headers != null && headers.Count > 0) - foreach (var key in headers.Keys) - request.Headers.Add(key, headers[key]); + if (requestHeaders != null && requestHeaders.Count > 0) + foreach (var key in requestHeaders.Keys) + request.Headers.Add(key, requestHeaders[key]); if (paramPosition == ParamPosition.Body && param != null) request.Content = new StringContent(contentType == ContentType_Json ? JsonConvert.SerializeObject(param) : param.ToString(), Encoding.UTF8, contentType); - using (var response = httpClient.SendAsync(request).Result) + using (var response = httpClient.SendAsync(request, httpCompletionOption).Result) { - if (!response.IsSuccessStatusCode) - throw new Exception($"HttpCode {response.StatusCode}"); - return response.Content.ReadAsStringAsync().Result; + if (!response.IsSuccessStatusCode && response.StatusCode != HttpStatusCode.Redirect && response.StatusCode != HttpStatusCode.Moved) + throw new Exception($"Reuqest {url} HttpCode {response.StatusCode}"); + return new RestApiResult() + { + StatusCode = response.StatusCode, + Content = httpCompletionOption == HttpCompletionOption.ResponseContentRead ? response.Content.ReadAsStringAsync().Result : + string.Empty, + Headers = getResponseHeader ? response.Headers : null + }; } } } } + + } + + public class RestApiResult + { + public HttpStatusCode StatusCode { get; set; } + + public string Content { get; set; } + + public HttpResponseHeaders Headers { get; set; } } /// diff --git a/Binance.TradeRobot.Model/Base/MappingProfiles.cs b/Binance.TradeRobot.Model/Base/MappingProfiles.cs index 97e3c2c..1167d20 100644 --- a/Binance.TradeRobot.Model/Base/MappingProfiles.cs +++ b/Binance.TradeRobot.Model/Base/MappingProfiles.cs @@ -26,7 +26,11 @@ namespace Binance.TradeRobot.Model.Base .ForPath(t => t.RobotAccount.WinCount, opt => opt.MapFrom(f => f.WinCount)) .ForPath(t => t.ExchangeAPIKey.AccountId, opt => opt.MapFrom(f => f.ExchangeAccountId)) .ForPath(t => t.ExchangeAPIKey.APIKey, opt => opt.MapFrom(f => f.ExchangeAPIKey)) - .ForPath(t => t.ExchangeAPIKey.SecretKey, opt => opt.MapFrom(f => f.ExchangeSecretKey)); + .ForPath(t => t.ExchangeAPIKey.SecretKey, opt => opt.MapFrom(f => f.ExchangeSecretKey)) + .ForPath(t => t.SymbolInfo.Id, opt => opt.MapFrom(f => f.SymbolId)) + .ForPath(t => t.SymbolInfo.Symbol, opt => opt.MapFrom(f => f.Symbol)) + .ForPath(t => t.SymbolInfo.SaleQuantityAccuracy, opt => opt.MapFrom(f => f.SymbolSaleQuantityAccuracy)) + .ForPath(t => t.SymbolInfo.ExchangeId, opt => opt.MapFrom(f => f.ExchangeId)); CreateMap().IncludeBase() .ForPath(t => t.D21Policy.Id, opt => opt.MapFrom(f => f.D21PolicyId)) .ForPath(t => t.D21Policy.RobotId, opt => opt.MapFrom(f => f.Id)) diff --git a/Binance.TradeRobot.Model/Binance.TradeRobot.Model.xml b/Binance.TradeRobot.Model/Binance.TradeRobot.Model.xml index 4807a02..6904c88 100644 --- a/Binance.TradeRobot.Model/Binance.TradeRobot.Model.xml +++ b/Binance.TradeRobot.Model/Binance.TradeRobot.Model.xml @@ -169,6 +169,11 @@ 关联机器人Id + + + 基础币卖出数量精度 + + 来源信号 @@ -339,6 +344,11 @@ 运行时长(s) + + + 卖币精度 + + 平仓次数 diff --git a/Binance.TradeRobot.Model/Db/Exchange/SymbolInfo.cs b/Binance.TradeRobot.Model/Db/Exchange/SymbolInfo.cs new file mode 100644 index 0000000..22e25df --- /dev/null +++ b/Binance.TradeRobot.Model/Db/Exchange/SymbolInfo.cs @@ -0,0 +1,32 @@ +using Binance.TradeRobot.Model.Base; +using FreeSql.DataAnnotations; +using System; + +namespace Binance.TradeRobot.Model.Db +{ + + [Table(Name = "symbolinfo", DisableSyncStructure = true)] + public partial class SymbolInfo + { + + [Column(DbType = "bigint", IsPrimary = true)] + public long Id { get; set; } + + [Column(DbType = "datetime")] + public DateTime? CreateTime { get; set; } + + [Column(DbType = "int", MapType = typeof(int))] + public Enums.Exchange ExchangeId { get; set; } + + /// + /// 基础币卖出数量精度 + /// + [Column(DbType = "int")] + public int SaleQuantityAccuracy { get; set; } + + [Column(StringLength = 50)] + public string Symbol { get; set; } + + } + +} diff --git a/Binance.TradeRobot.Model/Db/Robot/Robot.cs b/Binance.TradeRobot.Model/Db/Robot/Robot.cs index 53c8fbf..76cf1d8 100644 --- a/Binance.TradeRobot.Model/Db/Robot/Robot.cs +++ b/Binance.TradeRobot.Model/Db/Robot/Robot.cs @@ -36,6 +36,17 @@ namespace Binance.TradeRobot.Model.Db [Column(MapType = typeof(int), DbType = "int")] public Enums.Exchange ExchangeId { get; set; } + #region Symbol Extension + /// + /// 卖币精度 + /// + [Column(IsIgnore = true)] + public long SymbolId { get; set; } + + [Column(IsIgnore = true)] + public int SymbolSaleQuantityAccuracy { get; set; } + #endregion + #region RobotAccount Extension [Column(IsIgnore = true)] diff --git a/Binance.TradeRobot.Model/Db/代码生成/__重新生成.bat b/Binance.TradeRobot.Model/Db/代码生成/__重新生成.bat index 90a629a..8bb4fc9 100644 --- a/Binance.TradeRobot.Model/Db/代码生成/__重新生成.bat +++ b/Binance.TradeRobot.Model/Db/代码生成/__重新生成.bat @@ -1 +1 @@ -FreeSql.Generator -Razor 1 -NameOptions 1,0,0,0 -NameSpace Binance.TradeRobot.Model.Db -DB "MySql,data source=47.245.58.112;port=3306;user id=sa;password=rYn6re2AKhcDWcBi;initial catalog=tradedb;charset=utf8;sslmode=none;max pool size=2" -FileName "{name}.cs" +FreeSql.Generator -Razor 1 -NameOptions 1,0,0,0 -NameSpace Binance.TradeRobot.Model.Db -DB "MySql,data source=8.209.252.195;port=3306;user id=sa;password=rYn6re2AKhcDWcBi;initial catalog=tradedb;charset=utf8;sslmode=none;max pool size=2" -FileName "{name}.cs" diff --git a/Binance.TradeRobot.Model/Dto/Response/Exchange/SymbolInfoResponse.cs b/Binance.TradeRobot.Model/Dto/Response/Exchange/SymbolInfoResponse.cs new file mode 100644 index 0000000..3f4ac53 --- /dev/null +++ b/Binance.TradeRobot.Model/Dto/Response/Exchange/SymbolInfoResponse.cs @@ -0,0 +1,8 @@ +using Binance.TradeRobot.Model.Db; + +namespace Binance.TradeRobot.Model.Dto +{ + public class SymbolInfoResponse : SymbolInfo + { + } +} diff --git a/Binance.TradeRobot.Model/Dto/Response/Robot/RobotResponse.cs b/Binance.TradeRobot.Model/Dto/Response/Robot/RobotResponse.cs index c80a86c..8611609 100644 --- a/Binance.TradeRobot.Model/Dto/Response/Robot/RobotResponse.cs +++ b/Binance.TradeRobot.Model/Dto/Response/Robot/RobotResponse.cs @@ -26,6 +26,8 @@ namespace Binance.TradeRobot.Model.Dto public virtual string KLineKey { get { return $"KLine-{ExchangeId}-{Symbol}"; } } + public SymbolInfoResponse SymbolInfo { get; set; } + /// /// 机器人账户对象 ///