@@ -22,14 +22,9 @@ namespace ExchangeSharp.BinanceGroup
22
22
{
23
23
public abstract class BinanceGroupCommon : ExchangeAPI
24
24
{
25
- public abstract string BaseUrlPrivate { get ; set ; }
26
- public abstract string WithdrawalUrlPrivate { get ; set ; }
27
- /// <summary>
28
- /// base address for APIs used by the Binance website and not published in the API docs
29
- /// </summary>
30
- public abstract string BaseWebUrl { get ; set ; }
25
+ public string BaseUrlApi => $ "{ BaseUrl } /api/v3";
31
26
32
- public const string GetCurrenciesUrl = "/assetWithdraw/getAllAsset.html ";
27
+ public string BaseUrlSApi => $ " { BaseUrl } /sapi/v1 ";
33
28
34
29
protected async Task < string > GetWebSocketStreamUrlForSymbolsAsync ( string suffix , params string [ ] marketSymbols )
35
30
{
@@ -90,6 +85,25 @@ public async Task<IEnumerable<ExchangeOrderResult>> GetMyTradesAsync(string? mar
90
85
return await OnGetMyTradesAsync ( marketSymbol , afterDate ) ;
91
86
}
92
87
88
+ protected override async Task < IReadOnlyDictionary < string , ExchangeCurrency > > OnGetCurrenciesAsync ( )
89
+ {
90
+ var result = await MakeJsonRequestAsync < List < Currency > > ( "/capital/config/getall" , BaseUrlSApi ) ;
91
+
92
+ return result . ToDictionary ( x => x . Coin . ToUpper ( ) , x => {
93
+ var network = x . NetworkList . FirstOrDefault ( x => x . IsDefault ) ;
94
+ return new ExchangeCurrency
95
+ {
96
+ Name = x . Coin ,
97
+ FullName = x . Name ,
98
+ DepositEnabled = network ? . DepositEnable ?? x . DepositAllEnable ,
99
+ WithdrawalEnabled = network ? . WithdrawEnable ?? x . WithdrawAllEnable ,
100
+ MinConfirmations = network ? . MinConfirm ?? 0 ,
101
+ MinWithdrawalSize = decimal . Parse ( network ? . WithdrawMin ?? "0" ) ,
102
+ TxFee = decimal . Parse ( network ? . WithdrawFee ?? "0" )
103
+ } ;
104
+ } ) ;
105
+ }
106
+
93
107
protected override async Task < IEnumerable < string > > OnGetMarketSymbolsAsync ( )
94
108
{
95
109
List < string > symbols = new List < string > ( ) ;
@@ -189,30 +203,6 @@ protected internal override async Task<IEnumerable<ExchangeMarket>> OnGetMarketS
189
203
return markets ;
190
204
}
191
205
192
- protected override async Task < IReadOnlyDictionary < string , ExchangeCurrency > > OnGetCurrenciesAsync ( )
193
- {
194
- // https://www.binance.com/assetWithdraw/getAllAsset.html
195
- Dictionary < string , ExchangeCurrency > allCoins = new Dictionary < string , ExchangeCurrency > ( StringComparer . OrdinalIgnoreCase ) ;
196
-
197
- List < Currency > currencies = await MakeJsonRequestAsync < List < Currency > > ( GetCurrenciesUrl , BaseWebUrl ) ;
198
- foreach ( Currency coin in currencies )
199
- {
200
- allCoins [ coin . AssetCode ] = new ExchangeCurrency
201
- {
202
- CoinType = coin . ParentCode ,
203
- DepositEnabled = coin . EnableCharge ,
204
- FullName = coin . AssetName ,
205
- MinConfirmations = coin . ConfirmTimes . ConvertInvariant < int > ( ) ,
206
- Name = coin . AssetCode ,
207
- TxFee = coin . TransactionFee ,
208
- WithdrawalEnabled = coin . EnableWithdraw ,
209
- MinWithdrawalSize = coin . MinProductWithdraw . ConvertInvariant < decimal > ( ) ,
210
- } ;
211
- }
212
-
213
- return allCoins ;
214
- }
215
-
216
206
protected override async Task < ExchangeTicker > OnGetTickerAsync ( string marketSymbol )
217
207
{
218
208
JToken obj = await MakeJsonRequestAsync < JToken > ( "/ticker/24hr?symbol=" + marketSymbol ) ;
@@ -517,7 +507,7 @@ protected override async Task<IEnumerable<MarketCandle>> OnGetCandlesAsync(strin
517
507
518
508
protected override async Task < Dictionary < string , decimal > > OnGetAmountsAsync ( )
519
509
{
520
- JToken token = await MakeJsonRequestAsync < JToken > ( "/account" , BaseUrlPrivate , await GetNoncePayloadAsync ( ) ) ;
510
+ JToken token = await MakeJsonRequestAsync < JToken > ( "/account" , BaseUrlApi , await GetNoncePayloadAsync ( ) ) ;
521
511
Dictionary < string , decimal > balances = new Dictionary < string , decimal > ( StringComparer . OrdinalIgnoreCase ) ;
522
512
foreach ( JToken balance in token [ "balances" ] )
523
513
{
@@ -532,7 +522,7 @@ protected override async Task<Dictionary<string, decimal>> OnGetAmountsAsync()
532
522
533
523
protected override async Task < Dictionary < string , decimal > > OnGetAmountsAvailableToTradeAsync ( )
534
524
{
535
- JToken token = await MakeJsonRequestAsync < JToken > ( "/account" , BaseUrlPrivate , await GetNoncePayloadAsync ( ) ) ;
525
+ JToken token = await MakeJsonRequestAsync < JToken > ( "/account" , BaseUrlApi , await GetNoncePayloadAsync ( ) ) ;
536
526
Dictionary < string , decimal > balances = new Dictionary < string , decimal > ( StringComparer . OrdinalIgnoreCase ) ;
537
527
foreach ( JToken balance in token [ "balances" ] )
538
528
{
@@ -578,7 +568,7 @@ protected override async Task<ExchangeOrderResult> OnPlaceOrderAsync(ExchangeOrd
578
568
}
579
569
order . ExtraParameters . CopyTo ( payload ) ;
580
570
581
- JToken ? token = await MakeJsonRequestAsync < JToken > ( "/order" , BaseUrlPrivate , payload , "POST" ) ;
571
+ JToken ? token = await MakeJsonRequestAsync < JToken > ( "/order" , BaseUrlApi , payload , "POST" ) ;
582
572
if ( token is null )
583
573
{
584
574
return null ;
@@ -600,13 +590,13 @@ protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string
600
590
else
601
591
payload [ "orderId" ] = orderId ;
602
592
603
- JToken token = await MakeJsonRequestAsync < JToken > ( "/order" , BaseUrlPrivate , payload ) ;
593
+ JToken token = await MakeJsonRequestAsync < JToken > ( "/order" , BaseUrlApi , payload ) ;
604
594
ExchangeOrderResult result = ParseOrder ( token ) ;
605
595
606
596
// Add up the fees from each trade in the order
607
597
Dictionary < string , object > feesPayload = await GetNoncePayloadAsync ( ) ;
608
598
feesPayload [ "symbol" ] = marketSymbol ! ;
609
- JToken feesToken = await MakeJsonRequestAsync < JToken > ( "/myTrades" , BaseUrlPrivate , feesPayload ) ;
599
+ JToken feesToken = await MakeJsonRequestAsync < JToken > ( "/myTrades" , BaseUrlApi , feesPayload ) ;
610
600
ParseFees ( feesToken , result ) ;
611
601
612
602
return result ;
@@ -641,7 +631,7 @@ protected override async Task<IEnumerable<ExchangeOrderResult>> OnGetOpenOrderDe
641
631
{
642
632
payload [ "symbol" ] = marketSymbol ! ;
643
633
}
644
- JToken token = await MakeJsonRequestAsync < JToken > ( "/openOrders" , BaseUrlPrivate , payload ) ;
634
+ JToken token = await MakeJsonRequestAsync < JToken > ( "/openOrders" , BaseUrlApi , payload ) ;
645
635
foreach ( JToken order in token )
646
636
{
647
637
orders . Add ( ParseOrder ( order ) ) ;
@@ -704,74 +694,13 @@ protected override async Task<IEnumerable<ExchangeOrderResult>> OnGetCompletedOr
704
694
{
705
695
payload [ "startTime" ] = afterDate . Value . UnixTimestampFromDateTimeMilliseconds ( ) ;
706
696
}
707
- JToken token = await MakeJsonRequestAsync < JToken > ( "/myTrades" , BaseUrlPrivate , payload ) ;
697
+ JToken token = await MakeJsonRequestAsync < JToken > ( "/myTrades" , BaseUrlApi , payload ) ;
708
698
foreach ( JToken trade in token )
709
699
{
710
700
trades . Add ( ParseTrade ( trade , marketSymbol ! ) ) ;
711
701
}
712
702
}
713
703
return trades ;
714
-
715
- //old way
716
-
717
- //List<ExchangeOrderResult> orders = new List<ExchangeOrderResult>();
718
- //if (string.IsNullOrWhiteSpace(marketSymbol))
719
- //{
720
- // orders.AddRange(await GetCompletedOrdersForAllSymbolsAsync(afterDate));
721
- //}
722
- //else
723
- //{
724
- // Dictionary<string, object> payload = await GetNoncePayloadAsync();
725
- // payload["symbol"] = marketSymbol;
726
- // if (afterDate != null)
727
- // {
728
- // payload["startTime"] = Math.Round(afterDate.Value.UnixTimestampFromDateTimeMilliseconds());
729
- // }
730
- // JToken token = await MakeJsonRequestAsync<JToken>("/allOrders", BaseUrlPrivate, payload);
731
- // foreach (JToken order in token)
732
- // {
733
- // orders.Add(ParseOrder(order));
734
- // }
735
- //}
736
- //return orders;
737
- }
738
-
739
- private async Task < IEnumerable < ExchangeOrderResult > > GetMyTradesForAllSymbols ( DateTime ? afterDate )
740
- {
741
- // TODO: This is a HACK, Binance API needs to add a single API call to get all orders for all symbols, terrible...
742
- List < ExchangeOrderResult > trades = new List < ExchangeOrderResult > ( ) ;
743
- Exception ? ex = null ;
744
- string ? failedSymbol = null ;
745
- Parallel . ForEach ( ( await GetMarketSymbolsAsync ( ) ) . Where ( s => s . IndexOf ( "BTC" , StringComparison . OrdinalIgnoreCase ) >= 0 ) , async ( s ) =>
746
- {
747
- try
748
- {
749
- foreach ( ExchangeOrderResult trade in ( await GetMyTradesAsync ( s , afterDate ) ) )
750
- {
751
- lock ( trades )
752
- {
753
- trades . Add ( trade ) ;
754
- }
755
- }
756
- }
757
- catch ( Exception _ex )
758
- {
759
- failedSymbol = s ;
760
- ex = _ex ;
761
- }
762
- } ) ;
763
-
764
- if ( ex != null )
765
- {
766
- throw new APIException ( "Failed to get my trades for symbol " + failedSymbol , ex ) ;
767
- }
768
-
769
- // sort timestamp desc
770
- trades . Sort ( ( o1 , o2 ) =>
771
- {
772
- return o2 . OrderDate . CompareTo ( o1 . OrderDate ) ;
773
- } ) ;
774
- return trades ;
775
704
}
776
705
777
706
private async Task < IEnumerable < ExchangeOrderResult > > OnGetMyTradesAsync ( string ? marketSymbol = null , DateTime ? afterDate = null )
@@ -789,7 +718,7 @@ private async Task<IEnumerable<ExchangeOrderResult>> OnGetMyTradesAsync(string?
789
718
{
790
719
payload [ "timestamp" ] = afterDate . Value . UnixTimestampFromDateTimeMilliseconds ( ) ;
791
720
}
792
- JToken token = await MakeJsonRequestAsync < JToken > ( "/myTrades" , BaseUrlPrivate , payload ) ;
721
+ JToken token = await MakeJsonRequestAsync < JToken > ( "/myTrades" , BaseUrlApi , payload ) ;
793
722
foreach ( JToken trade in token )
794
723
{
795
724
trades . Add ( ParseTrade ( trade , marketSymbol ! ) ) ;
@@ -807,7 +736,7 @@ protected override async Task OnCancelOrderAsync(string orderId, string? marketS
807
736
}
808
737
payload [ "symbol" ] = marketSymbol ! ;
809
738
payload [ "orderId" ] = orderId ;
810
- _ = await MakeJsonRequestAsync < JToken > ( "/order" , BaseUrlPrivate , payload , "DELETE" ) ;
739
+ _ = await MakeJsonRequestAsync < JToken > ( "/order" , BaseUrlApi , payload , "DELETE" ) ;
811
740
}
812
741
813
742
/// <summary>A withdrawal request. Fee is automatically subtracted from the amount.</summary>
@@ -829,17 +758,21 @@ protected override async Task<ExchangeWithdrawalResponse> OnWithdrawAsync(Exchan
829
758
}
830
759
831
760
Dictionary < string , object > payload = await GetNoncePayloadAsync ( ) ;
832
- payload [ "asset " ] = withdrawalRequest . Currency ;
761
+ payload [ "coin " ] = withdrawalRequest . Currency ;
833
762
payload [ "address" ] = withdrawalRequest . Address ;
834
763
payload [ "amount" ] = withdrawalRequest . Amount ;
835
- payload [ "name" ] = withdrawalRequest . Description ?? "apiwithdrawal" ; // Contrary to what the API docs say, name is required
764
+
765
+ if ( ! string . IsNullOrWhiteSpace ( withdrawalRequest . Description ) )
766
+ {
767
+ payload [ "name" ] = withdrawalRequest . Description ;
768
+ }
836
769
837
770
if ( ! string . IsNullOrWhiteSpace ( withdrawalRequest . AddressTag ) )
838
771
{
839
772
payload [ "addressTag" ] = withdrawalRequest . AddressTag ;
840
773
}
841
774
842
- JToken response = await MakeJsonRequestAsync < JToken > ( "/withdraw.html " , WithdrawalUrlPrivate , payload , "POST" ) ;
775
+ JToken response = await MakeJsonRequestAsync < JToken > ( "/capital/ withdraw/apply " , BaseUrlSApi , payload , "POST" ) ;
843
776
ExchangeWithdrawalResponse withdrawalResponse = new ExchangeWithdrawalResponse
844
777
{
845
778
Id = response [ "id" ] . ToStringInvariant ( ) ,
@@ -1081,14 +1014,14 @@ protected override async Task<ExchangeDepositDetails> OnGetDepositAddressAsync(s
1081
1014
*/
1082
1015
1083
1016
Dictionary < string , object > payload = await GetNoncePayloadAsync ( ) ;
1084
- payload [ "asset " ] = currency ;
1017
+ payload [ "coin " ] = currency ;
1085
1018
1086
- JToken response = await MakeJsonRequestAsync < JToken > ( "/depositAddress.html " , WithdrawalUrlPrivate , payload ) ;
1019
+ JToken response = await MakeJsonRequestAsync < JToken > ( "/capital/deposit/address " , BaseUrlSApi , payload ) ;
1087
1020
ExchangeDepositDetails depositDetails = new ExchangeDepositDetails
1088
1021
{
1089
- Currency = response [ "asset " ] . ToStringInvariant ( ) ,
1022
+ Currency = response [ "coin " ] . ToStringInvariant ( ) ,
1090
1023
Address = response [ "address" ] . ToStringInvariant ( ) ,
1091
- AddressTag = response [ "addressTag " ] . ToStringInvariant ( )
1024
+ AddressTag = response [ "tag " ] . ToStringInvariant ( )
1092
1025
} ;
1093
1026
1094
1027
return depositDetails ;
@@ -1100,44 +1033,33 @@ protected override async Task<ExchangeDepositDetails> OnGetDepositAddressAsync(s
1100
1033
protected override async Task < IEnumerable < ExchangeTransaction > > OnGetDepositHistoryAsync ( string currency )
1101
1034
{
1102
1035
// TODO: API supports searching on status, startTime, endTime
1103
- Dictionary < string , object > payload = await GetNoncePayloadAsync ( ) ;
1036
+ var payload = await GetNoncePayloadAsync ( ) ;
1037
+
1104
1038
if ( ! string . IsNullOrWhiteSpace ( currency ) )
1105
1039
{
1106
- payload [ "asset " ] = currency ;
1040
+ payload [ "coin " ] = currency ;
1107
1041
}
1108
1042
1109
- JToken response = await MakeJsonRequestAsync < JToken > ( "/depositHistory.html " , WithdrawalUrlPrivate , payload ) ;
1043
+ var response = await MakeJsonRequestAsync < List < HistoryRecord > > ( "/capital/deposit/hisrec " , BaseUrlSApi , payload ) ;
1110
1044
var transactions = new List < ExchangeTransaction > ( ) ;
1111
- foreach ( JToken token in response [ "depositList" ] )
1045
+
1046
+ foreach ( var item in response )
1112
1047
{
1113
- var transaction = new ExchangeTransaction
1114
- {
1115
- Timestamp = token [ "insertTime" ] . ConvertInvariant < double > ( ) . UnixTimeStampToDateTimeMilliseconds ( ) ,
1116
- Amount = token [ "amount" ] . ConvertInvariant < decimal > ( ) ,
1117
- Currency = token [ "asset" ] . ToStringUpperInvariant ( ) ,
1118
- Address = token [ "address" ] . ToStringInvariant ( ) ,
1119
- AddressTag = token [ "addressTag" ] . ToStringInvariant ( ) ,
1120
- BlockchainTxId = token [ "txId" ] . ToStringInvariant ( )
1121
- } ;
1122
- int status = token [ "status" ] . ConvertInvariant < int > ( ) ;
1123
- switch ( status )
1048
+ transactions . Add ( new ExchangeTransaction
1124
1049
{
1125
- case 0 :
1126
- transaction . Status = TransactionStatus . Processing ;
1127
- break ;
1128
-
1129
- case 1 :
1130
- transaction . Status = TransactionStatus . Complete ;
1131
- break ;
1132
-
1133
- default :
1134
- // If new states are added, see https://github.com/binance-exchange/binance-official-api-docs/blob/master/wapi-api.md
1135
- transaction . Status = TransactionStatus . Unknown ;
1136
- transaction . Notes = "Unknown transaction status: " + status ;
1137
- break ;
1138
- }
1139
-
1140
- transactions . Add ( transaction ) ;
1050
+ Timestamp = item . InsertTime . UnixTimeStampToDateTimeMilliseconds ( ) ,
1051
+ Amount = decimal . Parse ( item . Amount ) ,
1052
+ Currency = item . Coin . ToUpperInvariant ( ) ,
1053
+ Address = item . Address ,
1054
+ AddressTag = item . AddressTag ,
1055
+ BlockchainTxId = item . TxId ,
1056
+ Status = item . Status switch
1057
+ {
1058
+ 0 => TransactionStatus . Processing ,
1059
+ 1 => TransactionStatus . Complete ,
1060
+ _ => TransactionStatus . Unknown
1061
+ }
1062
+ } ) ;
1141
1063
}
1142
1064
1143
1065
return transactions ;
@@ -1170,7 +1092,7 @@ protected override async Task<IWebSocket> OnUserDataWebSocketAsync(Action<object
1170
1092
1171
1093
public async Task < string > GetListenKeyAsync ( )
1172
1094
{
1173
- JToken response = await MakeJsonRequestAsync < JToken > ( "/userDataStream" , BaseUrl , null , "POST" ) ;
1095
+ JToken response = await MakeJsonRequestAsync < JToken > ( "/userDataStream" , BaseUrlApi , null , "POST" ) ;
1174
1096
var listenKey = response [ "listenKey" ] . ToStringInvariant ( ) ;
1175
1097
return listenKey ;
1176
1098
}
0 commit comments