Browse Source

封装多交易所API请求类

master
shanji 3 years ago
parent
commit
7932ae1fc0
  1. 3
      .editorconfig
  2. 8
      Binance.TradeRobot.API.sln
  3. 22
      Binance.TradeRobot.Business/Business/BaseBusiness.cs
  4. 11
      Binance.TradeRobot.Business/Business/ExchangeBusiness.cs
  5. 12
      Binance.TradeRobot.Business/Business/TradeBusiness/D21TradeBusiness.cs
  6. 21
      Binance.TradeRobot.Model/Base/Enums.cs
  7. 46
      Binance.TradeRobot.Model/Binance.TradeRobot.Model.xml
  8. 3
      Binance.TradeRobot.Model/Db/Order/SpotOrder.cs
  9. 4
      Binance.TradeRobot.Model/Dto/Response/Robot/RobotResponse.cs
  10. 38
      SDKAdapter/APIClient/BaseAPIClient.cs
  11. 60
      SDKAdapter/APIClient/BinanceAPIClient.cs
  12. 65
      SDKAdapter/Model/IsolatedMarginAccountAsset.cs
  13. 14
      SDKAdapter/WebSockets/Market/SpotMarketWebSocketClient.cs
  14. 25
      SDKTestConsole/Program.cs
  15. 17
      SDKTestConsole/SDKTestConsole.csproj

3
.editorconfig

@ -11,3 +11,6 @@ dotnet_diagnostic.CS8625.severity = none
# CS8602: 解引用可能出现空引用。
dotnet_diagnostic.CS8602.severity = none
# CS8603: 可能返回 null 引用。
dotnet_diagnostic.CS8603.severity = none

8
Binance.TradeRobot.API.sln

@ -16,7 +16,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.editorconfig = .editorconfig
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SDKAdapter", "SDKAdapter\SDKAdapter.csproj", "{E461043B-179D-4625-BF2F-C00EAB1C8213}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SDKAdapter", "SDKAdapter\SDKAdapter.csproj", "{E461043B-179D-4625-BF2F-C00EAB1C8213}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SDKTestConsole", "SDKTestConsole\SDKTestConsole.csproj", "{69458842-D4E0-4BB8-8E5A-254CC9074A23}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -44,6 +46,10 @@ Global
{E461043B-179D-4625-BF2F-C00EAB1C8213}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E461043B-179D-4625-BF2F-C00EAB1C8213}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E461043B-179D-4625-BF2F-C00EAB1C8213}.Release|Any CPU.Build.0 = Release|Any CPU
{69458842-D4E0-4BB8-8E5A-254CC9074A23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{69458842-D4E0-4BB8-8E5A-254CC9074A23}.Debug|Any CPU.Build.0 = Debug|Any CPU
{69458842-D4E0-4BB8-8E5A-254CC9074A23}.Release|Any CPU.ActiveCfg = Release|Any CPU
{69458842-D4E0-4BB8-8E5A-254CC9074A23}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

22
Binance.TradeRobot.Business/Business/BaseBusiness.cs

@ -1,7 +1,9 @@
using Binance.Net.Clients;
using Binance.Net.Objects;
using Binance.TradeRobot.Model.Base;
using CryptoExchange.Net.Authentication;
using Microsoft.Extensions.Caching.Memory;
using SDKAdapter.APIClient;
using System;
using Yitter.IdGenerator;
@ -25,23 +27,15 @@ namespace Binance.TradeRobot.Business
expirationTimeSpan = TimeSpan.FromDays(1);
}
protected BinanceClient GetBinanceClient(string apiKey, string secret)
protected BaseAPIClient GetBaseAPIClient(Enums.Exchange exchange, long uid, string apiKey, string secret)
{
if (!memoryCache.TryGetValue(apiKey, out BinanceClient binanceClient))
var cacheKey = exchange == Enums.Exchange.Binance ? uid.ToString() : apiKey;
if (!memoryCache.TryGetValue(cacheKey, out BaseAPIClient baseAPIClient))
{
var apiClientOption = new BinanceApiClientOptions()
{
BaseAddress = "https://fapi.binance.com",
ApiCredentials = new ApiCredentials(apiKey, secret)
};
binanceClient = new BinanceClient(new BinanceClientOptions()
{
UsdFuturesApiOptions = apiClientOption,
SpotApiOptions = apiClientOption
});
memoryCache.Set(apiKey, binanceClient, expirationTimeSpan);
baseAPIClient = BaseAPIClient.Create(exchange, uid, apiKey, secret);
memoryCache.Set(cacheKey, baseAPIClient, expirationTimeSpan);
}
return binanceClient;
return baseAPIClient;
}
}
}

