Skip to content

Commit cca788c

Browse files
committed
feature: add new exchange 'Korbot Ex'
'Korbot EX' based on OKEX. Has the same api as okex v3.
1 parent c5efa24 commit cca788c

File tree

12 files changed

+472
-5
lines changed

12 files changed

+472
-5
lines changed

.circleci/config.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,4 @@ jobs:
3838
- run: gradle ktlint test codeCoverageReport
3939
- codecov/upload:
4040
file: build/reports/jacoco/report.xml
41-
token: dc59b779-b8a0-4f1c-ba53-35f1550ac5cc
41+
token: dc59b779-b8a0-4f1c-ba53-35f1550ac5cc

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ Support public market feature (tickData, orderBook)
3636
| ![coineal](https://user-images.githubusercontent.com/16334718/58037062-7d90cb80-7b67-11e9-9278-e8b03c5ddd86.jpg) | Coineal | COINEAL | ⚠️ | ⚠️ |
3737
| ![poloniex](https://user-images.githubusercontent.com/16334718/59551277-335a0900-8fb2-11e9-9d1e-4ab2a7574148.jpg) | Poloniex | POLONIEX | * | [ws](https://docs.poloniex.com/#websocket-api) |
3838
| ![bitstamp](https://user-images.githubusercontent.com/16334718/59565122-2c062e80-908a-11e9-8a38-6264c26aa3c2.jpg) | Bitstamp | BITSTAMP | v2 | [ws](https://www.bitstamp.net/websocket/v2/) |
39+
| ![korbotex](https://user-images.githubusercontent.com/16334718/59919092-82e07f00-9461-11e9-869a-d801dce68b08.jpg) | Korbot EX | KOTBOTEX | v3 | [ws](https://www.okex.com/docs/en/#spot_ws-all) |
3940

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

reactive-crypto-core/src/main/kotlin/com/njkim/reactivecrypto/core/common/model/ExchangeVendor.kt

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ enum class ExchangeVendor {
3232
COINEAL,
3333
POLONIEX,
3434
BITSTAMP,
35+
KORBOTEX,
3536
UNKNOWN;
3637

3738
/**

reactive-crypto-korbotex/build.gradle

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2019 namjug-kim
3+
*
4+
* LINE Corporation licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
17+
apply plugin: 'kotlin'
18+
apply plugin: 'org.jetbrains.kotlin.jvm'
19+
20+
version '1.0-SNAPSHOT'
21+
22+
dependencies {
23+
compile project(':reactive-crypto-okex')
24+
25+
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
26+
}
27+
28+
compileKotlin {
29+
kotlinOptions.jvmTarget = "1.8"
30+
}
31+
compileTestKotlin {
32+
kotlinOptions.jvmTarget = "1.8"
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2019 namjug-kim
3+
*
4+
* LINE Corporation licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
17+
package com.njkim.reactivecrypto.korbotex
18+
19+
import com.njkim.reactivecrypto.core.common.model.ExchangeVendor
20+
import com.njkim.reactivecrypto.core.common.model.currency.CurrencyPair
21+
import com.njkim.reactivecrypto.core.common.model.order.OrderBook
22+
import com.njkim.reactivecrypto.core.common.model.order.TickData
23+
import com.njkim.reactivecrypto.okex.OkexWebsocketClient
24+
import reactor.core.publisher.Flux
25+
26+
class KorbotexWebsocketClient : OkexWebsocketClient("wss://okexcomreal.bafang.com:8443/ws/v3?brokerId=151") {
27+
override fun createDepthSnapshot(subscribeTargets: List<CurrencyPair>): Flux<OrderBook> {
28+
return super.createDepthSnapshot(subscribeTargets)
29+
.map { it.copy(exchangeVendor = ExchangeVendor.KORBOTEX) }
30+
}
31+
32+
override fun createTradeWebsocket(subscribeTargets: List<CurrencyPair>): Flux<TickData> {
33+
return super.createTradeWebsocket(subscribeTargets)
34+
.map { it.copy(exchangeVendor = ExchangeVendor.KORBOTEX) }
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2019 namjug-kim
3+
*
4+
* LINE Corporation licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
17+
package com.njkim.reactivecrypto.kobotex;
18+
19+
import com.njkim.reactivecrypto.core.ExchangeClientFactory;
20+
import com.njkim.reactivecrypto.core.common.model.ExchangeVendor;
21+
import com.njkim.reactivecrypto.core.websocket.ExchangeWebsocketClient;
22+
import com.njkim.reactivecrypto.korbotex.KorbotexWebsocketClient;
23+
import org.junit.Test;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
27+
public class ExchangeClientFactoryJavaTest {
28+
@Test
29+
public void websocket_client() {
30+
ExchangeWebsocketClient exchangeWebsocketClient = ExchangeClientFactory.websocket(ExchangeVendor.KORBOTEX);
31+
32+
assertThat(exchangeWebsocketClient).isNotNull();
33+
assertThat(exchangeWebsocketClient).isInstanceOf(ExchangeWebsocketClient.class);
34+
assertThat(exchangeWebsocketClient).isExactlyInstanceOf(KorbotexWebsocketClient.class);
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* Copyright 2019 namjug-kim
3+
*
4+
* LINE Corporation licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
17+
package com.njkim.reactivecrypto.kobotex;
18+
19+
import com.njkim.reactivecrypto.core.common.model.ExchangeVendor;
20+
import com.njkim.reactivecrypto.core.common.model.currency.CurrencyPair;
21+
import com.njkim.reactivecrypto.core.common.model.order.OrderBook;
22+
import com.njkim.reactivecrypto.core.common.model.order.TickData;
23+
import com.njkim.reactivecrypto.korbotex.KorbotexWebsocketClient;
24+
import org.junit.Test;
25+
import reactor.core.publisher.Flux;
26+
import reactor.test.StepVerifier;
27+
28+
import java.math.BigDecimal;
29+
import java.util.Collections;
30+
31+
import static org.assertj.core.api.Assertions.assertThat;
32+
33+
public class KorbotexWebsocketClientJavaTest {
34+
@Test
35+
public void tick_data_subscribe() {
36+
// given
37+
CurrencyPair targetCurrencyPair = CurrencyPair.parse("BTC", "USDT");
38+
Flux<TickData> tickDataFlux = new KorbotexWebsocketClient()
39+
.createTradeWebsocket(Collections.singletonList(targetCurrencyPair));
40+
41+
// when
42+
StepVerifier.create(tickDataFlux.limitRequest(5))
43+
.expectNextCount(3)
44+
// then
45+
.assertNext(tickData -> {
46+
assertThat(tickData).isNotNull();
47+
assertThat(tickData.getCurrencyPair())
48+
.isEqualTo(targetCurrencyPair);
49+
assertThat(tickData.getExchangeVendor())
50+
.isEqualByComparingTo(ExchangeVendor.KORBOTEX);
51+
assertThat(tickData.getPrice())
52+
.isGreaterThan(BigDecimal.ZERO);
53+
assertThat(tickData.getQuantity())
54+
.isGreaterThan(BigDecimal.ZERO);
55+
})
56+
.assertNext(tickData -> {
57+
assertThat(tickData).isNotNull();
58+
assertThat(tickData.getCurrencyPair())
59+
.isEqualTo(targetCurrencyPair);
60+
assertThat(tickData.getExchangeVendor())
61+
.isEqualByComparingTo(ExchangeVendor.KORBOTEX);
62+
assertThat(tickData.getPrice())
63+
.isGreaterThan(BigDecimal.ZERO);
64+
assertThat(tickData.getQuantity())
65+
.isGreaterThan(BigDecimal.ZERO);
66+
})
67+
.verifyComplete();
68+
}
69+
70+
@Test
71+
public void orderBook_subscribe() {
72+
// given
73+
CurrencyPair targetCurrencyPair = CurrencyPair.parse("BTC", "USDT");
74+
Flux<OrderBook> orderBookFlux = new KorbotexWebsocketClient()
75+
.createDepthSnapshot(Collections.singletonList(targetCurrencyPair));
76+
77+
// when
78+
StepVerifier.create(orderBookFlux.limitRequest(5))
79+
.expectNextCount(3)
80+
// then
81+
.assertNext(orderBook -> {
82+
assertThat(orderBook).isNotNull();
83+
assertThat(orderBook.getCurrencyPair())
84+
.isEqualTo(targetCurrencyPair);
85+
assertThat(orderBook.getExchangeVendor())
86+
.isEqualByComparingTo(ExchangeVendor.KORBOTEX);
87+
assertThat(orderBook.getAsks())
88+
.isNotEmpty();
89+
assertThat(orderBook.getBids())
90+
.isNotEmpty();
91+
92+
assertThat(orderBook.getAsks().get(0).getQuantity())
93+
.isGreaterThan(BigDecimal.ZERO);
94+
assertThat(orderBook.getBids().get(0).getQuantity())
95+
.isGreaterThan(BigDecimal.ZERO);
96+
97+
assertThat(orderBook.getAsks().get(0).getPrice())
98+
.withFailMessage("ask price must be bigger than bid price")
99+
.isGreaterThan(orderBook.getBids().get(0).getPrice());
100+
101+
assertThat(orderBook.getAsks().get(0).getPrice())
102+
.withFailMessage("asks must be sorted by price asc")
103+
.isLessThan(orderBook.getAsks().get(1).getPrice());
104+
assertThat(orderBook.getBids().get(0).getPrice())
105+
.withFailMessage("bids must be sorted by price desc")
106+
.isGreaterThan(orderBook.getBids().get(1).getPrice());
107+
})
108+
.assertNext(orderBook -> {
109+
assertThat(orderBook).isNotNull();
110+
assertThat(orderBook.getCurrencyPair())
111+
.isEqualTo(targetCurrencyPair);
112+
assertThat(orderBook.getExchangeVendor())
113+
.isEqualByComparingTo(ExchangeVendor.KORBOTEX);
114+
assertThat(orderBook.getAsks())
115+
.isNotEmpty();
116+
assertThat(orderBook.getBids())
117+
.isNotEmpty();
118+
119+
assertThat(orderBook.getAsks().get(0).getQuantity())
120+
.isGreaterThan(BigDecimal.ZERO);
121+
assertThat(orderBook.getBids().get(0).getQuantity())
122+
.isGreaterThan(BigDecimal.ZERO);
123+
124+
assertThat(orderBook.getAsks().get(0).getPrice())
125+
.withFailMessage("ask price must be bigger than bid price")
126+
.isGreaterThan(orderBook.getBids().get(0).getPrice());
127+
128+
assertThat(orderBook.getAsks().get(0).getPrice())
129+
.withFailMessage("asks must be sorted by price asc")
130+
.isLessThan(orderBook.getAsks().get(1).getPrice());
131+
assertThat(orderBook.getBids().get(0).getPrice())
132+
.withFailMessage("bids must be sorted by price desc")
133+
.isGreaterThan(orderBook.getBids().get(1).getPrice());
134+
})
135+
.verifyComplete();
136+
}
137+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2019 namjug-kim
3+
*
4+
* LINE Corporation licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
17+
package com.njkim.reactivecrypto.kobotex
18+
19+
import com.njkim.reactivecrypto.core.ExchangeClientFactory
20+
import com.njkim.reactivecrypto.core.common.model.ExchangeVendor
21+
import com.njkim.reactivecrypto.core.websocket.ExchangeWebsocketClient
22+
import com.njkim.reactivecrypto.korbotex.KorbotexWebsocketClient
23+
import org.assertj.core.api.Assertions.assertThat
24+
import org.junit.Test
25+
26+
class ExchangeClientFactoryTest {
27+
@Test
28+
fun `create websocket client`() {
29+
val exchangeWebsocketClient = ExchangeClientFactory.websocket(ExchangeVendor.KORBOTEX)
30+
31+
assertThat(exchangeWebsocketClient).isNotNull
32+
assertThat(exchangeWebsocketClient).isInstanceOf(ExchangeWebsocketClient::class.java)
33+
assertThat(exchangeWebsocketClient).isExactlyInstanceOf(KorbotexWebsocketClient::class.java)
34+
}
35+
}

0 commit comments

Comments
 (0)