I'm currently experimenting on Binance Websocket (https://binance-docs.github.io/apidocs/spot/en/#websocket-market-streams), streaming the candlestick data for processing.
As documented, the stream will randomly close after 24 hours. What's the best way to continue the session without interruption? I mean disconnect/reconnect after 23 hours so the program will continue without losing its state.
Here's what I did. I'm using the binance-java-api https://github.com/binance-exchange/binance-java-api.
And here's how I connect:
BinanceApiWebSocketClient client =
BinanceApiClientFactory.newInstance(
appConfig.getApiKey(),
appConfig.getApiSecret(),
appConfig.isUseTestNet(),
appConfig.isUseTestNet())
.newWebSocketClient();
client.onCandlestickEvent(cryptoPair.toLowerCase(), getCandlestickInterval(),
new BinanceApiCallback<>() {
@Override
public void onResponse(final CandlestickEvent evt) {}
To solve this issue, I have used a scheduler/timer to reconnect the session every 12 hours. Since I'm using the Quarkus framework, it's readily available.
Solution: SessionManager class:
@Singleton
@Slf4j
@RequiredArgsConstructor
public class SessionManagerScheduler {
final BinanceEventHandler binanceEventHandler;
@Scheduled(cron = "0 2 */12 * * ?")
public void reconnectSession() {
log.info("Keep-Alive: Binance Session Via WebSocket -------------------------");
binanceEventHandler.timeout();
}
}
The Binance event handler:
@ApplicationScoped
@Slf4j
@RequiredArgsConstructor
public class BinanceEventHandler {
final AppConfig appConfig;
final CandlestickAccumulator candlestickAccumulator;
final CandlestickMapper candlestickMapper;
private Closeable candleStream = null;
public void start() {
streamCandleEvent();
}
public void timeout() {
try {
candleStream.close();
streamCandleEvent();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void streamCandleEvent() {
String cryptoPair = String.join(",", appConfig.getCryptoPairs());
log.info("Start listening to cryptoPair={}", cryptoPair);
candleStream = getClient().onCandlestickEvent(cryptoPair.toLowerCase(), getCandlestickInterval(),
new BinanceApiCallback<>() {
@Override
public void onResponse(final CandlestickEvent evt) {
if (!evt.getBarFinal()) {
return;
}
log.debug("Processing cryptoPair={}, event={}", cryptoPair, evt);
Candlestick candlestick = candlestickMapper.asCandleStick(evt);
candlestickAccumulator.processCandlestickEvent(candlestick);
}
@Override
public void onFailure(final Throwable cause) {
Application.hasError = true;
log.error("Fail connecting to Binance API {}", cause.getMessage());
}
}
);
}
private BinanceApiWebSocketClient getClient() {
return BinanceApiClientFactory.newInstance(
appConfig.getApiKey(),
appConfig.getApiSecret(),
appConfig.isUseTestNet(),
appConfig.isUseTestNet())
.newWebSocketClient();
}
private CandlestickInterval getCandlestickInterval() {
return CandlestickInterval.valueOf(appConfig.getCandlestickInterval());
}
}