Skip to content

Commit 7a1fc4f

Browse files
authored
Merge pull request binance-exchange#178 from mironbalcerzak/master
Support for multi-channel subscription on single websocket.
2 parents e7995c0 + 8055ac1 commit 7a1fc4f

5 files changed

Lines changed: 72 additions & 26 deletions

File tree

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,9 @@ client.closeUserDataStream(listenKey);
280280
BinanceApiWebSocketClient client = BinanceApiClientFactory.newInstance().newWebSocketClient();
281281
```
282282

283+
User needs to be aware that REST symbols which are `upper case` differ from WebSocket symbols which must be `lower case`.
284+
In scenario of subscription with upper case styled symbol, server will return no error and subscribe to given channel - however, no events will be pushed.
285+
283286
#### Handling web socket errors
284287

285288
Each of the methods on `BinanceApiWebSocketClient`, which opens a new web socket, takes a `BinanceApiCallback`, which is
@@ -431,6 +434,37 @@ client.onUserDataUpdateEvent(listenKey, response -> {
431434
});
432435
```
433436

437+
#### Multi-channel subscription
438+
Client provides a way for user to subscribe to multiple channels using same websocket - to achieve that user needs to coma-separate symbols as it is in following examples.
439+
440+
````java
441+
client.onAggTradeEvent("ethbtc,ethusdt", (AggTradeEvent response) -> {
442+
if (Objects.equals(response.getSymbol(),"ethbtc")) {
443+
// handle ethbtc event
444+
} else if(Objects.equals(response.getSymbol()),"ethusdt")) {
445+
// handle ethusdt event
446+
}
447+
});
448+
````
449+
````java
450+
client.onDepthEvent("ethbtc,ethusdt", (DepthEvent response) -> {
451+
if (Objects.equals(response.getSymbol(),"ethbtc")) {
452+
// handle ethbtc event
453+
} else if(Objects.equals(response.getSymbol()),"ethusdt")) {
454+
// handle ethusdt event
455+
}
456+
});
457+
````
458+
````java
459+
client.onCandlestickEvent("ethbtc,ethusdt", CandlestickInterval.ONE_MINUTE, (CandlestickEvent response) -> {
460+
if (Objects.equals(response.getSymbol(),"ethbtc")) {
461+
// handle ethbtc event
462+
} else if(Objects.equals(response.getSymbol()),"ethusdt")) {
463+
// handle ethusdt event
464+
}
465+
});
466+
````
467+
434468
### Asynchronous requests
435469

