All Downloads are FREE. Search and download functionalities are using the official Maven repository.

info.bitrich.xchangestream.binance.BinanceStreamingTradeService Maven / Gradle / Ivy

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.ExecutionReportBinanceUserTransaction;
import info.bitrich.xchangestream.binance.dto.ExecutionReportBinanceUserTransaction.ExecutionType;
import info.bitrich.xchangestream.core.StreamingTradeService;
import info.bitrich.xchangestream.service.netty.StreamingObjectMapperHelper;

import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;
import io.reactivex.subjects.PublishSubject;
import io.reactivex.subjects.Subject;

import org.knowm.xchange.currency.CurrencyPair;
import org.knowm.xchange.dto.Order;
import org.knowm.xchange.dto.trade.UserTrade;
import org.knowm.xchange.exceptions.ExchangeException;
import org.knowm.xchange.exceptions.ExchangeSecurityException;

import java.io.IOException;

public class BinanceStreamingTradeService implements StreamingTradeService {

    private final Subject executionReportsPublisher = PublishSubject.create().toSerialized();

    private volatile Disposable executionReports;
    private volatile BinanceUserDataStreamingService binanceUserDataStreamingService;

    private final ObjectMapper mapper = StreamingObjectMapperHelper.getObjectMapper();

    public BinanceStreamingTradeService(BinanceUserDataStreamingService binanceUserDataStreamingService) {
        this.binanceUserDataStreamingService = binanceUserDataStreamingService;
    }

    public Observable getRawExecutionReports() {
        if (binanceUserDataStreamingService == null || !binanceUserDataStreamingService.isSocketOpen())
            throw new ExchangeSecurityException("Not authenticated");
        return executionReportsPublisher;
    }

    public Observable getOrderChanges() {
        return getRawExecutionReports()
            .filter(r -> !r.getExecutionType().equals(ExecutionType.REJECTED))
            .map(ExecutionReportBinanceUserTransaction::toOrder);
    }

    @Override
    public Observable getOrderChanges(CurrencyPair currencyPair, Object... args) {
        return getOrderChanges()
            .filter(oc -> currencyPair.equals(oc.getCurrencyPair()));
    }

    public Observable getUserTrades() {
        return getRawExecutionReports()
    		.filter(r -> r.getExecutionType().equals(ExecutionType.TRADE))
    		.map(ExecutionReportBinanceUserTransaction::toUserTrade);
    }

    @Override
    public Observable getUserTrades(CurrencyPair currencyPair, Object... args) {
        return getUserTrades().filter(t -> t.getCurrencyPair().equals(currencyPair));
    }

    /**
     * Registers subsriptions with the streaming service for the given products.
     */
    public void openSubscriptions() {
        if (binanceUserDataStreamingService != null) {
            executionReports = binanceUserDataStreamingService
                .subscribeChannel(BaseBinanceWebSocketTransaction.BinanceWebSocketTypes.EXECUTION_REPORT)
                .map(this::executionReport)
                .subscribe(executionReportsPublisher::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 (executionReports != null && !executionReports.isDisposed())
            executionReports.dispose();
        this.binanceUserDataStreamingService = binanceUserDataStreamingService;
        openSubscriptions();
    }

    private ExecutionReportBinanceUserTransaction executionReport(JsonNode json) {
        try {
            return mapper.treeToValue(json, ExecutionReportBinanceUserTransaction.class);
        } catch (IOException e) {
            throw new ExchangeException("Unable to parse execution report", e);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy