-
Notifications
You must be signed in to change notification settings - Fork 217
[BitMex] Authenticated Channels #267
Changes from 15 commits
5b622dc
dcf4ca1
780c46e
8d69f38
585d0c6
fd1e93c
07a62f5
7df1989
ae51fb0
c82ca98
07a8f30
37eb5c3
730f243
a047c64
93bf0b4
ef2632d
dd56579
cf395c9
1d0ac63
3714584
a11dfe5
856118c
6832744
5317da3
86b3e3a
6f52ed0
f12bd8d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ | |
<groupId>info.bitrich.xchange-stream</groupId> | ||
<artifactId>xchange-stream-parent</artifactId> | ||
<packaging>pom</packaging> | ||
<version>4.3.13-SNAPSHOT</version> | ||
<version>4.3.14-SNAPSHOT</version> | ||
|
||
<modules> | ||
<module>xchange-stream-core</module> | ||
|
@@ -80,7 +80,7 @@ | |
</repositories> | ||
|
||
<properties> | ||
<xchange.version>4.3.13</xchange.version> | ||
<xchange.version>4.3.14-SNAPSHOT</xchange.version> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you change this to 4.3.14? It's been released now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. will do |
||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> | ||
<maven.compiler.source>1.8</maven.compiler.source> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,12 +13,12 @@ | |
*/ | ||
public class BitmexStreamingExchange extends BitmexExchange implements StreamingExchange { | ||
private static final String API_URI = "wss://www.bitmex.com/realtime"; | ||
private static final String API_SANDBOX_URI = "wss://testnet.bitmex.com/realtime"; | ||
|
||
private final BitmexStreamingService streamingService; | ||
private BitmexStreamingService streamingService; | ||
private BitmexStreamingMarketDataService streamingMarketDataService; | ||
|
||
public BitmexStreamingExchange() { | ||
this.streamingService = new BitmexStreamingService(API_URI); | ||
} | ||
|
||
protected BitmexStreamingExchange(BitmexStreamingService streamingService) { | ||
|
@@ -28,6 +28,11 @@ protected BitmexStreamingExchange(BitmexStreamingService streamingService) { | |
@Override | ||
protected void initServices() { | ||
super.initServices(); | ||
if (exchangeSpecification.getExchangeSpecificParametersItem(USE_SANDBOX).equals(true)) | ||
this.streamingService = new BitmexStreamingService(API_SANDBOX_URI, exchangeSpecification); | ||
else | ||
this.streamingService = new BitmexStreamingService(API_URI, exchangeSpecification); | ||
|
||
streamingMarketDataService = new BitmexStreamingMarketDataService(streamingService); | ||
} | ||
|
||
|
@@ -65,4 +70,8 @@ public boolean isAlive() { | |
|
||
@Override | ||
public void useCompressedMessages(boolean compressedMessages) { streamingService.useCompressedMessages(compressedMessages); } | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rather than exposing the streaming service directly, perhaps it might be cleaner to add some specialised methods to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I agree, I wanted to open this up for discussuion |
||
public BitmexStreamingService getStreamingService() { | ||
return streamingService; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,56 @@ | ||
package info.bitrich.xchangestream.bitmex; | ||
|
||
import java.io.IOException; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import io.netty.handler.codec.http.websocketx.extensions.WebSocketClientExtensionHandler; | ||
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketClientCompressionHandler; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import com.fasterxml.jackson.databind.DeserializationFeature; | ||
import com.fasterxml.jackson.databind.JsonNode; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
|
||
import info.bitrich.xchangestream.bitmex.dto.BitmexWebSocketSubscriptionMessage; | ||
import info.bitrich.xchangestream.bitmex.dto.BitmexWebSocketTransaction; | ||
import info.bitrich.xchangestream.service.netty.JsonNettyStreamingService; | ||
import io.netty.handler.codec.http.websocketx.extensions.WebSocketClientExtensionHandler; | ||
import io.reactivex.Observable; | ||
import org.knowm.xchange.ExchangeSpecification; | ||
import org.knowm.xchange.bitmex.service.BitmexDigest; | ||
import org.knowm.xchange.utils.nonce.ExpirationTimeFactory; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import si.mazi.rescu.SynchronizedValueFactory; | ||
|
||
import java.io.IOException; | ||
|
||
/** | ||
* Created by Lukas Zaoralek on 13.11.17. | ||
*/ | ||
public class BitmexStreamingService extends JsonNettyStreamingService { | ||
private static final Logger LOG = LoggerFactory.getLogger(BitmexStreamingService.class); | ||
private ExchangeSpecification exchangeSpecification; | ||
|
||
public BitmexStreamingService(String apiUrl) { | ||
super(apiUrl, Integer.MAX_VALUE); | ||
this.exchangeSpecification = null; | ||
} | ||
public BitmexStreamingService(String apiUrl, ExchangeSpecification exchangeSpecification) { | ||
super(apiUrl, Integer.MAX_VALUE); | ||
this.exchangeSpecification = exchangeSpecification; | ||
} | ||
|
||
@Override | ||
@Override | ||
protected void handleMessage(JsonNode message) { | ||
// if (message.has("info") && message.get("info").asText().startsWith("Welcome ")) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this commented-out code be removed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes |
||
// if (exchangeSpecification.getApiKey() != null && exchangeSpecification.getSecretKey() != null) { | ||
// try { | ||
//TODO: send this onConnect | ||
// sendMessage(getAuthenticateMessage()); | ||
// } catch (Exception e) { | ||
// handleError(message, e); | ||
// } | ||
// } | ||
// return; | ||
// } | ||
if (message.has("info") || message.has("success")) { | ||
return; | ||
} | ||
if (message.has("error")) { | ||
String error = message.get("error").asText(); | ||
LOG.error("Error with message: " + error); | ||
LOG.debug("Error with message: " + message.toString()); | ||
return; | ||
} | ||
|
||
|
@@ -52,14 +67,19 @@ public Observable<BitmexWebSocketTransaction> subscribeBitmexChannel(String chan | |
BitmexWebSocketTransaction transaction = objectMapper.treeToValue(s, BitmexWebSocketTransaction.class); | ||
return transaction; | ||
}) | ||
.share(); | ||
.share(); | ||
} | ||
|
||
@Override | ||
protected String getChannelNameFromMessage(JsonNode message) throws IOException { | ||
String instrument = message.get("data").get(0).get("symbol").asText(); | ||
String table = message.get("table").asText(); | ||
return String.format("%s:%s", table, instrument); | ||
final JsonNode data0 = message.get("data").get(0); | ||
final JsonNode symbolNode = data0 == null ? null : data0.get("symbol"); | ||
final JsonNode tableNode = message.get("table"); | ||
|
||
if (symbolNode == null) | ||
return tableNode.asText(); | ||
else | ||
return String.format("%s:%s", tableNode.asText(), symbolNode.asText()); | ||
} | ||
|
||
@Override | ||
|
@@ -73,4 +93,30 @@ public String getUnsubscribeMessage(String channelName) throws IOException { | |
BitmexWebSocketSubscriptionMessage subscribeMessage = new BitmexWebSocketSubscriptionMessage("unsubscribe", new String[]{}); | ||
return objectMapper.writeValueAsString(subscribeMessage); | ||
} | ||
|
||
@Override // called by NettyStreamingService.resubscribeChannels | ||
public String getAuthenticateMessage() throws IOException { | ||
// connect().blockingAwait(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Commented out code |
||
|
||
BitmexDigest bitmexDigest = BitmexDigest.createInstance(exchangeSpecification.getSecretKey(), exchangeSpecification.getApiKey() ); | ||
if (bitmexDigest == null) | ||
return null; | ||
|
||
SynchronizedValueFactory<Long> nonceFactory = new ExpirationTimeFactory(30); | ||
|
||
long nonce = nonceFactory.createValue(); | ||
String payload = "GET/realtime" + nonce; | ||
String digestString = bitmexDigest.digestString(payload); | ||
|
||
BitmexWebSocketSubscriptionMessage subscribeMessage = | ||
new BitmexWebSocketSubscriptionMessage("authKeyExpires", | ||
new Object[]{exchangeSpecification.getApiKey(), nonce, digestString}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Couldn't you just use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, i first iteration passed a digest object, but a string is suffecient now |
||
|
||
//sendMessage( ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Commented out code |
||
|
||
return objectMapper.writeValueAsString(subscribeMessage); | ||
|
||
//streamingService.sendAuthKeyExpires(new Object[]{apiKey, nonce, digestString}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Commented out code |
||
//Thread.sleep(1500); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @mdvx! Thanks for contributing, and welcome. A few review comments from me. Firstly, could you remove the version updates? They make the merge harder - we already have #268 lined up to do this next version update.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It make more channels available, beyond orderbook and klines, I can now subscribe to position, wallet, order and execution channels
My goal is to provide all data required for trading as streams, for every exchange that can do it.
Another avenue I have been looking at is Manifold, but I would rather we have a proper supported api (I have several streaming exchanges in the works)
Please feel free to take what you want can from this PR (I am not a git guru)