11
Binance.TradeRobot.Business/Business/ExchangeBusiness.cs

@ -102,14 +102,13 @@ namespace Binance.TradeRobot.Business.Exchange
{
try
{
var binanceClient = GetBinanceClient(exchangeAccount.ExchangeAPIKeyList[0].APIKey, exchangeAccount.ExchangeAPIKeyList[0].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;
}
//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)
{

12
Binance.TradeRobot.Business/Business/TradeBusiness/D21TradeBusiness.cs

@ -128,13 +128,13 @@ namespace Binance.TradeRobot.Business
}
#endregion
#region 获取账户余额
#endregion
#region 计算下单数量
var recentSellOrder = fsql.Select<SpotOrder>().Where(o => o.RobotId == robot.Id &&
o.TradeDirection == Enums.TradeDirection.Sell &&
validStateList.Contains(o.State))
.OrderByDescending(o => o.LastTradeTime)
.ToOne();
var previewTradeAmount = d21Robot.D21Policy.Position; //预估交易额
#endregion
}

21
Binance.TradeRobot.Model/Base/Enums.cs

@ -148,6 +148,27 @@ namespace Binance.TradeRobot.Model.Base
Buy, Sell
}
/// <summary>
/// 订单类型
/// <para>LIMIT 限价单</para>
/// <para>MARKET 市价单</para>
/// <para>STOP_LOSS 止损单</para>
/// <para>STOP_LOSS_LIMIT 限价止损单</para>
/// <para>TAKE_PROFIT 止盈单</para>
/// <para>TAKE_PROFIT_LIMIT 限价止盈单</para>
/// <para>LIMIT_MAKER 限价只挂单</para>
/// </summary>
public enum OrderType
{
LIMIT,
MARKET,
STOP_LOSS,
STOP_LOSS_LIMIT,
TAKE_PROFIT,
TAKE_PROFIT_LIMIT,
LIMIT_MAKER
}
/// <summary>
/// 信号周期 1m=0,3m=1,5m=2,15m=3,30m=4,1h=5,2h=6,4h=7,6h=8,8h=9,12h=10,1d=11,3d=12,1w=13,1M=14
/// </summary>

46
Binance.TradeRobot.Model/Binance.TradeRobot.Model.xml

@ -94,9 +94,39 @@
借币状态 Loading=0 returned=1
</summary>
</member>
<member name="T:Binance.TradeRobot.Model.Base.Enums.OrderState">
<member name="T:Binance.TradeRobot.Model.Base.Enums.SpotOrderState">
<summary>
订单状态
现货订单订单状态
</summary>
</member>
<member name="F:Binance.TradeRobot.Model.Base.Enums.SpotOrderState.Created">
<summary>
已创建
</summary>
</member>
<member name="F:Binance.TradeRobot.Model.Base.Enums.SpotOrderState.PartiallyFilled">
<summary>
部分成交
</summary>
</member>
<member name="F:Binance.TradeRobot.Model.Base.Enums.SpotOrderState.Filled">
<summary>
完全成交
</summary>
</member>
<member name="F:Binance.TradeRobot.Model.Base.Enums.SpotOrderState.Canceled">
<summary>
用户取消
</summary>
</member>
<member name="F:Binance.TradeRobot.Model.Base.Enums.SpotOrderState.Rejected">
<summary>
拒绝
</summary>
</member>
<member name="F:Binance.TradeRobot.Model.Base.Enums.SpotOrderState.Expired">
<summary>
交易引擎取消 没有完全成交
</summary>
</member>
<member name="T:Binance.TradeRobot.Model.Base.Enums.TradeDirection">
@ -104,6 +134,18 @@
交易方向 Buy=0,Sell=1
</summary>
</member>
<member name="T:Binance.TradeRobot.Model.Base.Enums.OrderType">
<summary>
订单类型
<para>LIMIT 限价单</para>
<para>MARKET 市价单</para>
<para>STOP_LOSS 止损单</para>
<para>STOP_LOSS_LIMIT 限价止损单</para>
<para>TAKE_PROFIT 止盈单</para>
<para>TAKE_PROFIT_LIMIT 限价止盈单</para>
<para>LIMIT_MAKER 限价只挂单</para>
</summary>
</member>
<member name="T:Binance.TradeRobot.Model.Base.Enums.SignalPeriod">
<summary>
信号周期 1m=0,3m=1,5m=2,15m=3,30m=4,1h=5,2h=6,4h=7,6h=8,8h=9,12h=10,1d=11,3d=12,1w=13,1M=14

