Skip to content
This repository has been archived by the owner on Jun 8, 2020. It is now read-only.

Consider implementing Bitfinex websocket API #8

Closed
altmind opened this issue May 29, 2017 · 10 comments
Closed

Consider implementing Bitfinex websocket API #8

altmind opened this issue May 29, 2017 · 10 comments

Comments

@altmind
Copy link
Contributor

altmind commented May 29, 2017

https://docs.bitfinex.com/v2/docs/ws-general

@LeonidShamis
Copy link
Contributor

Hi,
I'd like to try implementing Bitfinex Streaming Exchange.
I have a question:
Taking a simple case of subscribing to Ticker public channel - https://docs.bitfinex.com/v2/reference#ws-public-ticker - I see that it is not sufficient to pass only channel name and action/event (subscribe, unsubscribe). We also need to pass a symbol - specially formatted currency pair (e.g. 'tBTCUSD' for CurrencyPair.BTC_USD), for instance:

{ 
  event: 'subscribe', 
  channel: 'ticker', 
  symbol: 'tBTCUSD' 
}

So, in BitfinexStreamingMarketDataService class I would make use of BitfinexStreamingService service to subscribe to channel by calling service.subscribeChannel(channelName).
I see that BitfinexStreamingService must implement related methods defined in NettyStreamingService:

protected abstract String getChannelNameFromMessage(T message) throws IOException;
public abstract String getSubscribeMessage(String channelName) throws IOException;
public abstract String getUnsubscribeMessage(String channelName) throws IOException;

However, the above methods seems to allow constructing subscribe/unsubscribe message only based on channel name, while Bitfinex also requires a symbol when creating subscribe message.

I compared the above with another similar Streaming Exchange implementation - GDAX - and there I see that it is possible to use the above methods with only channel name (actually it is mapped to currency pair) to create subscribe message like the foloowing:

{
    "type": "subscribe",
    "product_id": ""BTC-USD"
}

Appreciate your help.

@dozd
Copy link
Member

dozd commented Jul 28, 2017

Hmm either we should do some refactoring and add varargs into these methods. Then you could be able to pass additional data for the subscribe / unsubscribe messages. Or create another implementation with different interface.

I am not sure what's best approach :).

@LeonidShamis
Copy link
Contributor

@dozd thank you for the prompt response.
I think that your suggestion with refactoring could work.
In https://github.com/LeonidShamis/TestSubscribeChannel repo I have demonstrated simplified current functionality and in https://github.com/LeonidShamis/TestSubscribeChannelWithSymbol I have tried to make the necessary changes to Abstract class method signatures and code to allow the current behavior to still work while also allowing for extra arguments.
If this refactoring approach is fine, I would try applying it to the project and hopefully create PR.

@LeonidShamis
Copy link
Contributor

@dozd I have only addressed subscribing to channel, I haven't looked at unsubscribing yet. Please have a look here - develop...LeonidShamis:develop
If this is OK, I'll create PR

@LeonidShamis
Copy link
Contributor

I've sort of hit a roadblock due to limited knowledge of RxJava :(
I think that the most important part of implementing WebSocket API for an Exchange is in the implementation of the following 3 methods in <Exchange>StreamingMarketDataService:

    @Override
    public Observable<OrderBook> getOrderBook(CurrencyPair currencyPair, Object... args) {
    @Override
    public Observable<Ticker> getTicker(CurrencyPair currencyPair, Object... args) {
    @Override
    public Observable<Trade> getTrades(CurrencyPair currencyPair, Object... args) {

I know how the data returned by the WebSocket feed looks like, but I haven't figured a way of mapping it (.map(...)) to respective Observable<> streams.

I also noticed that v1 data looks slightly different (and simpler) that v2 data. See attached.

ticker.v1.txt
ticker.v2.txt
trades.v1.txt
trades.v2.txt

@dozd
Copy link
Member

dozd commented Aug 6, 2017

@LeonidShamis that change to varags seems working for me, create PR.

About mapping - it won't be much different to another exchanges, just look there. You also need to create proper mapping class if they are not similar to polling ones.

@LeonidShamis
Copy link
Contributor

Created PR#12

@dozd
Copy link
Member

dozd commented Aug 7, 2017

Merged. I'd like to see implementation that uses these varargs in subscribing :-).

@evdubs
Copy link

evdubs commented Oct 12, 2017

In case it helps, I had a working Bitfinex WebSocket v2 client using tyrus-standalone-client and dependencies pulled in from xchange-bitfinex. The code is available on BitBucket, and the two important classes are BitfinexWebSocketSecureClient and BitfinexHmacWebsocketAuthDigest. The rest is largely related to saving data, building order books, and executing a strategy. I haven't cleaned it up, and I'm not exactly sure if the libraries are easy to port to from tyrus-standalone-client to whatever xchange-stream uses, so it may be more trouble than its worth. If you happen to have questions about the implementation, let me know.

Edit: it looks like the API has added a few more fields since I wrote the client a year or so ago, so it will likely need to be extended a bit.

@dozd
Copy link
Member

dozd commented Nov 13, 2017

Thanks to @lukaszaoralek

@dozd dozd closed this as completed Nov 13, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants