币安量化交易
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

228 lines
11 KiB

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<SymbolInfo>();
foreach (JToken jtoken_symbol in jarray_symbols)
{
var symbol = jtoken_symbol.Value<string>("symbol").ToUpper();
if (!symbol.EndsWith("USDT"))
continue;
var stepSize = jtoken_symbol["filters"]?.FirstOrDefault(jtoken_filters => jtoken_filters.Value<string>("filterType") == "LOT_SIZE")?.Value<decimal>("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<SymbolInfo>().Where(s => s.ExchangeId == Enums.Exchange.Binance).ExecuteAffrows();
fsql.Insert(symbolList).ExecuteAffrows();
});
}
public void SyncGateIOSymbol()
{
}
public IList<SymbolInfoResponse> GetSymbolList(Enums.Exchange exchange)
{
return fsql.Select<SymbolInfo>().Where(s => s.ExchangeId == exchange).ToList<SymbolInfoResponse>();
}
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<ExchangeAccount>(addExchangeAccountRequest.Id).Any())
throw new BusinessException("交易所账号重复");
if (fsql.Select<ExchangeAPIKey>().Where(k => k.APIKey == addExchangeAccountRequest.APIKey || k.SecretKey == addExchangeAccountRequest.SecretKey).Any())
throw new BusinessException("重复的APIKey或SecretKey");
var exchangeAccount = addExchangeAccountRequest.Map<ExchangeAccount>();
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<ExchangeAPIKey>().Where(k => k.APIKey == addExchangeAPIKeyRequest.APIKey || k.SecretKey == addExchangeAPIKeyRequest.SecretKey).Any())
throw new BusinessException("重复的APIKey或SecretKey");
var exchangeAPIKey = addExchangeAPIKeyRequest.Map<ExchangeAPIKey>();
exchangeAPIKey.Id = idGenerator.NewLong();
fsql.Insert(exchangeAPIKey).ExecuteAffrows();
}
public IList<ExchangeAccountResponse> GetExchangeAccountList(Enums.TradePolicy tradePolicy)
{
var exchangeAccountList = fsql.Select<ExchangeAccount>().Where(ea => ea.TradePolicy == tradePolicy).ToList().Map<IList<ExchangeAccountResponse>>();
var accountIdList = exchangeAccountList.Select(ea => ea.Id);
var exchangeAPIKeyList = fsql.Select<ExchangeAPIKey, Robot>().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<WaitHandle>();
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();
}
}
/// <summary>
/// 获取APIKey未使用交易所账户列表
/// </summary>
/// <param name="tradePolicy"></param>
/// <param name="exchangeId"></param>
/// <returns></returns>
public IList<ExchangeAccountResponse> GetNoUsedExchangeAccountList(Enums.TradePolicy tradePolicy, Enums.Exchange exchangeId)
{
var exchangeAccountList = fsql.Select<ExchangeAccount>().Where(ea => ea.TradePolicy == tradePolicy && ea.ExchangeId == exchangeId)
.ToList().Map<IList<ExchangeAccountResponse>>();
var accountIdList = exchangeAccountList.Select(ea => ea.Id);
var exchangeAPIKeyList = fsql.Select<ExchangeAPIKey>().Where(k => k.RobotId == null && accountIdList.Contains(k.AccountId))
.ToList()
.Map<IList<ExchangeAPIKeyResponse>>();
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;
}
}
}