3
Binance.TradeRobot.Model/Db/Order/SpotOrder.cs

@ -94,6 +94,9 @@ namespace Binance.TradeRobot.Model.Db
[Column(DbType = "decimal(18,8)")]
public decimal TradeQuantity { get; set; }
[Column(MapType = typeof(int), DbType = "int")]
public Enums.OrderType OrderType { get; set; }
}
}

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

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

38
SDKAdapter/APIClient/BaseAPIClient.cs

@ -0,0 +1,38 @@
using Binance.TradeRobot.Model.Base;
using SDKAdapter.Model;
using System;
using System.Collections.Generic;
namespace SDKAdapter.APIClient
{
public class BaseAPIClient
{
public static BaseAPIClient Create(Enums.Exchange exchange, long uid, string apiKey, string secret)
{
if (exchange == Enums.Exchange.Binance)
return new BinanceAPIClient(uid, apiKey, secret);
return null;
}
protected long AccountId { get; private set; }
protected string ApiKey { get; private set; }
protected string Secret { get; private set; }
public BaseAPIClient(long uid, string apiKey, string secret)
{
this.AccountId = uid;
this.ApiKey = apiKey;
this.Secret = secret;
}
/// <summary>
/// 获取逐仓杠杆账户资产
/// </summary>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public virtual IList<IsolatedMarginAccountAsset> GetIsolatedMarginAccountAssets()
{
throw new NotImplementedException();
}
}
}

60
SDKAdapter/APIClient/BinanceAPIClient.cs

@ -0,0 +1,60 @@
using Binance.Net.Clients;
using Binance.Net.Objects;
using CryptoExchange.Net.Authentication;
using SDKAdapter.Model;
using System;
using System.Collections.Generic;
using System.Linq;
namespace SDKAdapter.APIClient
{
public class BinanceAPIClient : BaseAPIClient
{
private BinanceClient binanceClient;
public BinanceAPIClient(long uid, string apiKey, string secret) : base(uid, apiKey, secret)
{
var spotClientOption = new BinanceApiClientOptions()
{
BaseAddress = "https://api.binance.com",
ApiCredentials = new ApiCredentials(apiKey, secret)
};
var usdFuturesClientOption = new BinanceApiClientOptions()
{
BaseAddress = "https://fapi.binance.com",
ApiCredentials = new ApiCredentials(apiKey, secret)
};
binanceClient = new BinanceClient(new BinanceClientOptions()
{
UsdFuturesApiOptions = usdFuturesClientOption,
SpotApiOptions = spotClientOption
});
}
public override IList<IsolatedMarginAccountAsset> GetIsolatedMarginAccountAssets()
{
var r = binanceClient.SpotApi.Account.GetIsolatedMarginAccountAsync().Result;
if (!r.Success)
throw new Exception($"获取逐仓杠杆账户信息失败 {r.Error?.Message}");
return r.Data.Assets.Select(asset => new IsolatedMarginAccountAsset()
{
Symbol = asset.Symbol,
BaseAsset = asset.BaseAsset.Asset,
BaseBorrowed = asset.BaseAsset.Borrowed,
BaseFree = asset.BaseAsset.Free,
BaseInterest = asset.BaseAsset.Interest,
BaseLocked = asset.BaseAsset.Locked,
BaseNetAsset = asset.BaseAsset.NetAsset,
QuoteAsset = asset.QuoteAsset.Asset,
QuoteBorrowed = asset.QuoteAsset.Borrowed,
QuoteFree = asset.QuoteAsset.Free,
QuoteInterest = asset.QuoteAsset.Interest,
QuoteLocked = asset.QuoteAsset.Locked,
QuoteNetAsset = asset.QuoteAsset.NetAsset
}).ToList();
}
}
}

65
SDKAdapter/Model/IsolatedMarginAccountAsset.cs

@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SDKAdapter.Model
{
/// <summary>
/// 逐仓杠杆账户资产
/// </summary>
public class IsolatedMarginAccountAsset
{
public string Symbol { get; set; }
/// <summary>
/// 基础币
/// </summary>
public string BaseAsset { get; set; }
/// <summary>
/// 基础币借币金额
/// </summary>
public decimal BaseBorrowed { get; set; }
/// <summary>
/// 基础币可用资产
/// </summary>
public decimal BaseFree { get; set; }
/// <summary>
/// 基础币借币利息
/// </summary>
public decimal BaseInterest { get; set; }
/// <summary>
/// 基础币锁定资产
/// </summary>
public decimal BaseLocked { get; set; }
/// <summary>
/// 基础币净资产
/// </summary>
public decimal BaseNetAsset { get; set; }
/// <summary>
/// 报价币
/// </summary>
public string QuoteAsset { get; set; }
/// <summary>
/// 报价币借币金额
/// </summary>
public decimal QuoteBorrowed { get; set; }
/// <summary>
/// 报价币可用资产
/// </summary>
public decimal QuoteFree { get; set; }
/// <summary>
/// 报价币借币利息
/// </summary>
public decimal QuoteInterest { get; set; }
/// <summary>
/// 报价币锁定资产
/// </summary>
public decimal QuoteLocked { get; set; }
/// <summary>
/// 报价币净资产
/// </summary>
public decimal QuoteNetAsset { get; set; }
}
}

14
SDKAdapter/WebSockets/Market/SpotMarketWebSocketClient.cs

@ -5,6 +5,13 @@ namespace SDKAdapter.WebSockets.Market
{
public class SpotMarketWebSocketClient
{
public static SpotMarketWebSocketClient Create(Enums.Exchange exchange, string symbol, NLog.ILogger logger)
{
if (exchange == Enums.Exchange.Binance)
return new BinanceSpotMarketWebSocketClient(symbol, logger);
return null;
}
/// <summary>
/// 更新间隔(ms)
/// </summary>
@ -54,12 +61,5 @@ 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;
}
}
}

25
SDKTestConsole/Program.cs

@ -0,0 +1,25 @@
using Binance.Net.Clients;
using Binance.Net.Objects;
using Binance.TradeRobot.Model.Base;
using CryptoExchange.Net.Authentication;
using Newtonsoft.Json;
using SDKAdapter.APIClient;
using System;
namespace SDKTestConsole
{
internal class Program
{
static void Main(string[] args)
{
var apiKey = "NnLXgcdUAZ8FAye4Qge3zrrdg5o7ufoWbgtYsKzgfIXz0OMz27G1Kx4SykMzw7YS";
var secret = "lpJ3t50osPx6lEUerVFMdoKsZ6uHPc769OFPGtfhcoPANpv97CEcvR3pz3Bezhhv";
var marginList = BaseAPIClient.Create(Enums.Exchange.Binance, 0, apiKey, secret).GetIsolatedMarginAccountAssets();
var s = JsonConvert.SerializeObject(marginList);
Console.WriteLine(s);
Console.ReadKey();
}
}
}

17
SDKTestConsole/SDKTestConsole.csproj

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Binance.Net" Version="8.0.13" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Binance.TradeRobot.Model\Binance.TradeRobot.Model.csproj" />
<ProjectReference Include="..\SDKAdapter\SDKAdapter.csproj" />
</ItemGroup>
</Project>
Loading…
Cancel
Save