PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/xchange-stream-okcoin/src/main/java/info/bitrich/xchangestream/okcoin/OkCoinStreamingMarketDataService.java

http://github.com/timmolter/XChange
Java | 204 lines | 143 code | 17 blank | 44 comment | 12 complexity | 56df912ed01558347a76559f39739037 MD5 | raw file
  1. package info.bitrich.xchangestream.okcoin;
  2. import com.fasterxml.jackson.databind.ObjectMapper;
  3. import info.bitrich.xchangestream.core.StreamingMarketDataService;
  4. import info.bitrich.xchangestream.okcoin.dto.OkCoinOrderbook;
  5. import info.bitrich.xchangestream.okcoin.dto.OkCoinWebSocketTrade;
  6. import info.bitrich.xchangestream.okcoin.dto.marketdata.FutureTicker;
  7. import info.bitrich.xchangestream.service.netty.StreamingObjectMapperHelper;
  8. import io.reactivex.Observable;
  9. import java.math.BigDecimal;
  10. import java.util.HashMap;
  11. import java.util.Map;
  12. import org.knowm.xchange.currency.CurrencyPair;
  13. import org.knowm.xchange.dto.Order;
  14. import org.knowm.xchange.dto.marketdata.OrderBook;
  15. import org.knowm.xchange.dto.marketdata.Ticker;
  16. import org.knowm.xchange.dto.marketdata.Trade;
  17. import org.knowm.xchange.dto.marketdata.Trades;
  18. import org.knowm.xchange.okcoin.FuturesContract;
  19. import org.knowm.xchange.okcoin.OkCoinAdapters;
  20. import org.knowm.xchange.okcoin.dto.marketdata.OkCoinDepth;
  21. import org.knowm.xchange.okcoin.dto.marketdata.OkCoinTicker;
  22. import org.knowm.xchange.okcoin.dto.marketdata.OkCoinTickerResponse;
  23. /**
  24. * #### spot ####
  25. * https://github.com/okcoin-okex/API-docs-OKEx.com/blob/master/API-For-Spot-CN/%E5%B8%81%E5%B8%81%E4%BA%A4%E6%98%93WebSocket%20API.md
  26. * ##### future ####
  27. * https://github.com/okcoin-okex/API-docs-OKEx.com/blob/master/API-For-Futures-CN/%E5%90%88%E7%BA%A6%E4%BA%A4%E6%98%93WebSocket%20API.md
  28. * https://github.com/okcoin-okex/API-docs-OKEx.com/blob/master/API-For-Futures-EN/WebSocket%20API%20for%20FUTURES.md
  29. */
  30. public class OkCoinStreamingMarketDataService implements StreamingMarketDataService {
  31. private final OkCoinStreamingService service;
  32. private final ObjectMapper mapper = StreamingObjectMapperHelper.getObjectMapper();
  33. private final Map<String, OkCoinOrderbook> orderbooks = new HashMap<>();
  34. OkCoinStreamingMarketDataService(OkCoinStreamingService service) {
  35. this.service = service;
  36. }
  37. /**
  38. * #### spot #### 2. ok_sub_spot_X_depth 订阅币币市场深度(200增量数据返回) 3. ok_sub_spot_X_depth_Y 订阅市场深度 ####
  39. * future #### 3. ok_sub_futureusd_X_depth_Y 订阅合约市场深度(200增量数据返回) 3. ok_sub_futureusd_X_depth_Y
  40. * Subscribe Contract Market Depth(Incremental) 4. ok_sub_futureusd_X_depth_Y_Z 订阅合约市场深度(全量返回) 4.
  41. * ok_sub_futureusd_X_depth_Y_Z Subscribe Contract Market Depth(Full)
  42. *
  43. * @param currencyPair Currency pair of the order book
  44. * @param args if the first arg is {@link FuturesContract} means future, the next arg is amount
  45. * @return
  46. */
  47. @Override
  48. public Observable<OrderBook> getOrderBook(CurrencyPair currencyPair, Object... args) {
  49. String channel =
  50. String.format(
  51. "ok_sub_spot_%s_%s_depth",
  52. currencyPair.base.toString().toLowerCase(),
  53. currencyPair.counter.toString().toLowerCase());
  54. if (args.length > 0) {
  55. if (args[0] instanceof FuturesContract) {
  56. FuturesContract contract = (FuturesContract) args[0];
  57. channel =
  58. String.format(
  59. "ok_sub_future%s_%s_depth_%s",
  60. currencyPair.counter.toString().toLowerCase(),
  61. currencyPair.base.toString().toLowerCase(),
  62. contract.getName());
  63. if (args.length > 1) {
  64. channel = channel + "_" + args[1];
  65. }
  66. } else {
  67. channel = channel + "_" + args[1];
  68. }
  69. }
  70. final String key = channel;
  71. return service
  72. .subscribeChannel(channel)
  73. .map(
  74. s -> {
  75. OkCoinOrderbook okCoinOrderbook;
  76. if (!orderbooks.containsKey(key)) {
  77. OkCoinDepth okCoinDepth = mapper.treeToValue(s.get("data"), OkCoinDepth.class);
  78. okCoinOrderbook = new OkCoinOrderbook(okCoinDepth);
  79. orderbooks.put(key, okCoinOrderbook);
  80. } else {
  81. okCoinOrderbook = orderbooks.get(key);
  82. if (s.get("data").has("asks")) {
  83. if (s.get("data").get("asks").size() > 0) {
  84. BigDecimal[][] askLevels =
  85. mapper.treeToValue(s.get("data").get("asks"), BigDecimal[][].class);
  86. okCoinOrderbook.updateLevels(askLevels, Order.OrderType.ASK);
  87. }
  88. }
  89. if (s.get("data").has("bids")) {
  90. if (s.get("data").get("bids").size() > 0) {
  91. BigDecimal[][] bidLevels =
  92. mapper.treeToValue(s.get("data").get("bids"), BigDecimal[][].class);
  93. okCoinOrderbook.updateLevels(bidLevels, Order.OrderType.BID);
  94. }
  95. }
  96. }
  97. return OkCoinAdapters.adaptOrderBook(
  98. okCoinOrderbook.toOkCoinDepth(s.get("data").get("timestamp").asLong()),
  99. currencyPair);
  100. });
  101. }
  102. /**
  103. * #### spot #### 1. ok_sub_spot_X_ticker 订阅行情数据
  104. *
  105. * @param currencyPair Currency pair of the ticker
  106. * @param args
  107. * @return
  108. */
  109. @Override
  110. public Observable<Ticker> getTicker(CurrencyPair currencyPair, Object... args) {
  111. String channel =
  112. String.format(
  113. "ok_sub_spot_%s_%s_ticker",
  114. currencyPair.base.toString().toLowerCase(),
  115. currencyPair.counter.toString().toLowerCase());
  116. return service
  117. .subscribeChannel(channel)
  118. .map(
  119. s -> {
  120. // TODO: fix parsing of BigDecimal attribute val that has format: 1,625.23
  121. OkCoinTicker okCoinTicker = mapper.treeToValue(s.get("data"), OkCoinTicker.class);
  122. return OkCoinAdapters.adaptTicker(
  123. new OkCoinTickerResponse(okCoinTicker), currencyPair);
  124. });
  125. }
  126. /**
  127. * #### future #### 1. ok_sub_futureusd_X_ticker_Y 订阅合约行情 1. ok_sub_futureusd_X_ticker_Y Subscribe
  128. * Contract Market Price
  129. *
  130. * @param currencyPair Currency pair of the ticker
  131. * @param contract {@link FuturesContract}
  132. * @return
  133. */
  134. public Observable<FutureTicker> getFutureTicker(
  135. CurrencyPair currencyPair, FuturesContract contract) {
  136. String channel =
  137. String.format(
  138. "ok_sub_future%s_%s_ticker_%s",
  139. currencyPair.counter.toString().toLowerCase(),
  140. currencyPair.base.toString().toLowerCase(),
  141. contract.getName());
  142. return service
  143. .subscribeChannel(channel)
  144. .map(s -> mapper.treeToValue(s.get("data"), FutureTicker.class));
  145. }
  146. /**
  147. * #### spot #### 4. ok_sub_spot_X_deals 订阅成交记录
  148. *
  149. * <p>#### future #### 5. ok_sub_futureusd_X_trade_Y 订阅合约交易信息 5. ok_sub_futureusd_X_trade_Y
  150. * Subscribe Contract Trade Record
  151. *
  152. * @param currencyPair Currency pair of the trades
  153. * @param args the first arg {@link FuturesContract}
  154. * @return
  155. */
  156. @Override
  157. public Observable<Trade> getTrades(CurrencyPair currencyPair, Object... args) {
  158. String channel =
  159. String.format(
  160. "ok_sub_spot_%s_%s_deals",
  161. currencyPair.base.toString().toLowerCase(),
  162. currencyPair.counter.toString().toLowerCase());
  163. if (args.length > 0) {
  164. FuturesContract contract = (FuturesContract) args[0];
  165. channel =
  166. String.format(
  167. "ok_sub_future%s_%s_trade_%s",
  168. currencyPair.counter.toString().toLowerCase(),
  169. currencyPair.base.toString().toLowerCase(),
  170. contract.getName());
  171. }
  172. return service
  173. .subscribeChannel(channel)
  174. .map(
  175. s -> {
  176. String[][] trades = mapper.treeToValue(s.get("data"), String[][].class);
  177. // I don't know how to parse this array of arrays in Jacson.
  178. OkCoinWebSocketTrade[] okCoinTrades = new OkCoinWebSocketTrade[trades.length];
  179. for (int i = 0; i < trades.length; ++i) {
  180. OkCoinWebSocketTrade okCoinWebSocketTrade = new OkCoinWebSocketTrade(trades[i]);
  181. okCoinTrades[i] = okCoinWebSocketTrade;
  182. }
  183. return OkCoinAdapters.adaptTrades(okCoinTrades, currencyPair);
  184. })
  185. .flatMapIterable(Trades::getTrades);
  186. }
  187. }