436470
To make an asynchronous request it is necessary to use the `BinanceApiAsyncRestClient`, and call the method with the same name as in the synchronous version, but passing a callback [`BinanceApiCallback`](https://github.com/joaopsilva/binance-java-api/blob/master/src/main/java/com/binance/api/client/BinanceApiCallback.java) that handles the response whenever it arrives.

src/main/java/com/binance/api/client/BinanceApiWebSocketClient.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,30 @@ public interface BinanceApiWebSocketClient extends Closeable {
1818
/**
1919
* Open a new web socket to receive {@link DepthEvent depthEvents} on a callback.
2020
*
21-
* @param symbol the market symbol to subscribe to
22-
* @param callback the callback to call on new events
21+
* @param symbols market (one or coma-separated) symbol(s) to subscribe to
22+
* @param callback the callback to call on new events
2323
* @return a {@link Closeable} that allows the underlying web socket to be closed.
2424
*/
25-
Closeable onDepthEvent(String symbol, BinanceApiCallback<DepthEvent> callback);
25+
Closeable onDepthEvent(String symbols, BinanceApiCallback<DepthEvent> callback);
2626

2727
/**
2828
* Open a new web socket to receive {@link CandlestickEvent candlestickEvents} on a callback.
2929
*
30-
* @param symbol the market symbol to subscribe to
31-
* @param interval the interval of the candles tick events required
32-
* @param callback the callback to call on new events
30+
* @param symbols market (one or coma-separated) symbol(s) to subscribe to
31+
* @param interval the interval of the candles tick events required
32+
* @param callback the callback to call on new events
3333
* @return a {@link Closeable} that allows the underlying web socket to be closed.
3434
*/
35-
Closeable onCandlestickEvent(String symbol, CandlestickInterval interval, BinanceApiCallback<CandlestickEvent> callback);
35+
Closeable onCandlestickEvent(String symbols, CandlestickInterval interval, BinanceApiCallback<CandlestickEvent> callback);
3636

3737
/**
3838
* Open a new web socket to receive {@link AggTradeEvent aggTradeEvents} on a callback.
3939
*
40-
* @param symbol the market symbol to subscribe to
41-
* @param callback the callback to call on new events
40+
* @param symbols market (one or coma-separated) symbol(s) to subscribe to
41+
* @param callback the callback to call on new events
4242
* @return a {@link Closeable} that allows the underlying web socket to be closed.
4343
*/
44-
Closeable onAggTradeEvent(String symbol, BinanceApiCallback<AggTradeEvent> callback);
44+
Closeable onAggTradeEvent(String symbols, BinanceApiCallback<AggTradeEvent> callback);
4545

4646
/**
4747
* Open a new web socket to receive {@link UserDataUpdateEvent userDataUpdateEvents} on a callback.

src/main/java/com/binance/api/client/domain/event/OrderTradeUpdateEvent.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public class OrderTradeUpdateEvent {
2525
private String eventType;
2626

2727
@JsonProperty("E")
28-
private long eventTime;
28+
private Long eventTime;
2929

3030
@JsonProperty("s")
3131
private String symbol;
@@ -137,11 +137,11 @@ public void setEventType(String eventType) {
137137
this.eventType = eventType;
138138
}
139139

140-
public long getEventTime() {
140+
public Long getEventTime() {
141141
return eventTime;
142142
}
143143

144-
public void setEventTime(long eventTime) {
144+
public void setEventTime(Long eventTime) {
145145
this.eventTime = eventTime;
146146
}
147147

@@ -225,7 +225,7 @@ public void setOrderRejectReason(OrderRejectReason orderRejectReason) {
225225
this.orderRejectReason = orderRejectReason;
226226
}
227227

228-
public long getOrderId() {
228+
public Long getOrderId() {
229229
return orderId;
230230
}
231231

@@ -273,19 +273,19 @@ public void setCommissionAsset(String commissionAsset) {
273273
this.commissionAsset = commissionAsset;
274274
}
275275

276-
public long getOrderTradeTime() {
276+
public Long getOrderTradeTime() {
277277
return orderTradeTime;
278278
}
279279

280-
public void setOrderTradeTime(long orderTradeTime) {
280+
public void setOrderTradeTime(Long orderTradeTime) {
281281
this.orderTradeTime = orderTradeTime;
282282
}
283283

284-
public long getTradeId() {
284+
public Long getTradeId() {
285285
return tradeId;
286286
}
287287

288-
public void setTradeId(long tradeId) {
288+
public void setTradeId(Long tradeId) {
289289
this.tradeId = tradeId;
290290
}
291291

src/main/java/com/binance/api/client/impl/BinanceApiWebSocketClientImpl.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
import okhttp3.WebSocket;
1717

1818
import java.io.Closeable;
19+
import java.util.Arrays;
1920
import java.util.List;
21+
import java.util.stream.Collectors;
2022

2123
/**
2224
* Binance API WebSocket client implementation using OkHttp.
@@ -29,19 +31,29 @@ public BinanceApiWebSocketClientImpl(OkHttpClient client) {
2931
this.client = client;
3032
}
3133

32-
public Closeable onDepthEvent(String symbol, BinanceApiCallback<DepthEvent> callback) {
33-
final String channel = String.format("%s@depth", symbol);
34+
@Override
35+
public Closeable onDepthEvent(String symbols, BinanceApiCallback<DepthEvent> callback) {
36+
final String channel = Arrays.stream(symbols.split(","))
37+
.map(String::trim)
38+
.map(s -> String.format("%s@depth", s))
39+
.collect(Collectors.joining("/"));
3440
return createNewWebSocket(channel, new BinanceApiWebSocketListener<>(callback, DepthEvent.class));
3541
}
3642

3743
@Override
38-
public Closeable onCandlestickEvent(String symbol, CandlestickInterval interval, BinanceApiCallback<CandlestickEvent> callback) {
39-
final String channel = String.format("%s@kline_%s", symbol, interval.getIntervalId());
44+
public Closeable onCandlestickEvent(String symbols, CandlestickInterval interval, BinanceApiCallback<CandlestickEvent> callback) {
45+
final String channel = Arrays.stream(symbols.split(","))
46+
.map(String::trim)
47+
.map(s -> String.format("%s@kline_%s", s, interval.getIntervalId()))
48+
.collect(Collectors.joining("/"));
4049
return createNewWebSocket(channel, new BinanceApiWebSocketListener<>(callback, CandlestickEvent.class));
4150
}
4251

43-
public Closeable onAggTradeEvent(String symbol, BinanceApiCallback<AggTradeEvent> callback) {
44-
final String channel = String.format("%s@aggTrade", symbol);
52+
public Closeable onAggTradeEvent(String symbols, BinanceApiCallback<AggTradeEvent> callback) {
53+
final String channel = Arrays.stream(symbols.split(","))
54+
.map(String::trim)
55+
.map(s -> String.format("%s@aggTrade", s))
56+
.collect(Collectors.joining("/"));
4557
return createNewWebSocket(channel, new BinanceApiWebSocketListener<>(callback, AggTradeEvent.class));
4658
}
4759

src/test/java/com/binance/api/domain/event/UserDataUpdateEventDeserializerTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ public void testOrderUpdateEventDeserializer() {
7070
assertEquals(orderTradeUpdateEvent.getOrderStatus(), OrderStatus.CANCELED);
7171
assertEquals(orderTradeUpdateEvent.getOrderRejectReason(), OrderRejectReason.NONE);
7272

73-
assertEquals(orderTradeUpdateEvent.getOrderId(), 123456L);
74-
assertEquals(orderTradeUpdateEvent.getOrderTradeTime(), 1L);
73+
assertEquals(orderTradeUpdateEvent.getOrderId(), new Long(123456));
74+
assertEquals(orderTradeUpdateEvent.getOrderTradeTime(), new Long(1));
7575
} catch (IOException e) {
7676
fail();
7777
}

0 commit comments

Comments
 (0)