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; namespace Binance.TradeRobot.Business.Exchange { [BatchRegistration(ServiceLifetime.Singleton, RegistrationType.Self)] public class ExchangeBusiness : BaseBusiness { 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) { if (addExchangeAccountRequest.Id == 0 || string.IsNullOrEmpty(addExchangeAccountRequest.LoginName) || string.IsNullOrEmpty(addExchangeAccountRequest.APIKey) || string.IsNullOrEmpty(addExchangeAccountRequest.SecretKey)) throw new BusinessException("交易所账号参数有误"); if (fsql.Select(addExchangeAccountRequest.Id).Any()) throw new BusinessException("交易所账号重复"); if (fsql.Select().Where(k => k.APIKey == addExchangeAccountRequest.APIKey || k.SecretKey == addExchangeAccountRequest.SecretKey).Any()) throw new BusinessException("重复的APIKey或SecretKey"); var exchangeAccount = addExchangeAccountRequest.Map(); exchangeAccount.BusinessType = addExchangeAccountRequest.TradePolicy.GetBusinessType(); var exchangeAPIKey = new ExchangeAPIKey() { Id = idGenerator.NewLong(), AccountId = addExchangeAccountRequest.Id, APIKey = addExchangeAccountRequest.APIKey, SecretKey = addExchangeAccountRequest.SecretKey }; fsql.Transaction(() => { fsql.Insert(exchangeAPIKey).ExecuteAffrows(); fsql.Insert(exchangeAccount).ExecuteAffrows(); }); } public void AddExchangeAPIKey(AddExchangeAPIKeyRequest addExchangeAPIKeyRequest) { if (addExchangeAPIKeyRequest.AccountId == 0 || string.IsNullOrEmpty(addExchangeAPIKeyRequest.APIKey) || string.IsNullOrEmpty(addExchangeAPIKeyRequest.SecretKey)) throw new BusinessException("参数有误"); if (fsql.Select().Where(k => k.APIKey == addExchangeAPIKeyRequest.APIKey || k.SecretKey == addExchangeAPIKeyRequest.SecretKey).Any()) throw new BusinessException("重复的APIKey或SecretKey"); var exchangeAPIKey = addExchangeAPIKeyRequest.Map(); exchangeAPIKey.Id = idGenerator.NewLong(); fsql.Insert(exchangeAPIKey).ExecuteAffrows(); } public IList GetExchangeAccountList(Enums.TradePolicy tradePolicy) { var exchangeAccountList = fsql.Select().Where(ea => ea.TradePolicy == tradePolicy).ToList().Map>(); var accountIdList = exchangeAccountList.Select(ea => ea.Id); var exchangeAPIKeyList = fsql.Select().LeftJoin((k, r) => k.RobotId == r.Id) .Where((k, r) => accountIdList.Contains(k.AccountId)) .ToList((k, r) => new ExchangeAPIKeyResponse() { Id = k.Id, AccountId = k.AccountId, APIKey = k.APIKey, SecretKey = k.SecretKey, CreateTime = k.CreateTime, RobotId = k.RobotId, RobotSymbol = r.Symbol }); var waitList = new List(); foreach (var exchangeAccount in exchangeAccountList) { var currentExchangeAccountAPIKeyList = exchangeAPIKeyList.Where(k => k.AccountId == exchangeAccount.Id); if (currentExchangeAccountAPIKeyList.Count() == 0) continue; exchangeAccount.ExchangeAPIKeyList.AddRange(currentExchangeAccountAPIKeyList); var ewh = new ManualResetEvent(false); waitList.Add(ewh); Task.Factory.StartNew(() => GetExchangeAssets(exchangeAccount, ewh)); } WaitHandle.WaitAll(waitList.ToArray(), 5000); return exchangeAccountList; } private void GetExchangeAssets(ExchangeAccountResponse exchangeAccount, EventWaitHandle ewh) { try { var firstAPIKey = exchangeAccount.ExchangeAPIKeyList.FirstOrDefault(); var apiClient = GetBaseAPIClient(exchangeAccount.ExchangeId, exchangeAccount.Id, firstAPIKey.APIKey, firstAPIKey.SecretKey); if (exchangeAccount.BusinessType == Enums.BusinessType.UPrep) { //var result = binanceClient.UsdFuturesApi.Account.GetBalancesAsync().Result; //if (result.Success) //{ // exchangeAccount.UPrepUSDT = result.Data.FirstOrDefault(b => b.Asset == "USDT")?.WalletBalance ?? 0; //} } else if (exchangeAccount.BusinessType == Enums.BusinessType.Spot) { } else if (exchangeAccount.BusinessType == Enums.BusinessType.Spot_Margin) { var isolatedMarginAccountAssetList = apiClient.GetIsolatedMarginAccountAssets(); foreach (var apiKey in exchangeAccount.ExchangeAPIKeyList) { if (apiKey.RobotId == null) continue; var asset = isolatedMarginAccountAssetList.FirstOrDefault(s => s.Symbol == apiKey.RobotSymbol); if (asset != null) { apiKey.BaseAmount = asset.BaseFree; apiKey.QuoteAmount = asset.QuoteFree; apiKey.QuoteNetAmount = asset.QuoteNetAsset; apiKey.QuoteLoanAmount = asset.QuoteBorrowed; } } } } catch (Exception ex) { } finally { foreach (var apiKey in exchangeAccount.ExchangeAPIKeyList) apiKey.SecretKey = string.Empty; ewh.Set(); } } /// /// 获取APIKey未使用交易所账户列表 /// /// /// /// public IList GetNoUsedExchangeAccountList(Enums.TradePolicy tradePolicy, Enums.Exchange exchangeId) { var exchangeAccountList = fsql.Select().Where(ea => ea.TradePolicy == tradePolicy && ea.ExchangeId == exchangeId) .ToList().Map>(); var accountIdList = exchangeAccountList.Select(ea => ea.Id); var exchangeAPIKeyList = fsql.Select().Where(k => k.RobotId == null && accountIdList.Contains(k.AccountId)) .ToList() .Map>(); foreach (var exchangeAccount in exchangeAccountList) { var currentExchangeAccountAPIKeyList = exchangeAPIKeyList.Where(k => k.AccountId == exchangeAccount.Id); if (currentExchangeAccountAPIKeyList.Count() == 0) continue; exchangeAccount.ExchangeAPIKeyList.AddRange(currentExchangeAccountAPIKeyList); } return exchangeAccountList; } } }