Skip to content

Commit 528df33

Browse files
authored
Merge pull request #23 from namjug-kim/develop
Develop
2 parents 5b43d3d + b314083 commit 528df33

File tree

35 files changed

+1213
-231
lines changed

35 files changed

+1213
-231
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Support public market feature (tickData, orderBook)
1717
| ![bithumb](https://user-images.githubusercontent.com/16334718/57194948-e54fef80-6f87-11e9-90d8-41f108789c77.jpg) | Bithumb | BITHUMB | ⚠️ | ⚠️ |
1818
| ![hubi](https://user-images.githubusercontent.com/16334718/57194945-e4b75900-6f87-11e9-8fea-889fc93a7ba4.jpg) | Hubi | HUBI | * | [ws](https://www.hubi.com/docs/index-en.pdf) |
1919
| ![bitmex](https://user-images.githubusercontent.com/16334718/57194950-e54fef80-6f87-11e9-8b54-3f2192012306.jpg) | Bitmex | BITMEX | * | [ws](https://www.bitmex.com/app/wsAPI) |
20+
| ![kraken](https://user-images.githubusercontent.com/16334718/57220400-2dc5e680-7036-11e9-803c-18b14e82921a.jpg) | Kraken | KRAKEN | 0.1.1 | [ws](https://www.kraken.com/features/websocket-api) |
2021

2122
⚠️ : Uses endpoints that are used by the official web. This is not an official api and should be used with care.
2223

reactive-crypto-binance/src/main/kotlin/com/njkim/reactivecrypto/binance/BinanceJsonObjectMapper.kt

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,57 +19,50 @@ package com.njkim.reactivecrypto.binance
1919
import com.fasterxml.jackson.core.JsonParser
2020
import com.fasterxml.jackson.core.JsonProcessingException
2121
import com.fasterxml.jackson.databind.DeserializationContext
22-
import com.fasterxml.jackson.databind.DeserializationFeature
2322
import com.fasterxml.jackson.databind.JsonDeserializer
24-
import com.fasterxml.jackson.databind.ObjectMapper
25-
import com.fasterxml.jackson.databind.module.SimpleModule
26-
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
2723
import com.njkim.reactivecrypto.binance.BinanceCommonUtil.parseCurrencyPair
24+
import com.njkim.reactivecrypto.core.ExchangeJsonObjectMapper
2825
import com.njkim.reactivecrypto.core.common.model.currency.CurrencyPair
2926
import mu.KotlinLogging
30-
import org.apache.commons.lang3.StringUtils
3127
import java.io.IOException
3228
import java.math.BigDecimal
3329
import java.time.Instant
3430
import java.time.ZoneId
3531
import java.time.ZonedDateTime
3632

37-
class BinanceJsonObjectMapper {
33+
class BinanceJsonObjectMapper : ExchangeJsonObjectMapper {
3834
private val log = KotlinLogging.logger {}
3935

40-
companion object {
41-
val instance = BinanceJsonObjectMapper().objectMapper()
42-
}
43-
44-
private fun objectMapper(): ObjectMapper {
45-
val simpleModule = SimpleModule()
46-
47-
simpleModule.addDeserializer(ZonedDateTime::class.java, object : JsonDeserializer<ZonedDateTime>() {
36+
override fun zonedDateTimeDeserializer(): JsonDeserializer<ZonedDateTime>? {
37+
return object : JsonDeserializer<ZonedDateTime>() {
4838
@Throws(IOException::class, JsonProcessingException::class)
4939
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): ZonedDateTime {
5040
return ZonedDateTime.ofInstant(Instant.ofEpochMilli(p.longValue), ZoneId.systemDefault())
5141
}
52-
})
53-
simpleModule.addDeserializer(BigDecimal::class.java, object : JsonDeserializer<BigDecimal>() {
42+
}
43+
}
44+
45+
override fun bigDecimalDeserializer(): JsonDeserializer<BigDecimal>? {
46+
return object : JsonDeserializer<BigDecimal>() {
5447
@Throws(IOException::class, JsonProcessingException::class)
5548
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): BigDecimal? {
5649
val valueAsString = p.valueAsString
57-
return if (StringUtils.isBlank(valueAsString)) {
50+
return if (valueAsString.isBlank()) {
5851
null
59-
} else BigDecimal(valueAsString)
52+
} else {
53+
BigDecimal(valueAsString)
54+
}
6055
}
61-
})
62-
simpleModule.addDeserializer(CurrencyPair::class.java, object : JsonDeserializer<CurrencyPair>() {
56+
}
57+
}
58+
59+
override fun currencyPairDeserializer(): JsonDeserializer<CurrencyPair>? {
60+
return object : JsonDeserializer<CurrencyPair>() {
6361
@Throws(IOException::class, JsonProcessingException::class)
6462
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): CurrencyPair? {
6563
val rawValue = p.valueAsString
6664
return parseCurrencyPair(rawValue)
6765
}
68-
})
69-
70-
val objectMapper = ObjectMapper().registerKotlinModule()
71-
objectMapper.registerModule(simpleModule)
72-
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
73-
return objectMapper
66+
}
7467
}
7568
}

reactive-crypto-binance/src/main/kotlin/com/njkim/reactivecrypto/binance/BinanceWebsocketClient.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ import com.fasterxml.jackson.module.kotlin.readValue
2121
import com.njkim.reactivecrypto.binance.model.BinanceOrderBook
2222
import com.njkim.reactivecrypto.binance.model.BinanceResponseWrapper
2323
import com.njkim.reactivecrypto.binance.model.BinanceTickData
24-
import com.njkim.reactivecrypto.core.ExchangeWebsocketClient
24+
import com.njkim.reactivecrypto.core.AbstractExchangeWebsocketClient
25+
import com.njkim.reactivecrypto.core.ExchangeJsonObjectMapper
2526
import com.njkim.reactivecrypto.core.common.model.ExchangeVendor
2627
import com.njkim.reactivecrypto.core.common.model.currency.CurrencyPair
2728
import com.njkim.reactivecrypto.core.common.model.order.OrderBook
@@ -33,11 +34,16 @@ import reactor.netty.http.client.HttpClient
3334
import java.time.ZonedDateTime
3435
import java.util.stream.Collectors
3536

36-
class BinanceWebsocketClient : ExchangeWebsocketClient {
37+
class BinanceWebsocketClient : AbstractExchangeWebsocketClient() {
3738
private val log = KotlinLogging.logger {}
3839

3940
private val baseUri = "wss://stream.binance.com:9443"
40-
private val objectMapper: ObjectMapper = BinanceJsonObjectMapper.instance
41+
42+
private val objectMapper: ObjectMapper = createJsonObjectMapper().objectMapper()
43+
44+
override fun createJsonObjectMapper(): ExchangeJsonObjectMapper {
45+
return BinanceJsonObjectMapper()
46+
}
4147

4248
override fun createTradeWebsocket(subscribeTargets: List<CurrencyPair>): Flux<TickData> {
4349
val streams = subscribeTargets.stream()

reactive-crypto-bithumb/src/main/kotlin/com/njkim/reactivecrypto/bithumb/BithumbJsonObjectMapper.kt

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,32 +19,22 @@ package com.njkim.reactivecrypto.bithumb
1919
import com.fasterxml.jackson.core.JsonParser
2020
import com.fasterxml.jackson.core.JsonProcessingException
2121
import com.fasterxml.jackson.databind.DeserializationContext
22-
import com.fasterxml.jackson.databind.DeserializationFeature
2322
import com.fasterxml.jackson.databind.JsonDeserializer
24-
import com.fasterxml.jackson.databind.ObjectMapper
25-
import com.fasterxml.jackson.databind.module.SimpleModule
26-
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
23+
import com.njkim.reactivecrypto.core.ExchangeJsonObjectMapper
2724
import com.njkim.reactivecrypto.core.common.model.currency.Currency
2825
import mu.KotlinLogging
29-
import org.apache.commons.lang3.StringUtils
3026
import java.io.IOException
3127
import java.math.BigDecimal
3228
import java.time.LocalDateTime
3329
import java.time.ZoneOffset
3430
import java.time.ZonedDateTime
3531
import java.time.format.DateTimeFormatter
3632

37-
class BithumbJsonObjectMapper {
33+
class BithumbJsonObjectMapper : ExchangeJsonObjectMapper {
3834
private val log = KotlinLogging.logger {}
3935

40-
companion object {
41-
val instance = BithumbJsonObjectMapper().objectMapper()
42-
}
43-
44-
private fun objectMapper(): ObjectMapper {
45-
val simpleModule = SimpleModule()
46-
47-
simpleModule.addDeserializer(ZonedDateTime::class.java, object : JsonDeserializer<ZonedDateTime>() {
36+
override fun zonedDateTimeDeserializer(): JsonDeserializer<ZonedDateTime>? {
37+
return object : JsonDeserializer<ZonedDateTime>() {
4838
@Throws(IOException::class, JsonProcessingException::class)
4939
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): ZonedDateTime {
5040
// Bithumb use KOR(+9) timezone without zone information
@@ -54,27 +44,30 @@ class BithumbJsonObjectMapper {
5444
)
5545
return ZonedDateTime.of(parsedKorLocalDateTime, ZoneOffset.ofHours(9))
5646
}
57-
})
58-
simpleModule.addDeserializer(BigDecimal::class.java, object : JsonDeserializer<BigDecimal>() {
47+
}
48+
}
49+
50+
override fun bigDecimalDeserializer(): JsonDeserializer<BigDecimal>? {
51+
return object : JsonDeserializer<BigDecimal>() {
5952
@Throws(IOException::class, JsonProcessingException::class)
6053
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): BigDecimal? {
6154
val valueAsString = p.valueAsString
62-
return if (StringUtils.isBlank(valueAsString)) {
55+
return if (valueAsString.isBlank()) {
6356
null
64-
} else BigDecimal(valueAsString)
57+
} else {
58+
BigDecimal(valueAsString)
59+
}
6560
}
66-
})
67-
simpleModule.addDeserializer(Currency::class.java, object : JsonDeserializer<Currency>() {
61+
}
62+
}
63+
64+
override fun currencyDeserializer(): JsonDeserializer<Currency>? {
65+
return object : JsonDeserializer<Currency>() {
6866
@Throws(IOException::class, JsonProcessingException::class)
6967
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Currency? {
7068
val rawValue = p.valueAsString
7169
return Currency.valueOf(rawValue)
7270
}
73-
})
74-
75-
val objectMapper = ObjectMapper().registerKotlinModule()
76-
objectMapper.registerModule(simpleModule)
77-
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
78-
return objectMapper
71+
}
7972
}
80-
}
73+
}

reactive-crypto-bithumb/src/main/kotlin/com/njkim/reactivecrypto/bithumb/BithumbWebsocketClient.kt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616

1717
package com.njkim.reactivecrypto.bithumb
1818

19+
import com.fasterxml.jackson.databind.ObjectMapper
1920
import com.fasterxml.jackson.module.kotlin.readValue
2021
import com.njkim.reactivecrypto.bithumb.model.BithumbOrderBook
2122
import com.njkim.reactivecrypto.bithumb.model.BithumbResponseWrapper
2223
import com.njkim.reactivecrypto.bithumb.model.BithumbTickData
23-
import com.njkim.reactivecrypto.core.ExchangeWebsocketClient
24+
import com.njkim.reactivecrypto.core.AbstractExchangeWebsocketClient
25+
import com.njkim.reactivecrypto.core.ExchangeJsonObjectMapper
2426
import com.njkim.reactivecrypto.core.common.model.ExchangeVendor
2527
import com.njkim.reactivecrypto.core.common.model.currency.Currency
2628
import com.njkim.reactivecrypto.core.common.model.currency.CurrencyPair
@@ -35,11 +37,17 @@ import reactor.core.publisher.toFlux
3537
import reactor.netty.http.client.HttpClient
3638
import java.time.ZonedDateTime
3739

38-
class BithumbWebsocketClient : ExchangeWebsocketClient {
40+
class BithumbWebsocketClient : AbstractExchangeWebsocketClient() {
3941
private val log = KotlinLogging.logger {}
4042

4143
private val baseUri = "wss://wss.bithumb.com/public"
4244

45+
private val objectMapper: ObjectMapper = createJsonObjectMapper().objectMapper()
46+
47+
override fun createJsonObjectMapper(): ExchangeJsonObjectMapper {
48+
return BithumbJsonObjectMapper()
49+
}
50+
4351
override fun createTradeWebsocket(subscribeTargets: List<CurrencyPair>): Flux<TickData> {
4452
val subscribeRequests = subscribeTargets.stream()
4553
.map {
@@ -62,7 +70,7 @@ class BithumbWebsocketClient : ExchangeWebsocketClient {
6270
.then()
6371
.thenMany(inbound.receive().asString())
6472
}
65-
.map { BithumbJsonObjectMapper.instance.readValue<BithumbResponseWrapper<List<BithumbTickData>>>(it) }
73+
.map { objectMapper.readValue<BithumbResponseWrapper<List<BithumbTickData>>>(it) }
6674
.flatMapIterable {
6775
it.data.map { bithumbTickData ->
6876
TickData(
@@ -99,7 +107,7 @@ class BithumbWebsocketClient : ExchangeWebsocketClient {
99107
.then()
100108
.thenMany(inbound.receive().asString())
101109
}
102-
.map { BithumbJsonObjectMapper.instance.readValue<BithumbResponseWrapper<BithumbOrderBook>>(it) }
110+
.map { objectMapper.readValue<BithumbResponseWrapper<BithumbOrderBook>>(it) }
103111
.map {
104112
OrderBook(
105113
"${it.header.currency}${ZonedDateTime.now().toEpochMilli()}",

reactive-crypto-bitmex/src/main/kotlin/com/njkim/reactivecrypto/bitmex/BitmexJsonObjectMapper.kt

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,60 +19,51 @@ package com.njkim.reactivecrypto.bitmex
1919
import com.fasterxml.jackson.core.JsonParser
2020
import com.fasterxml.jackson.core.JsonProcessingException
2121
import com.fasterxml.jackson.databind.DeserializationContext
22-
import com.fasterxml.jackson.databind.DeserializationFeature
2322
import com.fasterxml.jackson.databind.JsonDeserializer
24-
import com.fasterxml.jackson.databind.ObjectMapper
25-
import com.fasterxml.jackson.databind.module.SimpleModule
26-
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
23+
import com.njkim.reactivecrypto.core.ExchangeJsonObjectMapper
2724
import com.njkim.reactivecrypto.core.common.model.currency.CurrencyPair
2825
import com.njkim.reactivecrypto.core.common.model.order.TradeSideType
2926
import com.njkim.reactivecrypto.core.common.util.CurrencyPairUtil
3027
import java.io.IOException
3128
import java.math.BigDecimal
3229
import java.time.ZonedDateTime
3330

34-
class BitmexJsonObjectMapper {
35-
companion object {
36-
val instance = BitmexJsonObjectMapper().objectMapper()
37-
}
38-
39-
private fun objectMapper(): ObjectMapper {
40-
val simpleModule = SimpleModule()
41-
42-
simpleModule.addDeserializer(ZonedDateTime::class.java, object : JsonDeserializer<ZonedDateTime>() {
31+
class BitmexJsonObjectMapper : ExchangeJsonObjectMapper {
32+
override fun zonedDateTimeDeserializer(): JsonDeserializer<ZonedDateTime>? {
33+
return object : JsonDeserializer<ZonedDateTime>() {
4334
@Throws(IOException::class, JsonProcessingException::class)
4435
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): ZonedDateTime {
4536
return ZonedDateTime.parse(p.valueAsString)
4637
}
47-
})
38+
}
39+
}
4840

49-
simpleModule.addDeserializer(BigDecimal::class.java, object : JsonDeserializer<BigDecimal>() {
41+
override fun bigDecimalDeserializer(): JsonDeserializer<BigDecimal>? {
42+
return object : JsonDeserializer<BigDecimal>() {
5043
@Throws(IOException::class, JsonProcessingException::class)
5144
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): BigDecimal {
5245
return BigDecimal.valueOf(p.valueAsDouble)
5346
}
54-
})
47+
}
48+
}
5549

56-
simpleModule.addDeserializer(CurrencyPair::class.java, object : JsonDeserializer<CurrencyPair>() {
50+
override fun currencyPairDeserializer(): JsonDeserializer<CurrencyPair>? {
51+
return object : JsonDeserializer<CurrencyPair>() {
5752
@Throws(IOException::class, JsonProcessingException::class)
5853
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): CurrencyPair {
5954
val parse = CurrencyPairUtil.parse(p.valueAsString)
6055
return checkNotNull(parse)
6156
}
62-
})
57+
}
58+
}
6359

64-
simpleModule.addDeserializer(TradeSideType::class.java, object : JsonDeserializer<TradeSideType>() {
60+
override fun tradeSideTypeDeserializer(): JsonDeserializer<TradeSideType>? {
61+
return object : JsonDeserializer<TradeSideType>() {
6562
@Throws(IOException::class, JsonProcessingException::class)
6663
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): TradeSideType {
6764
val valueAsString = p.valueAsString
6865
return TradeSideType.valueOf(valueAsString.toUpperCase())
6966
}
70-
})
71-
72-
val objectMapper = ObjectMapper().registerKotlinModule()
73-
objectMapper.registerModule(simpleModule)
74-
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
75-
return objectMapper
67+
}
7668
}
77-
7869
}

reactive-crypto-bitmex/src/main/kotlin/com/njkim/reactivecrypto/bitmex/BitmexWebsocketClient.kt

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616

1717
package com.njkim.reactivecrypto.bitmex
1818

19+
import com.fasterxml.jackson.databind.ObjectMapper
1920
import com.fasterxml.jackson.module.kotlin.readValue
2021
import com.njkim.reactivecrypto.bitmex.model.BitmexMessageFrame
2122
import com.njkim.reactivecrypto.bitmex.model.BitmexOrderBook
2223
import com.njkim.reactivecrypto.bitmex.model.BitmexTickData
23-
import com.njkim.reactivecrypto.core.ExchangeWebsocketClient
24+
import com.njkim.reactivecrypto.core.AbstractExchangeWebsocketClient
25+
import com.njkim.reactivecrypto.core.ExchangeJsonObjectMapper
2426
import com.njkim.reactivecrypto.core.common.model.ExchangeVendor
2527
import com.njkim.reactivecrypto.core.common.model.currency.CurrencyPair
2628
import com.njkim.reactivecrypto.core.common.model.order.OrderBook
@@ -31,12 +33,17 @@ import reactor.core.publisher.Flux
3133
import reactor.netty.http.client.HttpClient
3234

3335

34-
class BitmexWebsocketClient : ExchangeWebsocketClient {
35-
36+
class BitmexWebsocketClient : AbstractExchangeWebsocketClient() {
3637
private val log = KotlinLogging.logger {}
3738

3839
private val baseUri = "wss://www.bitmex.com/realtime"
3940

41+
private val objectMapper: ObjectMapper = createJsonObjectMapper().objectMapper()
42+
43+
override fun createJsonObjectMapper(): ExchangeJsonObjectMapper {
44+
return BitmexJsonObjectMapper()
45+
}
46+
4047
override fun createDepthSnapshot(subscribeTargets: List<CurrencyPair>): Flux<OrderBook> {
4148
val args = subscribeTargets.map { "\"orderBook10:${it.targetCurrency}${it.baseCurrency}\"" }
4249
.joinToString(",", "[", "]")
@@ -53,7 +60,7 @@ class BitmexWebsocketClient : ExchangeWebsocketClient {
5360
.thenMany(inbound.receive().asString())
5461
}
5562
.filter { it.contains("\"table\":\"orderBook10\"") }
56-
.map { BitmexJsonObjectMapper.instance.readValue<BitmexMessageFrame<List<BitmexOrderBook>>>(it) }
63+
.map { objectMapper.readValue<BitmexMessageFrame<List<BitmexOrderBook>>>(it) }
5764
.flatMapIterable { messageFrame ->
5865
messageFrame.data.map { bitmexOrderBook ->
5966
OrderBook(
@@ -85,7 +92,7 @@ class BitmexWebsocketClient : ExchangeWebsocketClient {
8592
.thenMany(inbound.receive().asString())
8693
}
8794
.filter { it.contains("\"table\":\"trade\"") }
88-
.map { BitmexJsonObjectMapper.instance.readValue<BitmexMessageFrame<List<BitmexTickData>>>(it) }
95+
.map { objectMapper.readValue<BitmexMessageFrame<List<BitmexTickData>>>(it) }
8996
.flatMapIterable {
9097
it.data
9198
.map { hubiTickData ->

0 commit comments

Comments
 (0)