
info.bitrich.xchangestream.binance.BinanceStreamingAccountService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xchange-stream-binance Show documentation
Show all versions of xchange-stream-binance Show documentation
Development fork. Not for general use.
The newest version!
package info.bitrich.xchangestream.binance;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import info.bitrich.xchangestream.binance.dto.BaseBinanceWebSocketTransaction;
import info.bitrich.xchangestream.binance.dto.BinanceWebsocketBalance;
import info.bitrich.xchangestream.binance.dto.OutboundAccountInfoBinanceWebsocketTransaction;
import info.bitrich.xchangestream.core.StreamingAccountService;
import info.bitrich.xchangestream.service.netty.StreamingObjectMapperHelper;
import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;
import io.reactivex.subjects.BehaviorSubject;
import io.reactivex.subjects.Subject;
import org.knowm.xchange.currency.Currency;
import org.knowm.xchange.dto.account.Balance;
import org.knowm.xchange.exceptions.ExchangeException;
import org.knowm.xchange.exceptions.ExchangeSecurityException;
import java.util.List;
public class BinanceStreamingAccountService implements StreamingAccountService {
private final BehaviorSubject accountInfoLast = BehaviorSubject.create();
private final Subject accountInfoPublisher = accountInfoLast.toSerialized();
private volatile Disposable accountInfo;
private volatile BinanceUserDataStreamingService binanceUserDataStreamingService;
private final ObjectMapper mapper = StreamingObjectMapperHelper.getObjectMapper();
public BinanceStreamingAccountService(BinanceUserDataStreamingService binanceUserDataStreamingService) {
this.binanceUserDataStreamingService = binanceUserDataStreamingService;
}
public Observable getRawAccountInfo() {
if (binanceUserDataStreamingService == null || !binanceUserDataStreamingService.isSocketOpen())
throw new ExchangeSecurityException("Not authenticated");
return accountInfoPublisher;
}
public Observable getBalanceChanges() {
return getRawAccountInfo()
.map(OutboundAccountInfoBinanceWebsocketTransaction::getBalances)
.flatMap((List balances) -> Observable.fromIterable(balances))
.map(BinanceWebsocketBalance::toBalance);
}
@Override
public Observable getBalanceChanges(Currency currency, Object... args) {
return getBalanceChanges().filter(t -> t.getCurrency().equals(currency));
}
/**
* Registers subsriptions with the streaming service for the given products.
*
* As we receive messages as soon as the connection is open, we need to register subscribers to handle these before the
* first messages arrive.
*/
public void openSubscriptions() {
if (binanceUserDataStreamingService != null) {
accountInfo = binanceUserDataStreamingService
.subscribeChannel(BaseBinanceWebSocketTransaction.BinanceWebSocketTypes.OUTBOUND_ACCOUNT_INFO)
.map(this::accountInfo)
.filter(m -> accountInfoLast.getValue() == null ||
accountInfoLast.getValue().getEventTime().before(m.getEventTime()))
.subscribe(accountInfoPublisher::onNext);
}
}
/**
* User data subscriptions may have to persist across multiple socket connections to different
* URLs and therefore must act in a publisher fashion so that subscribers get an uninterrupted
* stream.
*/
void setUserDataStreamingService(BinanceUserDataStreamingService binanceUserDataStreamingService) {
if (accountInfo != null && !accountInfo.isDisposed())
accountInfo.dispose();
this.binanceUserDataStreamingService = binanceUserDataStreamingService;
openSubscriptions();
}
private OutboundAccountInfoBinanceWebsocketTransaction accountInfo(JsonNode json) {
try {
return mapper.treeToValue(json, OutboundAccountInfoBinanceWebsocketTransaction.class);
} catch (Exception e) {
throw new ExchangeException("Unable to parse account info", e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy