@@ -10,11 +10,12 @@ The above copyright notice and this permission notice shall be included in all c
1010THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1111*/
1212
13- using ExchangeSharp . OKGroup ;
14- using Newtonsoft . Json . Linq ;
1513using System ;
1614using System . Collections . Generic ;
15+ using System . Linq ;
1716using System . Threading . Tasks ;
17+ using ExchangeSharp . OKGroup ;
18+ using Newtonsoft . Json . Linq ;
1819
1920namespace ExchangeSharp
2021{
@@ -27,6 +28,11 @@ public sealed partial class ExchangeOKExAPI : OKGroupCommon
2728 public string BaseUrlV5 { get ; set ; } = "https://okex.com/api/v5" ;
2829 protected override bool IsFuturesAndSwapEnabled { get ; } = true ;
2930
31+ public override string PeriodSecondsToString ( int seconds )
32+ {
33+ return CryptoUtility . SecondsToPeriodString ( seconds , true ) ;
34+ }
35+
3036 protected internal override async Task < IEnumerable < ExchangeMarket > > OnGetMarketSymbolsMetadataAsync ( )
3137 {
3238 /*
@@ -61,61 +67,54 @@ protected internal override async Task<IEnumerable<ExchangeMarket>> OnGetMarketS
6167 ]
6268 }
6369 */
64- List < ExchangeMarket > markets = new List < ExchangeMarket > ( ) ;
70+ var markets = new List < ExchangeMarket > ( ) ;
6571 parseMarketSymbolTokens ( await MakeJsonRequestAsync < JToken > (
6672 "/public/instruments?instType=SPOT" , BaseUrlV5 ) ) ;
67- if ( IsFuturesAndSwapEnabled )
68- {
69- parseMarketSymbolTokens ( await MakeJsonRequestAsync < JToken > (
70- "/public/instruments?instType=FUTURES" , BaseUrlV5 ) ) ;
71- parseMarketSymbolTokens ( await MakeJsonRequestAsync < JToken > (
72- "/public/instruments?instType=SWAP" , BaseUrlV5 ) ) ;
73- }
73+ if ( ! IsFuturesAndSwapEnabled )
74+ return markets ;
75+ parseMarketSymbolTokens ( await MakeJsonRequestAsync < JToken > (
76+ "/public/instruments?instType=FUTURES" , BaseUrlV5 ) ) ;
77+ parseMarketSymbolTokens ( await MakeJsonRequestAsync < JToken > (
78+ "/public/instruments?instType=SWAP" , BaseUrlV5 ) ) ;
79+ return markets ;
80+
7481 void parseMarketSymbolTokens ( JToken allMarketSymbolTokens )
7582 {
76- foreach ( JToken marketSymbolToken in allMarketSymbolTokens )
77- {
78- var isSpot = marketSymbolToken [ "instType" ] . Value < string > ( ) == "SPOT" ;
79- var baseCurrency = isSpot
80- ? marketSymbolToken [ "baseCcy" ] . Value < string > ( )
81- : marketSymbolToken [ "settleCcy" ] . Value < string > ( ) ;
82- var quoteCurrency = isSpot
83- ? marketSymbolToken [ "quoteCcy" ] . Value < string > ( )
84- : marketSymbolToken [ "ctValCcy" ] . Value < string > ( ) ;
85- var market = new ExchangeMarket
86- {
87- MarketSymbol = marketSymbolToken [ "instId" ] . Value < string > ( ) ,
88- IsActive = marketSymbolToken [ "state" ] . Value < string > ( ) == "live" ,
89- QuoteCurrency = quoteCurrency ,
90- BaseCurrency = baseCurrency ,
91- PriceStepSize = marketSymbolToken [ "tickSz" ] . ConvertInvariant < decimal > ( ) ,
92- MinPrice = marketSymbolToken [ "tickSz" ] . ConvertInvariant < decimal > ( ) , // assuming that this is also the min price since it isn't provided explicitly by the exchange
93- MinTradeSize = marketSymbolToken [ "minSz" ] . ConvertInvariant < decimal > ( ) ,
94- QuantityStepSize = marketSymbolToken [ "lotSz" ] . ConvertInvariant < decimal > ( ) ,
95- } ;
96- markets . Add ( market ) ;
97- }
83+ markets . AddRange ( from marketSymbolToken in allMarketSymbolTokens
84+ let isSpot = marketSymbolToken [ "instType" ] . Value < string > ( ) == "SPOT"
85+ let baseCurrency = isSpot ? marketSymbolToken [ "baseCcy" ] . Value < string > ( ) : marketSymbolToken [ "settleCcy" ] . Value < string > ( )
86+ let quoteCurrency = isSpot ? marketSymbolToken [ "quoteCcy" ] . Value < string > ( ) : marketSymbolToken [ "ctValCcy" ] . Value < string > ( )
87+ select new ExchangeMarket
88+ {
89+ MarketSymbol = marketSymbolToken [ "instId" ] . Value < string > ( ) ,
90+ IsActive = marketSymbolToken [ "state" ] . Value < string > ( ) == "live" ,
91+ QuoteCurrency = quoteCurrency ,
92+ BaseCurrency = baseCurrency ,
93+ PriceStepSize = marketSymbolToken [ "tickSz" ] . ConvertInvariant < decimal > ( ) ,
94+ MinPrice = marketSymbolToken [ "tickSz" ] . ConvertInvariant < decimal > ( ) , // assuming that this is also the min price since it isn't provided explicitly by the exchange
95+ MinTradeSize = marketSymbolToken [ "minSz" ] . ConvertInvariant < decimal > ( ) ,
96+ QuantityStepSize = marketSymbolToken [ "lotSz" ] . ConvertInvariant < decimal > ( )
97+ } ) ;
9898 }
99-
100- return markets ;
10199 }
102100
103101 protected override async Task < ExchangeTicker > OnGetTickerAsync ( string marketSymbol )
104102 {
105103 var tickerResponse = await MakeJsonRequestAsync < JToken > ( $ "/market/ticker?instId={ marketSymbol } ", BaseUrlV5 ) ;
106- var symbol = tickerResponse [ "instId" ] . Value < string > ( ) ;
107- return await ParseTickerV5Async ( tickerResponse , symbol ) ;
104+ var symbol = tickerResponse [ 0 ] [ "instId" ] . Value < string > ( ) ;
105+ return await ParseTickerV5Async ( tickerResponse [ 0 ] , symbol ) ;
108106 }
109107
110108 protected override async Task < IEnumerable < KeyValuePair < string , ExchangeTicker > > > OnGetTickersAsync ( )
111109 {
112- List < KeyValuePair < string , ExchangeTicker > > tickers = new List < KeyValuePair < string , ExchangeTicker > > ( ) ;
110+ var tickers = new List < KeyValuePair < string , ExchangeTicker > > ( ) ;
113111 await parseData ( await MakeJsonRequestAsync < JToken > ( "/market/tickers?instType=SPOT" , BaseUrlV5 ) ) ;
114- if ( IsFuturesAndSwapEnabled )
115- {
116- await parseData ( await MakeJsonRequestAsync < JToken > ( "/market/tickers?instType=FUTURES" , BaseUrlV5 ) ) ;
117- await parseData ( await MakeJsonRequestAsync < JToken > ( "/market/tickers?instType=SWAP" , BaseUrlV5 ) ) ;
118- }
112+ if ( ! IsFuturesAndSwapEnabled )
113+ return tickers ;
114+ await parseData ( await MakeJsonRequestAsync < JToken > ( "/market/tickers?instType=FUTURES" , BaseUrlV5 ) ) ;
115+ await parseData ( await MakeJsonRequestAsync < JToken > ( "/market/tickers?instType=SWAP" , BaseUrlV5 ) ) ;
116+ return tickers ;
117+
119118 async Task parseData ( JToken tickerResponse )
120119 {
121120 /*{
@@ -148,49 +147,83 @@ async Task parseData(JToken tickerResponse)
148147 foreach ( JToken t in tickerResponse )
149148 {
150149 var symbol = t [ "instId" ] . Value < string > ( ) ;
151- ExchangeTicker ticker = await ParseTickerV5Async ( t , symbol ) ;
150+ var ticker = await ParseTickerV5Async ( t , symbol ) ;
152151 tickers . Add ( new KeyValuePair < string , ExchangeTicker > ( symbol , ticker ) ) ;
153152 }
154153 }
155-
156- return tickers ;
157154 }
158155
159- protected override async Task < IEnumerable < ExchangeTrade > > OnGetRecentTradesAsync ( string marketSymbol , int ? limit )
156+ protected override async Task < IEnumerable < ExchangeTrade > > OnGetRecentTradesAsync ( string marketSymbol ,
157+ int ? limit = null )
160158 {
161- limit = limit ?? 500 ;
159+ limit ??= 500 ;
162160 marketSymbol = NormalizeMarketSymbol ( marketSymbol ) ;
163- List < ExchangeTrade > trades = new List < ExchangeTrade > ( ) ;
164- var recentTradesResponse = await MakeJsonRequestAsync < JToken > ( $ "/market/trades?instId={ marketSymbol } &limit={ limit } ", BaseUrlV5 ) ;
165- foreach ( var t in recentTradesResponse )
166- {
167- trades . Add (
168- t . ParseTrade (
169- amountKey : "sz" ,
170- priceKey : "px" ,
171- typeKey : "side" ,
172- timestampKey : "ts" ,
173- timestampType : TimestampType . UnixMilliseconds ,
174- idKey : "tradeId" ) ) ;
161+ var recentTradesResponse =
162+ await MakeJsonRequestAsync < JToken > ( $ "/market/trades?instId={ marketSymbol } &limit={ limit } ", BaseUrlV5 ) ;
163+ return recentTradesResponse . Select ( t => t . ParseTrade (
164+ "sz" , "px" , "side" , "ts" , TimestampType . UnixMilliseconds , "tradeId" ) )
165+ . ToList ( ) ;
166+ }
167+
168+ protected override async Task < ExchangeOrderBook > OnGetOrderBookAsync ( string marketSymbol , int maxCount = 100 )
169+ {
170+ var token = await MakeJsonRequestAsync < JToken > ( $ "/market/books?instId={ marketSymbol } &sz={ maxCount } ", BaseUrlV5 ) ;
171+ return token [ 0 ] . ParseOrderBookFromJTokenArrays ( maxCount : maxCount ) ;
172+ }
173+
174+ protected override async Task < IEnumerable < MarketCandle > > OnGetCandlesAsync ( string marketSymbol , int periodSeconds , DateTime ? startDate = null , DateTime ? endDate = null , int ? limit = null )
175+ {
176+ /*
177+ {
178+ "code":"0",
179+ "msg":"",
180+ "data":[
181+ [
182+ "1597026383085", timestamp
183+ "3.721", open
184+ "3.743", high
185+ "3.677", low
186+ "3.708", close
187+ "8422410", volume
188+ "22698348.04828491" volCcy (Quote)
189+ ],..
190+ ]
175191 }
192+ */
176193
177- return trades ;
194+ var candles = new List < MarketCandle > ( ) ;
195+ var url = $ "/market/history-candles?instId={ marketSymbol } ";
196+ if ( startDate . HasValue )
197+ url += "&after=" + ( long ) startDate . Value . UnixTimestampFromDateTimeMilliseconds ( ) ;
198+ if ( endDate . HasValue )
199+ url += "&before=" + ( long ) endDate . Value . UnixTimestampFromDateTimeMilliseconds ( ) ;
200+ if ( limit . HasValue )
201+ url += "&limit=" + limit . Value . ToStringInvariant ( ) ;
202+ var periodString = PeriodSecondsToString ( periodSeconds ) ;
203+ url += $ "&bar={ periodString } ";
204+ var obj = await MakeJsonRequestAsync < JToken > ( url , BaseUrlV5 ) ;
205+ foreach ( JArray token in obj )
206+ candles . Add ( this . ParseCandle ( token , marketSymbol , periodSeconds , 1 , 2 , 3 , 4 , 0 , TimestampType . UnixMilliseconds , 5 , 6 ) ) ;
207+ return candles ;
178208 }
179209
180210 private async Task < ExchangeTicker > ParseTickerV5Async ( JToken t , string symbol )
181211 {
182212 return await this . ParseTickerAsync (
183- t ,
184- symbol ,
185- askKey : "askPx" ,
186- bidKey : "bidPx" ,
187- lastKey : "last" ,
188- baseVolumeKey : "vol24h" ,
189- quoteVolumeKey : "volCcy24h" ,
190- timestampKey : "ts" ,
191- timestampType : TimestampType . UnixMilliseconds ) ;
213+ token : t ,
214+ marketSymbol : symbol ,
215+ askKey : "askPx" ,
216+ bidKey : "bidPx" ,
217+ lastKey : "last" ,
218+ baseVolumeKey : "vol24h" ,
219+ quoteVolumeKey : "volCcy24h" ,
220+ timestampKey : "ts" ,
221+ timestampType : TimestampType . UnixMilliseconds ) ;
192222 }
193223 }
194224
195- public partial class ExchangeName { public const string OKEx = "OKEx" ; }
225+ public partial class ExchangeName
226+ {
227+ public const string OKEx = "OKEx" ;
228+ }
196229}
0 commit comments