diff --git a/pom.xml b/pom.xml
index 821b951ff37..fd0a22a1835 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,585 +1,586 @@
-
-
- 4.0.0
-
-
- 3.0
-
-
- org.knowm.xchange
- xchange-parent
- 5.1.1-SNAPSHOT
- pom
-
- XChange
- XChange is a Java library providing a simple and consistent API for interacting with
- a diverse set of cryptocurrency exchanges.
-
-
- http://knowm.org/open-source/xchange
- 2012
-
-
-
- Knowm Inc.
- http://knowm.org/open-source/xchange/
-
-
-
- UTF-8
- UTF-8
-
- 1.8
- 3.23.1
- 3.12.0
- 2.14.1
- 2.1.0
- 1.7.0
- 4.13.2
- 1.18.22
- 3.8.2
- 1.4.5
- 0.10.2
- 2.0.6
- 5.0.0
- 3.19.2
-
- true
-
-
-
-
- Tim Molter
-
-
-
-
-
- MIT
- http://www.opensource.org/licenses/mit-license.php
- repo
- All source code is under the MIT license.
-
-
-
-
- GitHub
- https://github.com/knowm/XChange/issues
-
-
-
-
- sonatype-nexus-snapshots
- Sonatype Nexus Snapshots
- https://oss.sonatype.org/content/repositories/snapshots
-
-
- sonatype-nexus-staging
- Nexus Release Repository
- https://oss.sonatype.org/service/local/staging/deploy/maven2/
-
- https://oss.sonatype.org/content/groups/public/org/knowm/xchange
-
-
-
- scm:git:git@github.com:knowm/XChange.git
- scm:git:git@github.com:knowm/XChange.git
- git@github.com:knowm/XChange.git
- HEAD
-
-
-
- xchange-bankera
- xchange-bibox
- xchange-binance
- xchange-bitbay
- xchange-bitcoinaverage
- xchange-bitcoincharts
- xchange-bitcoincore
- xchange-bitcoinde
- xchange-bitcointoyou
- xchange-bitfinex
- xchange-bitflyer
- xchange-bithumb
- xchange-ascendex
- xchange-bitmex
- xchange-bitso
- xchange-bitstamp
- xchange-bittrex
- xchange-bity
- xchange-bitz
- xchange-bl3p
- xchange-bleutrade
- xchange-blockchain
- xchange-btcc
- xchange-btcmarkets
- xchange-btcturk
- xchange-bybit
- xchange-ccex
- xchange-cexio
- xchange-coinbase
- xchange-coinbasepro
- xchange-coincheck
- xchange-coindeal
- xchange-coindirect
- xchange-coinjar
- xchange-coinegg
- xchange-coinex
- xchange-coinone
- xchange-coinfloor
- xchange-coingi
- xchange-coinmarketcap
- xchange-coinmate
- xchange-core
- xchange-krakenfutures
- xchange-cryptowatch
- xchange-deribit
- xchange-dvchain
- xchange-dydx
- xchange-exmo
- xchange-examples
- xchange-ftx
- xchange-gateio
- xchange-globitex
- xchange-gemini
- xchange-hitbtc
- xchange-huobi
- xchange-idex
- xchange-independentreserve
- xchange-itbit
- xchange-koineks
- xchange-koinim
- xchange-kraken
- xchange-kucoin
- xchange-kuna
- xchange-lgo
- xchange-latoken
- xchange-livecoin
- xchange-luno
- xchange-lykke
- xchange-mercadobitcoin
- xchange-mexc
- xchange-okcoin
- xchange-okex
- xchange-openexchangerates
- xchange-paribu
- xchange-paymium
- xchange-poloniex
- xchange-quoine
- xchange-ripple
- xchange-serum
- xchange-simulated
- xchange-therock
- xchange-tradeogre
- xchange-truefx
- xchange-upbit
- xchange-vaultoro
- xchange-yobit
- xchange-zaif
- xchange-enigma
-
-
- xchange-stream-bankera
- xchange-stream-binance
- xchange-stream-bitfinex
- xchange-stream-bitflyer
- xchange-stream-bitmex
- xchange-stream-bitstamp
- xchange-stream-btcmarkets
- xchange-stream-cexio
- xchange-stream-coinbasepro
- xchange-stream-coinjar
- xchange-stream-coinmate
- xchange-stream-core
- xchange-stream-dydx
- xchange-stream-ftx
- xchange-stream-gateio
- xchange-stream-gemini
- xchange-stream-gemini-v2
- xchange-stream-hitbtc
- xchange-stream-huobi
- xchange-stream-kraken
- xchange-stream-kucoin
- xchange-stream-lgo
- xchange-stream-okcoin
- xchange-stream-okex
- xchange-stream-poloniex2
- xchange-stream-serum
- xchange-stream-service-core
- xchange-stream-service-netty
- xchange-stream-service-pubnub
- xchange-stream-coincheck
- xchange-stream-krakenfutures
-
-
-
- https://travis-ci.org/github/knowm/XChange
-
-
-
-
- sonatype-oss-public
- https://oss.sonatype.org/content/groups/public/
-
- true
-
-
- true
-
-
-
-
-
+
+
+ 4.0.0
+
+
+ 3.0
+
+
+ org.knowm.xchange
+ xchange-parent
+ 5.1.1-SNAPSHOT
+ pom
+
+ XChange
+ XChange is a Java library providing a simple and consistent API for interacting with
+ a diverse set of cryptocurrency exchanges.
+
+
+ http://knowm.org/open-source/xchange
+ 2012
+
+
+
+ Knowm Inc.
+ http://knowm.org/open-source/xchange/
+
+
+
+ UTF-8
+ UTF-8
+
+ 1.8
+ 3.23.1
+ 3.12.0
+ 2.14.1
+ 2.1.0
+ 1.7.0
+ 4.13.2
+ 1.18.22
+ 3.8.2
+ 1.4.5
+ 0.10.2
+ 2.0.6
+ 5.0.0
+ 3.19.2
+
+ true
+
+
+
+
+ Tim Molter
+
+
+
+
+
+ MIT
+ http://www.opensource.org/licenses/mit-license.php
+ repo
+ All source code is under the MIT license.
+
+
+
+
+ GitHub
+ https://github.com/knowm/XChange/issues
+
+
+
+
+ sonatype-nexus-snapshots
+ Sonatype Nexus Snapshots
+ https://oss.sonatype.org/content/repositories/snapshots
+
+
+ sonatype-nexus-staging
+ Nexus Release Repository
+ https://oss.sonatype.org/service/local/staging/deploy/maven2/
+
+ https://oss.sonatype.org/content/groups/public/org/knowm/xchange
+
+
+
+ scm:git:git@github.com:knowm/XChange.git
+ scm:git:git@github.com:knowm/XChange.git
+ git@github.com:knowm/XChange.git
+ HEAD
+
+
+
+ xchange-bankera
+ xchange-bibox
+ xchange-binance
+ xchange-bitbay
+ xchange-bitcoinaverage
+ xchange-bitcoincharts
+ xchange-bitcoincore
+ xchange-bitcoinde
+ xchange-bitcointoyou
+ xchange-bitfinex
+ xchange-bitflyer
+ xchange-bithumb
+ xchange-ascendex
+ xchange-bitmex
+ xchange-bitso
+ xchange-bitstamp
+ xchange-bittrex
+ xchange-bity
+ xchange-bitz
+ xchange-bl3p
+ xchange-bleutrade
+ xchange-blockchain
+ xchange-btcc
+ xchange-btcmarkets
+ xchange-btcturk
+ xchange-bybit
+ xchange-ccex
+ xchange-cexio
+ xchange-coinbase
+ xchange-coinbasepro
+ xchange-coincheck
+ xchange-coindeal
+ xchange-coindirect
+ xchange-coinjar
+ xchange-coinegg
+ xchange-coinex
+ xchange-coinone
+ xchange-coinfloor
+ xchange-coingi
+ xchange-coinmarketcap
+ xchange-coinmate
+ xchange-core
+ xchange-krakenfutures
+ xchange-cryptowatch
+ xchange-deribit
+ xchange-dvchain
+ xchange-dydx
+ xchange-exmo
+ xchange-examples
+ xchange-ftx
+ xchange-gateio
+ xchange-globitex
+ xchange-gemini
+ xchange-hitbtc
+ xchange-huobi
+ xchange-idex
+ xchange-independentreserve
+ xchange-itbit
+ xchange-koineks
+ xchange-koinim
+ xchange-kraken
+ xchange-kucoin
+ xchange-kuna
+ xchange-lgo
+ xchange-latoken
+ xchange-livecoin
+ xchange-luno
+ xchange-lykke
+ xchange-mercadobitcoin
+ xchange-mexc
+ xchange-okcoin
+ xchange-okex
+ xchange-openexchangerates
+ xchange-paribu
+ xchange-paymium
+ xchange-poloniex
+ xchange-quoine
+ xchange-ripple
+ xchange-serum
+ xchange-simulated
+ xchange-therock
+ xchange-tradeogre
+ xchange-truefx
+ xchange-upbit
+ xchange-vaultoro
+ xchange-yobit
+ xchange-zaif
+ xchange-enigma
+
+
+ xchange-stream-bankera
+ xchange-stream-binance
+ xchange-stream-bitfinex
+ xchange-stream-bitflyer
+ xchange-stream-bitmex
+ xchange-stream-bitstamp
+ xchange-stream-btcmarkets
+ xchange-stream-cexio
+ xchange-stream-coinbasepro
+ xchange-stream-coinjar
+ xchange-stream-coinmate
+ xchange-stream-core
+ xchange-stream-dydx
+ xchange-stream-ftx
+ xchange-stream-gateio
+ xchange-stream-gemini
+ xchange-stream-gemini-v2
+ xchange-stream-hitbtc
+ xchange-stream-huobi
+ xchange-stream-kraken
+ xchange-stream-kucoin
+ xchange-stream-lgo
+ xchange-stream-okcoin
+ xchange-stream-okex
+ xchange-stream-poloniex2
+ xchange-stream-serum
+ xchange-stream-service-core
+ xchange-stream-service-netty
+ xchange-stream-service-pubnub
+ xchange-stream-coincheck
+ xchange-stream-krakenfutures
+ xchange-stream-vertex
+
+
+
+ https://travis-ci.org/github/knowm/XChange
+
+
+
+
+ sonatype-oss-public
+ https://oss.sonatype.org/content/groups/public/
+
+ true
+
+
+ true
+
+
+
+
+
+
+
+
+
+ com.github.mmazi
+ rescu
+ ${version.github.mmazi}
+
+
+ commons-codec
+ commons-codec
+
+
+
+
+
+ io.github.resilience4j
+ resilience4j-ratelimiter
+ ${version.resilience4j}
+
+
+
+ io.github.resilience4j
+ resilience4j-retry
+ ${version.resilience4j}
+
+
+
+
+ org.apache.commons
+ commons-lang3
+ ${version.commons.lang3}
+
+
+
+
+ org.knowm.xchart
+ xchart
+ ${version.knowm.xchart}
+
+
+
+
+ org.reflections
+ reflections
+ ${version.reflections}
+ test
+
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-csv
+ ${version.fasterxml}
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${version.fasterxml}
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ ${version.fasterxml}
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ ${version.fasterxml}
+
+
+ org.web3j
+ crypto
+ ${version.crypto}
+
+
+
+ com.google.guava
+ guava
+ 31.1-jre
+
+
+
+ org.mockito
+ mockito-core
+ 3.12.4
+ test
+
+
+
+ com.github.tomakehurst
+ wiremock-jre8
+ 2.35.0
+ test
+
+
+
+
+ ch.qos.logback
+ logback-classic
+ ${version.qos.logback}
+
+
+
+
+ org.projectlombok
+ lombok
+ ${version.lombok}
+ provided
+
+
+
+
+ com.auth0
+ java-jwt
+ ${version.java-jwt}
+
+
+
+
+ io.reactivex.rxjava2
+ rxjava
+ 2.2.21
+
+
+ com.pubnub
+ pubnub-gson
+ 4.31.3
+
+
+
+ io.netty
+ netty-all
+ 4.1.86.Final
+
+
+
+
+
+
+
+
+
+ org.slf4j
+ slf4j-api
+ ${version.slf4j}
+
+
+
+
+ javax.annotation
+ javax.annotation-api
+ 1.3.2
+
-
-
- com.github.mmazi
- rescu
- ${version.github.mmazi}
-
-
- commons-codec
- commons-codec
-
-
-
-
-
- io.github.resilience4j
- resilience4j-ratelimiter
- ${version.resilience4j}
-
-
-
- io.github.resilience4j
- resilience4j-retry
- ${version.resilience4j}
-
-
-
-
- org.apache.commons
- commons-lang3
- ${version.commons.lang3}
-
-
-
-
- org.knowm.xchart
- xchart
- ${version.knowm.xchart}
-
-
-
-
- org.reflections
- reflections
- ${version.reflections}
- test
-
-
-
- com.fasterxml.jackson.dataformat
- jackson-dataformat-csv
- ${version.fasterxml}
-
-
- com.fasterxml.jackson.core
- jackson-databind
- ${version.fasterxml}
-
+
- com.fasterxml.jackson.core
- jackson-annotations
- ${version.fasterxml}
+ ch.qos.logback
+ logback-classic
+ test
+
+
- com.fasterxml.jackson.core
- jackson-core
- ${version.fasterxml}
+ junit
+ junit
+ ${version.junit}
+ test
-
- org.web3j
- crypto
- ${version.crypto}
-
-
-
- com.google.guava
- guava
- 31.1-jre
-
-
-
- org.mockito
- mockito-core
- 3.12.4
- test
-
-
-
- com.github.tomakehurst
- wiremock-jre8
- 2.35.0
- test
-
-
-
-
- ch.qos.logback
- logback-classic
- ${version.qos.logback}
-
-
-
-
- org.projectlombok
- lombok
- ${version.lombok}
- provided
-
-
-
-
- com.auth0
- java-jwt
- ${version.java-jwt}
-
-
-
-
- io.reactivex.rxjava2
- rxjava
- 2.2.21
-
-
- com.pubnub
- pubnub-gson
- 4.31.3
-
-
- io.netty
- netty-all
- 4.1.86.Final
+ org.assertj
+ assertj-core
+ ${version.assertj}
+ test
-
-
-
-
-
-
- org.slf4j
- slf4j-api
- ${version.slf4j}
-
-
-
-
- javax.annotation
- javax.annotation-api
- 1.3.2
-
-
-
-
- ch.qos.logback
- logback-classic
- test
-
-
-
-
- junit
- junit
- ${version.junit}
- test
-
-
- org.assertj
- assertj-core
- ${version.assertj}
- test
-
-
-
-
-
-
- release-sign-artifacts
-
-
- gpg.passphrase
- true
-
-
-
+
+
+ release-sign-artifacts
+
+
+ gpg.passphrase
+ true
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+ 3.0.1
+
+
+ sign-artifacts
+ verify
+
+ sign
+
+
+
+ --pinentry-mode
+ loopback
+
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.2.1
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.4.1
+
+
+ attach-javadocs
+
+ jar
+
+
+ none
+
+
+
+
+
+
+
+
+
+
+
+
-
- org.apache.maven.plugins
- maven-gpg-plugin
- 3.0.1
-
-
- sign-artifacts
- verify
-
- sign
-
-
-
- --pinentry-mode
- loopback
-
-
-
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-source-plugin
- 3.2.1
-
-
- attach-sources
-
- jar
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-javadoc-plugin
- 3.4.1
-
-
- attach-javadocs
-
- jar
-
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.10.1
+
+ ${version.java}
+ ${version.java}
+ true
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-release-plugin
+ 2.5.3
+
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.2.1
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.4.1
+
+
+ attach-javadocs
+
+ jar
+
+
+
+
+ true
+ none
+ ${version.java}
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.0.0-M7
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+ 3.0.0-M7
+
+
+
+ integration-test
+ verify
+
+
+
+
+ ${skipIntegrationTests}
+
+ **/*Integration.java
+
+
+
+
+ com.coveo
+ fmt-maven-plugin
+ 2.13
- none
+ .*\.java
+ false
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.10.1
-
- ${version.java}
- ${version.java}
- true
- true
-
-
-
-
- org.apache.maven.plugins
- maven-release-plugin
- 2.5.3
-
- true
-
-
-
-
- org.apache.maven.plugins
- maven-source-plugin
- 3.2.1
-
-
- attach-sources
-
- jar
-
-
-
-
-
- org.apache.maven.plugins
- maven-javadoc-plugin
- 3.4.1
-
-
- attach-javadocs
-
- jar
-
-
-
-
- true
- none
- ${version.java}
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
- 3.0.0-M7
-
-
-
- org.apache.maven.plugins
- maven-failsafe-plugin
- 3.0.0-M7
-
-
-
- integration-test
- verify
-
-
-
-
- ${skipIntegrationTests}
-
- **/*Integration.java
-
-
-
-
- com.coveo
- fmt-maven-plugin
- 2.13
-
- .*\.java
- false
-
-
-
-
-
-
-
-
-
-
-
-
+
-
diff --git a/xchange-examples/pom.xml b/xchange-examples/pom.xml
index b83acfbc78a..207c9341a72 100755
--- a/xchange-examples/pom.xml
+++ b/xchange-examples/pom.xml
@@ -1,367 +1,372 @@
- 4.0.0
+ 4.0.0
-
- org.knowm.xchange
- xchange-parent
- 5.1.1-SNAPSHOT
-
+
+ org.knowm.xchange
+ xchange-parent
+ 5.1.1-SNAPSHOT
+
- xchange-examples
+ xchange-examples
- XChange Examples
- Provides a set of examples that demonstrate how to use XChange in client applications
+ XChange Examples
+ Provides a set of examples that demonstrate how to use XChange in client applications
- http://knowm.org/open-source/xchange/
- 2012
+ http://knowm.org/open-source/xchange/
+ 2012
-
- Knowm Inc.
- http://knowm.org/open-source/xchange/
-
+
+ Knowm Inc.
+ http://knowm.org/open-source/xchange/
+
-
-
+
+
-
- ch.qos.logback
- logback-classic
-
-
- org.knowm.xchart
- xchart
-
+
+ ch.qos.logback
+ logback-classic
+
+
+ org.knowm.xchart
+ xchart
+
-
- org.reflections
- reflections
-
+
+ org.reflections
+ reflections
+
-
-
- ${project.groupId}
- xchange-core
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-openexchangerates
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-bibox
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-binance
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-bithumb
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-bitstamp
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-bittrex
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-bitcoincharts
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-bitcoinde
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-blockchain
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-kraken
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-kucoin
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-bitfinex
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-bitmex
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-coinbase
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-coincheck
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-coinegg
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-coinbasepro
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-bitcoinaverage
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-cexio
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-coingi
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-huobi
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-itbit
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-independentreserve
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-hitbtc
- ${project.version}
-
+
+
+ ${project.groupId}
+ xchange-core
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-openexchangerates
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-bibox
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-binance
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-bithumb
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-bitstamp
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-bittrex
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-bitcoincharts
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-bitcoinde
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-blockchain
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-kraken
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-kucoin
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-bitfinex
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-bitmex
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-coinbase
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-coincheck
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-coinegg
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-coinbasepro
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-bitcoinaverage
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-cexio
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-coingi
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-huobi
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-itbit
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-independentreserve
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-hitbtc
+ ${project.version}
+
-
-
- ${project.groupId}
- xchange-paymium
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-poloniex
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-okcoin
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-okex
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-bleutrade
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-mercadobitcoin
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-bitbay
- ${project.version}
-
-
-
- ${project.groupId}
- xchange-bitso
- ${project.version}
-
-
- ${project.groupId}
- xchange-quoine
- ${project.version}
-
-
- ${project.groupId}
- xchange-ripple
- ${project.version}
-
-
- ${project.groupId}
- xchange-therock
- ${project.version}
-
-
- ${project.groupId}
- xchange-btcmarkets
- ${project.version}
-
-
- ${project.groupId}
- xchange-krakenfutures
- ${project.version}
-
-
- ${project.groupId}
- xchange-coinmate
- ${project.version}
-
-
- ${project.groupId}
- xchange-coinone
- ${project.version}
-
-
- ${project.groupId}
- xchange-upbit
- ${project.version}
-
-
- ${project.groupId}
- xchange-ccex
- ${project.version}
-
-
- ${project.groupId}
- xchange-livecoin
- ${project.version}
-
-
- ${project.groupId}
- xchange-yobit
- ${project.version}
-
-
- ${project.groupId}
- xchange-btcturk
- ${project.version}
-
-
- ${project.groupId}
- xchange-paribu
- ${project.version}
-
-
- ${project.groupId}
- xchange-koineks
- ${project.version}
-
-
- ${project.groupId}
- xchange-gateio
- ${project.version}
-
-
- ${project.groupId}
- xchange-koinim
- ${project.version}
-
-
- ${project.groupId}
- xchange-bitflyer
- ${project.version}
-
-
- ${project.groupId}
- xchange-bitz
- ${project.version}
-
-
- ${project.groupId}
- xchange-zaif
- ${project.version}
-
-
- ${project.groupId}
- xchange-coindirect
- ${project.version}
-
-
- ${project.groupId}
- xchange-dvchain
- ${project.version}
-
-
- ${project.groupId}
- xchange-bankera
- ${project.version}
-
+
+
+ ${project.groupId}
+ xchange-paymium
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-poloniex
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-okcoin
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-okex
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-bleutrade
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-mercadobitcoin
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-bitbay
+ ${project.version}
+
+
+
+ ${project.groupId}
+ xchange-bitso
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-quoine
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-ripple
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-therock
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-btcmarkets
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-krakenfutures
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-coinmate
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-coinone
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-upbit
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-ccex
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-livecoin
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-yobit
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-btcturk
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-paribu
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-koineks
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-gateio
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-koinim
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-bitflyer
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-bitz
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-zaif
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-coindirect
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-dvchain
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-bankera
+ ${project.version}
+
org.knowm.xchange
xchange-enigma
${project.version}
-
- org.knowm.xchange
- xchange-lgo
- ${project.version}
-
-
- ${project.groupId}
- xchange-deribit
- ${project.version}
-
-
+
+ org.knowm.xchange
+ xchange-lgo
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-deribit
+ ${project.version}
+
+
+ ${project.groupId}
+ xchange-stream-vertex
+ ${project.version}
+
+
diff --git a/xchange-examples/src/main/java/org/knowm/xchange/examples/vertex/VertexMarketDataExample.java b/xchange-examples/src/main/java/org/knowm/xchange/examples/vertex/VertexMarketDataExample.java
new file mode 100644
index 00000000000..6a2a0ab042f
--- /dev/null
+++ b/xchange-examples/src/main/java/org/knowm/xchange/examples/vertex/VertexMarketDataExample.java
@@ -0,0 +1,87 @@
+package org.knowm.xchange.examples.vertex;
+
+import com.knowm.xchange.vertex.VertexStreamingExchange;
+import info.bitrich.xchangestream.core.StreamingExchange;
+import info.bitrich.xchangestream.core.StreamingExchangeFactory;
+import info.bitrich.xchangestream.core.StreamingMarketDataService;
+import io.reactivex.Observable;
+import io.reactivex.disposables.CompositeDisposable;
+import io.reactivex.disposables.Disposable;
+import java.util.concurrent.atomic.AtomicLong;
+import org.knowm.xchange.ExchangeSpecification;
+import org.knowm.xchange.currency.Currency;
+import org.knowm.xchange.currency.CurrencyPair;
+import org.knowm.xchange.dto.marketdata.OrderBook;
+import org.knowm.xchange.dto.marketdata.Trade;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.web3j.crypto.Credentials;
+import org.web3j.crypto.ECKeyPair;
+import org.web3j.crypto.Keys;
+
+public class VertexMarketDataExample {
+
+ private static final Logger logger = LoggerFactory.getLogger(VertexMarketDataExample.class);
+
+
+ public static void main(String[] args) throws InterruptedException {
+ ExchangeSpecification exchangeSpecification = new ExchangeSpecification(VertexStreamingExchange.class);
+
+ String privateKey = System.getProperty("WALLET_PRIVATE_KEY");
+ ECKeyPair ecKeyPair = Credentials.create(privateKey).getEcKeyPair();
+ String address = "0x" + Keys.getAddress(ecKeyPair.getPublicKey());
+
+ exchangeSpecification.setApiKey(address);
+ exchangeSpecification.setSecretKey(privateKey);
+
+ exchangeSpecification.setExchangeSpecificParametersItem(StreamingExchange.USE_SANDBOX, true);
+
+ StreamingExchange exchange = StreamingExchangeFactory.INSTANCE.createExchange(exchangeSpecification);
+
+ exchange.connect().blockingAwait();
+
+ CurrencyPair btcUsdc = new CurrencyPair(Currency.BTC, Currency.USDC);
+ CurrencyPair ethUsdc = new CurrencyPair(Currency.ETH, Currency.USDC);
+
+ Disposable ticker = exchange.getStreamingMarketDataService().getTicker(btcUsdc)
+ .forEach(tick -> logger.info(btcUsdc + " TOB: " + tick));
+
+ Disposable disconnectBtcTOB = subscribe(exchange.getStreamingMarketDataService(), btcUsdc.toString(), 1);
+ Disposable disconnectBtc15 = subscribe(exchange.getStreamingMarketDataService(), btcUsdc.toString(), 15);
+
+ Disposable disconnectEth = subscribe(exchange.getStreamingMarketDataService(), ethUsdc.toString(), 2);
+
+ logger.info("\n\n Disconnecting 15 depth BTC-USDC \n\n");
+
+ disconnectBtc15.dispose();
+
+ logger.info("\n\n Disconnecting ETH-USDC \n\n");
+
+ disconnectEth.dispose();
+
+ Thread.sleep(10000);
+
+ disconnectBtcTOB.dispose();
+
+ ticker.dispose();
+
+ exchange.disconnect().blockingAwait();
+
+
+ }
+
+ public static Disposable subscribe(StreamingMarketDataService streamingMarketDataService, String instrument, int depth) {
+ CurrencyPair currencyPair = new CurrencyPair(instrument);
+
+ Observable orderBook = streamingMarketDataService.getOrderBook(currencyPair, depth);
+
+ AtomicLong counter = new AtomicLong(0);
+ Disposable disconnectMarketData = orderBook.subscribe(book -> logger.info("Received book update for instrument {}, depth {} #{} {}", instrument, depth, counter.incrementAndGet(), book));
+
+ Observable trades = streamingMarketDataService.getTrades(currencyPair);
+ Disposable disconnectTrades = trades.subscribe(trade -> logger.info("Received trade update for instrument {}: {}", instrument, trade));
+
+
+ return new CompositeDisposable(disconnectMarketData, disconnectTrades);
+ }
+}
diff --git a/xchange-examples/src/main/java/org/knowm/xchange/examples/vertex/VertexOrderExample.java b/xchange-examples/src/main/java/org/knowm/xchange/examples/vertex/VertexOrderExample.java
new file mode 100644
index 00000000000..f203bb51bae
--- /dev/null
+++ b/xchange-examples/src/main/java/org/knowm/xchange/examples/vertex/VertexOrderExample.java
@@ -0,0 +1,133 @@
+package org.knowm.xchange.examples.vertex;
+
+import com.knowm.xchange.vertex.VertexOrderFlags;
+import com.knowm.xchange.vertex.VertexStreamingExchange;
+import com.knowm.xchange.vertex.VertexStreamingTradeService;
+import com.knowm.xchange.vertex.dto.RewardsList;
+import info.bitrich.xchangestream.core.StreamingExchange;
+import info.bitrich.xchangestream.core.StreamingExchangeFactory;
+import io.reactivex.disposables.Disposable;
+import java.io.IOException;
+import java.math.BigDecimal;
+import org.knowm.xchange.ExchangeSpecification;
+import org.knowm.xchange.currency.CurrencyPair;
+import org.knowm.xchange.dto.Order;
+import org.knowm.xchange.dto.trade.LimitOrder;
+import org.knowm.xchange.dto.trade.MarketOrder;
+import org.knowm.xchange.service.trade.params.CancelAllOrders;
+import org.knowm.xchange.service.trade.params.DefaultCancelAllOrdersByInstrument;
+import org.knowm.xchange.service.trade.params.DefaultCancelOrderByInstrumentAndIdParams;
+import org.knowm.xchange.service.trade.params.orders.DefaultOpenOrdersParamInstrument;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.web3j.crypto.Credentials;
+import org.web3j.crypto.ECKeyPair;
+import org.web3j.crypto.Keys;
+import org.web3j.utils.Numeric;
+
+public class VertexOrderExample {
+
+ private static final Logger log = LoggerFactory.getLogger(VertexOrderExample.class);
+
+
+ public static void main(String[] args) throws IOException, InterruptedException {
+
+ ExchangeSpecification exchangeSpecification = StreamingExchangeFactory.INSTANCE
+ .createExchangeWithoutSpecification(VertexStreamingExchange.class)
+ .getDefaultExchangeSpecification();
+
+
+ ECKeyPair ecKeyPair = Credentials.create(System.getProperty("WALLET_PRIVATE_KEY")).getEcKeyPair();
+ String address = "0x" + Keys.getAddress(ecKeyPair.getPublicKey());
+ String subAccount = "default";
+
+ exchangeSpecification.setApiKey(address);
+ exchangeSpecification.setSecretKey(Numeric.toHexStringNoPrefix(ecKeyPair.getPrivateKey()));
+ exchangeSpecification.setExchangeSpecificParametersItem(StreamingExchange.USE_SANDBOX, true);
+ exchangeSpecification.setExchangeSpecificParametersItem(VertexStreamingExchange.USE_LEVERAGE, true);
+
+ exchangeSpecification.setUserName(subAccount); //subaccount name
+
+ VertexStreamingExchange exchange = (VertexStreamingExchange) StreamingExchangeFactory.INSTANCE.createExchange(exchangeSpecification);
+
+ exchange.connect().blockingAwait();
+
+
+ RewardsList rewardsList = exchange.queryRewards(address);
+ System.out.println(rewardsList);
+
+ VertexStreamingTradeService tradeService = exchange.getStreamingTradeService();
+
+
+ CurrencyPair btc = new CurrencyPair("BTC-PERP", "USDC");
+
+ Disposable trades = tradeService.getUserTrades(btc, subAccount).subscribe(userTrade -> {
+ log.info("User trade: {}", userTrade);
+ });
+
+ Disposable changes = tradeService.getOrderChanges(btc, subAccount).subscribe(order -> {
+ log.info("User order event: {}", order);
+ });
+
+ MarketOrder buy = new MarketOrder(Order.OrderType.BID, BigDecimal.valueOf(0.01), btc);
+ buy.addOrderFlag(VertexOrderFlags.TIME_IN_FORCE_IOC);
+ tradeService.placeMarketOrder(buy);
+
+ Thread.sleep(2000);
+
+ log.info("Open positions before sell: {}", tradeService.getOpenPositions());
+
+ MarketOrder sell = new MarketOrder(Order.OrderType.ASK, BigDecimal.valueOf(0.01), btc);
+ sell.addOrderFlag(VertexOrderFlags.TIME_IN_FORCE_FOK);
+ tradeService.placeMarketOrder(sell);
+
+ LimitOrder resting = new LimitOrder(Order.OrderType.BID, BigDecimal.valueOf(0.01), btc, null, null, BigDecimal.valueOf(20000));
+ String orderId = tradeService.placeLimitOrder(resting);
+
+ Thread.sleep(5000);
+
+ log.info("Open orders before cancel: {}", tradeService.getOpenOrders(new DefaultOpenOrdersParamInstrument(btc)));
+ log.info("Open positions before cancel: {}", tradeService.getOpenPositions());
+
+ tradeService.cancelOrder(new DefaultCancelOrderByInstrumentAndIdParams(btc, orderId));
+
+ log.info("Open orders after cancel: {}", tradeService.getOpenOrders(new DefaultOpenOrdersParamInstrument(btc)));
+
+ // Check leveraged shorting works
+ sell = new MarketOrder(Order.OrderType.ASK, BigDecimal.valueOf(0.01), btc);
+ sell.addOrderFlag(VertexOrderFlags.TIME_IN_FORCE_FOK);
+ tradeService.placeMarketOrder(sell);
+
+ buy = new MarketOrder(Order.OrderType.BID, BigDecimal.valueOf(0.01), btc);
+ buy.addOrderFlag(VertexOrderFlags.TIME_IN_FORCE_IOC);
+ tradeService.placeMarketOrder(buy);
+
+ Thread.sleep(2000);
+
+ LimitOrder resting2 = new LimitOrder(Order.OrderType.BID, BigDecimal.valueOf(0.01), btc, null, null, BigDecimal.valueOf(20000));
+ String orderId2 = tradeService.placeLimitOrder(resting);
+
+
+ log.info("Open orders before cancel all instrument: {}", tradeService.getOpenOrders());
+
+ tradeService.cancelOrder(new DefaultCancelAllOrdersByInstrument(btc));
+
+ log.info("Open orders after cancel: {}", tradeService.getOpenOrders(new DefaultOpenOrdersParamInstrument(btc)));
+
+
+ LimitOrder resting3 = new LimitOrder(Order.OrderType.ASK, BigDecimal.valueOf(0.01), btc, null, null, BigDecimal.valueOf(40000));
+ String orderId3 = tradeService.placeLimitOrder(resting);
+
+
+ log.info("Open orders before cancel all instrument: {}", tradeService.getOpenOrders(new DefaultOpenOrdersParamInstrument(btc)));
+
+ tradeService.cancelOrder(new CancelAllOrders() {
+ });
+
+
+ log.info("Open orders after cancel: {}", tradeService.getOpenOrders(new DefaultOpenOrdersParamInstrument(btc)));
+
+ exchange.disconnect().blockingAwait();
+
+ }
+}
diff --git a/xchange-examples/src/main/java/org/knowm/xchange/examples/vertex/VertexRewardsExample.java b/xchange-examples/src/main/java/org/knowm/xchange/examples/vertex/VertexRewardsExample.java
new file mode 100644
index 00000000000..6e04d5dca13
--- /dev/null
+++ b/xchange-examples/src/main/java/org/knowm/xchange/examples/vertex/VertexRewardsExample.java
@@ -0,0 +1,50 @@
+package org.knowm.xchange.examples.vertex;
+
+import com.knowm.xchange.vertex.VertexStreamingExchange;
+import com.knowm.xchange.vertex.dto.RewardsList;
+import info.bitrich.xchangestream.core.StreamingExchange;
+import info.bitrich.xchangestream.core.StreamingExchangeFactory;
+import java.io.IOException;
+import org.knowm.xchange.ExchangeSpecification;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.web3j.crypto.Credentials;
+import org.web3j.crypto.ECKeyPair;
+import org.web3j.crypto.Keys;
+import org.web3j.utils.Numeric;
+
+public class VertexRewardsExample {
+
+ private static final Logger log = LoggerFactory.getLogger(VertexRewardsExample.class);
+
+
+ public static void main(String[] args) throws IOException, InterruptedException {
+
+ ExchangeSpecification exchangeSpecification = StreamingExchangeFactory.INSTANCE
+ .createExchangeWithoutSpecification(VertexStreamingExchange.class)
+ .getDefaultExchangeSpecification();
+
+
+ ECKeyPair ecKeyPair = Credentials.create(System.getProperty("WALLET_PRIVATE_KEY")).getEcKeyPair();
+ String address = "0x" + Keys.getAddress(ecKeyPair.getPublicKey());
+ String subAccount = "default";
+
+ exchangeSpecification.setApiKey(address);
+ exchangeSpecification.setSecretKey(Numeric.toHexStringNoPrefix(ecKeyPair.getPrivateKey()));
+ exchangeSpecification.setExchangeSpecificParametersItem(StreamingExchange.USE_SANDBOX, true);
+ exchangeSpecification.setExchangeSpecificParametersItem(VertexStreamingExchange.USE_LEVERAGE, true);
+
+ exchangeSpecification.setUserName(subAccount); //subaccount name
+
+ VertexStreamingExchange exchange = (VertexStreamingExchange) StreamingExchangeFactory.INSTANCE.createExchange(exchangeSpecification);
+
+ exchange.connect().blockingAwait();
+
+ log.info("Querying rewards for address: " + address);
+ RewardsList rewardsList = exchange.queryRewards(address);
+ log.info("Response: " + rewardsList);
+
+ exchange.disconnect().blockingAwait();
+
+ }
+}
diff --git a/xchange-examples/src/main/java/org/knowm/xchange/examples/vertex/VertexTickerExample.java b/xchange-examples/src/main/java/org/knowm/xchange/examples/vertex/VertexTickerExample.java
new file mode 100644
index 00000000000..88681d57d8d
--- /dev/null
+++ b/xchange-examples/src/main/java/org/knowm/xchange/examples/vertex/VertexTickerExample.java
@@ -0,0 +1,40 @@
+package org.knowm.xchange.examples.vertex;
+
+import com.knowm.xchange.vertex.VertexStreamingExchange;
+import info.bitrich.xchangestream.core.StreamingExchange;
+import info.bitrich.xchangestream.core.StreamingExchangeFactory;
+import io.reactivex.disposables.Disposable;
+import org.knowm.xchange.ExchangeSpecification;
+import org.knowm.xchange.currency.CurrencyPair;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class VertexTickerExample {
+
+ private static final Logger logger = LoggerFactory.getLogger(VertexTickerExample.class);
+ public static final String BTC_USDC = "wBTC-USDC";
+
+ public static void main(String[] args) throws InterruptedException {
+ ExchangeSpecification exchangeSpecification = new ExchangeSpecification(VertexStreamingExchange.class);
+
+ exchangeSpecification.setApiKey("YOUR_WALLET_ADDRESS");
+ exchangeSpecification.setSecretKey("YOUR_WALLET_SECRET_KEY");
+ exchangeSpecification.setExchangeSpecificParametersItem(StreamingExchange.USE_SANDBOX, true);
+
+ StreamingExchange exchange = StreamingExchangeFactory.INSTANCE.createExchange(exchangeSpecification);
+
+ exchange.connect().blockingAwait();
+
+ Disposable ticker = exchange.getStreamingMarketDataService().getTicker(new CurrencyPair(BTC_USDC))
+ .forEach(tick -> logger.info(BTC_USDC + " TOB: " + tick));
+
+ Thread.sleep(30000);
+
+ ticker.dispose();
+
+ exchange.disconnect().blockingAwait();
+
+
+ }
+
+}
diff --git a/xchange-stream-service-netty/src/main/java/info/bitrich/xchangestream/service/netty/NettyStreamingService.java b/xchange-stream-service-netty/src/main/java/info/bitrich/xchangestream/service/netty/NettyStreamingService.java
index 925d9ad1e53..02a6ff087dc 100644
--- a/xchange-stream-service-netty/src/main/java/info/bitrich/xchangestream/service/netty/NettyStreamingService.java
+++ b/xchange-stream-service-netty/src/main/java/info/bitrich/xchangestream/service/netty/NettyStreamingService.java
@@ -10,6 +10,7 @@
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
+import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
@@ -34,11 +35,13 @@
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
+import io.netty.util.concurrent.ScheduledFuture;
import io.netty.util.internal.SocketUtils;
import io.netty.util.internal.StringUtil;
import io.reactivex.Completable;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
+import io.reactivex.disposables.Disposable;
import io.reactivex.subjects.PublishSubject;
import io.reactivex.subjects.Subject;
import java.io.IOException;
@@ -50,6 +53,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Supplier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -59,6 +63,7 @@ public abstract class NettyStreamingService extends ConnectableService {
protected static final Duration DEFAULT_CONNECTION_TIMEOUT = Duration.ofSeconds(10);
protected static final Duration DEFAULT_RETRY_DURATION = Duration.ofSeconds(15);
protected static final int DEFAULT_IDLE_TIMEOUT = 15;
+ private ScheduledFuture scheduledReconnection;
protected class Subscription {
@@ -84,7 +89,9 @@ public ObservableEmitter getEmitter() {
private final Duration retryDuration;
private final Duration connectionTimeout;
private final int idleTimeoutSeconds;
- private volatile NioEventLoopGroup eventLoopGroup;
+ private Supplier extends EventLoopGroup> eventLoopGroupFactory = () -> new NioEventLoopGroup(2);
+ private volatile EventLoopGroup eventLoopGroup;
+ private Class extends SocketChannel> socketChannelClass = NioSocketChannel.class;
protected final Map channels = new ConcurrentHashMap<>();
private boolean compressedMessages = false;
@@ -191,7 +198,7 @@ protected Completable openConnection() {
this::messageHandler);
if (eventLoopGroup == null || eventLoopGroup.isShutdown()) {
- eventLoopGroup = new NioEventLoopGroup(2);
+ eventLoopGroup = eventLoopGroupFactory.get();
}
new Bootstrap()
@@ -200,7 +207,7 @@ protected Completable openConnection() {
ChannelOption.CONNECT_TIMEOUT_MILLIS,
java.lang.Math.toIntExact(connectionTimeout.toMillis()))
.option(ChannelOption.SO_KEEPALIVE, true)
- .channel(NioSocketChannel.class)
+ .channel(socketChannelClass)
.handler(
new ChannelInitializer() {
@Override
@@ -281,10 +288,11 @@ protected void initChannel(SocketChannel ch) {
}
private void scheduleReconnect() {
- if (autoReconnect) {
- LOG.info("Scheduling reconnection");
+ if (autoReconnect && !isManualDisconnect.get()) {
+ LOG.info("Scheduling reconnection to " + uri.toString() + " in " + retryDuration.toMillis() + "ms");
+ if (scheduledReconnection != null) scheduledReconnection.cancel(true);
- webSocketChannel
+ scheduledReconnection = webSocketChannel
.eventLoop()
.schedule(
() ->
@@ -302,7 +310,11 @@ protected DefaultHttpHeaders getCustomHeaders() {
}
public Completable disconnect() {
- isManualDisconnect.set(true);
+ return disconnect(false);
+ }
+
+ public Completable disconnect(boolean autoReconnect) {
+ isManualDisconnect.set(!autoReconnect);
return Completable.create(
completable -> {
if (webSocketChannel != null && webSocketChannel.isOpen()) {
@@ -311,7 +323,7 @@ public Completable disconnect() {
.writeAndFlush(closeFrame)
.addListener(
future -> {
- channels.clear();
+ if (autoReconnect) channels.clear();
eventLoopGroup
.shutdownGracefully(2, idleTimeoutSeconds, TimeUnit.SECONDS)
.addListener(
@@ -359,7 +371,6 @@ public String getSubscriptionUniqueId(String channelName, Object... args) {
public abstract void messageHandler(String message);
public void sendMessage(String message) {
- LOG.debug("Sending message: {}", message);
if (webSocketChannel == null || !webSocketChannel.isOpen()) {
LOG.warn("WebSocket is not open! Call connect first.");
@@ -371,6 +382,7 @@ public void sendMessage(String message) {
return;
}
if (message != null) {
+ LOG.debug("Sending message: {}", message);
webSocketChannel.writeAndFlush(new TextWebSocketFrame(message));
}
}
@@ -419,7 +431,7 @@ public Observable subscribeChannel(String channelName, Object... args) {
() -> {
if (channels.remove(channelId) != null) {
try {
- sendMessage(getUnsubscribeMessage(channelId));
+ sendMessage(getUnsubscribeMessage(channelId, args));
} catch (IOException e) {
LOG.debug("Failed to unsubscribe channel: {} {}", channelId, e.toString());
} catch (Exception e) {
@@ -431,6 +443,7 @@ public Observable subscribeChannel(String channelName, Object... args) {
}
public void resubscribeChannels() {
+ LOG.info("Resubscribing to {} channels on {}: {}", channels.size(), uri.toString(), channels.keySet());
for (Entry entry : channels.entrySet()) {
try {
Subscription subscription = entry.getValue();
@@ -538,6 +551,7 @@ public void channelInactive(ChannelHandlerContext ctx) {
super.channelInactive(ctx);
disconnectEmitters.onNext(new Object());
LOG.info("Reopening Websocket Client because it was closed! {}", ctx.channel());
+ connectionStateModel.setState(State.CLOSED);
scheduleReconnect();
}
}
@@ -562,6 +576,14 @@ public void useCompressedMessages(boolean compressedMessages) {
this.compressedMessages = compressedMessages;
}
+ public void setEventLoopGroupFactory(Supplier extends EventLoopGroup> eventLoopGroupFactory) {
+ this.eventLoopGroupFactory = eventLoopGroupFactory;
+ }
+
+ public void setSocketChannelClass(Class extends SocketChannel> socketChannelClass) {
+ this.socketChannelClass = socketChannelClass;
+ }
+
public void setAcceptAllCertificates(boolean acceptAllCertificates) {
this.acceptAllCertificates = acceptAllCertificates;
}
diff --git a/xchange-stream-vertex/pom.xml b/xchange-stream-vertex/pom.xml
new file mode 100644
index 00000000000..445a3df6293
--- /dev/null
+++ b/xchange-stream-vertex/pom.xml
@@ -0,0 +1,60 @@
+
+
+
+ 4.0.0
+
+
+ xchange-parent
+ org.knowm.xchange
+ 5.1.1-SNAPSHOT
+
+
+ xchange-stream-vertex
+ XChange Vertex Stream
+
+
+
+ org.knowm.xchange
+ xchange-stream-core
+ ${project.version}
+ compile
+
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+ ${version.fasterxml}
+
+
+
+ org.web3j
+ crypto
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 11
+ 11
+
+
+
+
+
+
+
diff --git a/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/InstrumentDefinition.java b/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/InstrumentDefinition.java
new file mode 100644
index 00000000000..ec6ff43ead0
--- /dev/null
+++ b/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/InstrumentDefinition.java
@@ -0,0 +1,18 @@
+package com.knowm.xchange.vertex;
+
+import java.math.BigDecimal;
+import lombok.Getter;
+import lombok.ToString;
+
+@Getter
+@ToString
+public class InstrumentDefinition {
+
+ private final BigDecimal priceIncrement;
+ private final BigDecimal quantityIncrement;
+
+ public InstrumentDefinition(BigDecimal priceIncrement, BigDecimal quantityIncrement) {
+ this.priceIncrement = priceIncrement;
+ this.quantityIncrement = quantityIncrement;
+ }
+}
diff --git a/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/NanoSecondsDeserializer.java b/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/NanoSecondsDeserializer.java
new file mode 100644
index 00000000000..ba0f8203bc4
--- /dev/null
+++ b/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/NanoSecondsDeserializer.java
@@ -0,0 +1,38 @@
+package com.knowm.xchange.vertex;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.time.Instant;
+
+public class NanoSecondsDeserializer extends JsonDeserializer {
+
+ private static final BigDecimal NANOS_PER_MILLI = new BigDecimal(1000000);
+
+ private static final CacheLoader parser = new CacheLoader<>() {
+ @Override
+ public Instant load(String str) {
+ BigInteger nano = new BigInteger(str);
+ return Instant.ofEpochMilli(new BigDecimal(nano).divide(NANOS_PER_MILLI, RoundingMode.FLOOR).longValue());
+ }
+ };
+
+ public static Instant parse(String str) {
+ return instantCache.getUnchecked(str);
+ }
+
+ private static final LoadingCache instantCache = CacheBuilder.newBuilder().maximumSize(1000).build(parser);
+
+ @Override
+ public Instant deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+ return instantCache.getUnchecked(p.getValueAsString());
+
+ }
+}
diff --git a/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/Query.java b/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/Query.java
new file mode 100644
index 00000000000..f563f5114a8
--- /dev/null
+++ b/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/Query.java
@@ -0,0 +1,29 @@
+package com.knowm.xchange.vertex;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+public class Query {
+ private final String queryMsg;
+ private final Consumer respHandler;
+ private final BiConsumer errorHandler;
+
+ public Query(String queryMsg, Consumer respHandler, BiConsumer errorHandler) {
+ this.queryMsg = queryMsg;
+ this.respHandler = respHandler;
+ this.errorHandler = errorHandler;
+ }
+
+ public String getQueryMsg() {
+ return queryMsg;
+ }
+
+ public Consumer getRespHandler() {
+ return respHandler;
+ }
+
+ public BiConsumer getErrorHandler() {
+ return errorHandler;
+ }
+}
diff --git a/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/TopOfBookPrice.java b/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/TopOfBookPrice.java
new file mode 100644
index 00000000000..dde1482a3cb
--- /dev/null
+++ b/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/TopOfBookPrice.java
@@ -0,0 +1,18 @@
+package com.knowm.xchange.vertex;
+
+import java.math.BigDecimal;
+import lombok.Getter;
+import lombok.ToString;
+
+@Getter
+@ToString
+public class TopOfBookPrice {
+ private final BigDecimal bid;
+ private final BigDecimal offer;
+
+ public TopOfBookPrice(BigDecimal bid, BigDecimal offer) {
+
+ this.bid = bid;
+ this.offer = offer;
+ }
+}
diff --git a/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/VertexOrderFlags.java b/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/VertexOrderFlags.java
new file mode 100644
index 00000000000..4db8e98c498
--- /dev/null
+++ b/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/VertexOrderFlags.java
@@ -0,0 +1,11 @@
+package com.knowm.xchange.vertex;
+
+import org.knowm.xchange.dto.Order;
+
+public enum VertexOrderFlags implements Order.IOrderFlags {
+
+ TIME_IN_FORCE_IOC,
+ TIME_IN_FORCE_GTC,
+ TIME_IN_FORCE_FOK,
+ TIME_IN_FORCE_POS_ONLY
+}
diff --git a/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/VertexProductInfo.java b/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/VertexProductInfo.java
new file mode 100644
index 00000000000..e82485ab3fa
--- /dev/null
+++ b/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/VertexProductInfo.java
@@ -0,0 +1,85 @@
+package com.knowm.xchange.vertex;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import com.knowm.xchange.vertex.dto.Symbol;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.knowm.xchange.currency.CurrencyPair;
+import org.knowm.xchange.instrument.Instrument;
+
+public class VertexProductInfo {
+
+
+ private final Set spotProducts;
+
+ private final BiMap productIdToInstrument = HashBiMap.create();
+
+ private final Map takerFees = new HashMap<>();
+
+ private final Map makerFees = new HashMap<>();
+
+ private final BigDecimal takerSequencerFee;
+
+ public VertexProductInfo(Set spotProducts, Symbol[] symbols, List takerFeeList, List makerFeeList, BigDecimal takerSequencerFee) {
+ this.spotProducts = spotProducts;
+ this.takerSequencerFee = takerSequencerFee;
+ for (Symbol symbol : symbols) {
+ long productId = symbol.getProduct_id();
+ CurrencyPair usdcPair = new CurrencyPair(symbol.getSymbol(), "USDC");
+ productIdToInstrument.put(productId, usdcPair);
+ }
+
+ for (int i = 0; i < takerFeeList.size(); i++) {
+ BigDecimal value = takerFeeList.get(i);
+ if (value.compareTo(BigDecimal.ZERO) < 0) {
+ value = value.negate();
+ }
+ takerFees.put((long) i, value);
+ }
+ for (int i = 0; i < makerFeeList.size(); i++) {
+ BigDecimal value = makerFeeList.get(i);
+ if (value.compareTo(BigDecimal.ZERO) < 0) {
+ value = value.negate();
+ }
+ makerFees.put((long) i, value);
+ }
+ }
+
+ long lookupProductId(Instrument currencyPair) {
+ Long id = productIdToInstrument.inverse().get(currencyPair);
+ if (id != null) {
+ return id;
+ }
+ throw new RuntimeException("unknown product id for " + currencyPair);
+
+ }
+
+ public List getProductsIds() {
+ return new ArrayList<>(productIdToInstrument.keySet());
+ }
+
+ public boolean isSpot(Instrument instrument) {
+ return spotProducts.contains(lookupProductId(instrument));
+ }
+
+ public Instrument lookupInstrument(long productId) {
+ return productIdToInstrument.get(productId);
+ }
+
+ public BigDecimal makerTradeFee(long productId) {
+ return makerFees.get(productId);
+ }
+
+ public BigDecimal takerTradeFee(long productId) {
+ return takerFees.get(productId);
+ }
+
+ public BigDecimal takerSequencerFee() {
+ return takerSequencerFee;
+ }
+}
diff --git a/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/VertexStreamingExchange.java b/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/VertexStreamingExchange.java
new file mode 100644
index 00000000000..63c848c3f80
--- /dev/null
+++ b/xchange-stream-vertex/src/main/java/com/knowm/xchange/vertex/VertexStreamingExchange.java
@@ -0,0 +1,355 @@
+package com.knowm.xchange.vertex;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.google.common.base.MoreObjects;
+import static com.knowm.xchange.vertex.VertexStreamingService.ALL_MESSAGES;
+import com.knowm.xchange.vertex.api.VertexApi;
+import com.knowm.xchange.vertex.dto.RewardsList;
+import com.knowm.xchange.vertex.dto.RewardsRequest;
+import static com.knowm.xchange.vertex.dto.VertexModelUtils.buildSender;
+import static com.knowm.xchange.vertex.dto.VertexModelUtils.convertToDecimal;
+import static com.knowm.xchange.vertex.dto.VertexModelUtils.readX18Decimal;
+import static com.knowm.xchange.vertex.dto.VertexModelUtils.readX18DecimalArray;
+import info.bitrich.xchangestream.core.ProductSubscription;
+import info.bitrich.xchangestream.core.StreamingExchange;
+import info.bitrich.xchangestream.core.StreamingMarketDataService;
+import info.bitrich.xchangestream.service.netty.ConnectionStateModel;
+import io.reactivex.Completable;
+import io.reactivex.Observable;
+import io.reactivex.disposables.Disposable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+import org.apache.commons.lang3.StringUtils;
+import org.knowm.xchange.BaseExchange;
+import org.knowm.xchange.ExchangeSpecification;
+import org.knowm.xchange.client.ExchangeRestProxyBuilder;
+import org.knowm.xchange.exceptions.ExchangeException;
+import org.knowm.xchange.service.trade.TradeService;
+
+public class VertexStreamingExchange extends BaseExchange implements StreamingExchange {
+
+ public static final String USE_LEVERAGE = "useLeverage";
+ public static final String MAX_SLIPPAGE_RATIO = "maxSlippageRatio";
+ public static final String DEFAULT_SUB_ACCOUNT = "default";
+ public static final String PLACE_ORDER_VALID_UNTIL_MS_PROP = "placeOrderValidUntilMs";
+
+ private VertexStreamingService subscriptionStream;
+ private VertexStreamingMarketDataService streamingMarketDataService;
+ private VertexStreamingTradeService streamingTradeService;
+
+ private boolean useTestnet;
+
+ private long chainId;
+
+ private String endpointContract;
+
+ private List bookContracts;
+
+ private VertexStreamingService requestResponseStream;
+ private VertexProductInfo productInfo;
+
+ private final Map marketPrices = new ConcurrentHashMap<>();
+ private final Map increments = new HashMap<>();
+
+ private final Set spotProducts = new TreeSet<>();
+ private final Set perpProducts = new TreeSet<>();
+
+ private Observable allMessages;
+ private VertexApi restApiClient;
+
+
+ private VertexStreamingService createStreamingService(String suffix) {
+ VertexStreamingService streamingService = new VertexStreamingService(getApiUrl() + suffix);
+ applyStreamingSpecification(getExchangeSpecification(), streamingService);
+
+ return streamingService;
+ }
+
+ private String getApiUrl() {
+ return "wss://" + getHost(useTestnet);
+
+ }
+
+ @Override
+ public ExchangeSpecification getDefaultExchangeSpecification() {
+ ExchangeSpecification exchangeSpecification = new ExchangeSpecification(this.getClass());
+ String host = getHost(useTestnet);
+ exchangeSpecification.setSslUri("https://" + host);
+ exchangeSpecification.setHost(host);
+ exchangeSpecification.setExchangeName("Vertex");
+ exchangeSpecification.setExchangeDescription("Vertex - One DEX. Everything you need.");
+ return exchangeSpecification;
+ }
+
+ private static String getHost(boolean useTestnet) {
+ return useTestnet ? "test.vertexprotocol-backend.com" : "prod.vertexprotocol-backend.com";
+ }
+
+
+ public void applySpecification(ExchangeSpecification exchangeSpecification) {
+ this.useTestnet = !Boolean.FALSE.equals(exchangeSpecification.getExchangeSpecificParametersItem(USE_SANDBOX));
+
+ exchangeSpecification.setSslUri("https://" + getHost(useTestnet));
+
+ super.applySpecification(exchangeSpecification);
+ }
+
+
+ @Override
+ public void remoteInit() throws ExchangeException {
+
+ if (!requestResponseStream.isSocketOpen() && !requestResponseStream.connect().blockingAwait(10, TimeUnit.SECONDS)) {
+ throw new RuntimeException("Timeout waiting for connection");
+ }
+
+ ArrayList queries = new ArrayList<>();
+ ArrayList priceQueries = new ArrayList<>();
+ logger.info("Loading contract data and current prices");
+ queries.add(new Query("{\"type\":\"contracts\"}",
+ data1 -> {
+ chainId = Long.parseLong(data1.get("chain_id").asText());
+ endpointContract = data1.get("endpoint_addr").asText();
+ bookContracts = new ArrayList<>();
+ data1.withArray("book_addrs").elements().forEachRemaining(node -> bookContracts.add(node.asText()));
+ }, (code, error) -> logger.error("Error loading contract data: " + code + " " + error)));
+
+ List takerFees = new ArrayList<>();
+ List makerFees = new ArrayList<>();
+ AtomicReference takerSequencerFee = new AtomicReference<>();
+ String walletAddress = exchangeSpecification.getApiKey();
+ if (StringUtils.isNotEmpty(walletAddress)) {
+ queries.add(new Query("{\"type\":\"fee_rates\", \"sender\": \"" + buildSender(walletAddress, getSubAccountOrDefault()) + "\"}",
+ feeData -> {
+ readX18DecimalArray(feeData, "taker_fee_rates_x18", takerFees);
+ readX18DecimalArray(feeData, "maker_fee_rates_x18", makerFees);
+ takerSequencerFee.set(readX18Decimal(feeData, "taker_sequencer_fee"));
+ }, (code, error) -> logger.error("Error loading fees data: " + code + " " + error)));
+
+ }
+ queries.add(new Query("{\"type\":\"all_products\"}", productData -> {
+ processProductIncrements(productData.withArray("spot_products"), spotProducts);
+ processProductIncrements(productData.withArray("perp_products"), perpProducts);
+
+ productInfo = new VertexProductInfo(spotProducts, restApiClient.symbols(), takerFees, makerFees, takerSequencerFee.get());
+
+
+ for (Long productId : productInfo.getProductsIds()) {
+ if (productId != 0) {
+ Query marketPricesQuery = new Query("{\"type\":\"market_price\", \"product_id\": " + productId + "}",
+ priceData -> {
+ JsonNode bidX18 = priceData.get("bid_x18");
+ BigInteger bid = new BigInteger(bidX18.asText());
+ JsonNode offerX18 = priceData.get("ask_x18");
+ BigInteger offer = new BigInteger(offerX18.asText());
+ marketPrices.computeIfAbsent(productId, k -> new TopOfBookPrice(convertToDecimal(bid), convertToDecimal(offer)));
+ }, (code, error) -> logger.error("Error loading market prices: " + code + " " + error));
+ priceQueries.add(marketPricesQuery);
+ }
+ }
+ }, (code, error) -> logger.error("Error loading product info: " + code + " " + error)));
+
+ submitQueries(queries.toArray(new Query[0]));
+
+ submitQueries(priceQueries.toArray(new Query[0]));
+
+ }
+
+ private void processProductIncrements(ArrayNode spotProducts, Set productSet) {
+ for (JsonNode spotProduct : spotProducts) {
+ long productId = spotProduct.get("product_id").asLong();
+ if (productId == 0) { // skip USDC product
+ continue;
+ }
+ productSet.add(productId);
+ JsonNode bookInfo = spotProduct.get("book_info");
+ BigDecimal quantityIncrement = convertToDecimal(new BigInteger(bookInfo.get("size_increment").asText()));
+ BigDecimal priceIncrement = convertToDecimal(new BigInteger(bookInfo.get("price_increment_x18").asText()));
+ increments.put(productId, new InstrumentDefinition(priceIncrement, quantityIncrement));
+ }
+ }
+
+ public RewardsList queryRewards(String walletAddress) {
+ return restApiClient.rewards(new RewardsRequest(new RewardsRequest.RewardAddress(walletAddress)));
+ }
+
+ public synchronized void submitQueries(Query... queries) {
+
+ Observable stream = subscribeToAllMessages();
+
+ for (Query query : queries) {
+ CountDownLatch responseLatch = new CountDownLatch(1);
+ Disposable subscription = stream.subscribe(resp -> {
+ JsonNode requestType = resp.get("request_type");
+ if (requestType != null && requestType.textValue().startsWith("query_")) {
+ try {
+ JsonNode data = resp.get("data");
+ JsonNode error = resp.get("error");
+ JsonNode errorCode = resp.get("error_code");
+ JsonNode status = resp.get("status");
+ boolean success = status != null && status.asText().equals("success");
+
+ if (!success) {
+ query.getErrorHandler().accept(errorCode.asInt(-1), error.asText("Unknown error"));
+ } else {
+ query.getRespHandler().accept(data);
+ logger.info("Query response " + data.toPrettyString());
+ }
+ } catch (Throwable t) {
+ logger.error("Query error running " + query.getQueryMsg(), t);
+ } finally {
+ responseLatch.countDown();
+ }
+
+ }
+ }, (err) -> logger.error("Query error running " + query.getQueryMsg(), err));
+ try {
+ logger.info("Sending query " + query.getQueryMsg());
+ requestResponseStream.sendMessage(query.getQueryMsg());
+ if (!responseLatch.await(20, TimeUnit.SECONDS)) {
+ query.getErrorHandler().accept(-1, "Timed out after 20 seconds waiting for response for " + query.getQueryMsg());
+ }
+ } catch (InterruptedException e) {
+ logger.error("Failed to get contract data due to timeout");
+ } finally {
+ subscription.dispose();
+ }
+ }
+
+
+ }
+
+ public Observable subscribeToAllMessages() {
+ if (allMessages == null) {
+ allMessages = requestResponseStream.subscribeChannel(ALL_MESSAGES);
+ }
+ return allMessages;
+ }
+
+ @Override
+ protected void initServices() {
+
+ String wallet = exchangeSpecification.getApiKey();
+
+ this.subscriptionStream = createStreamingService("/subscribe");
+ this.requestResponseStream = createStreamingService("/ws");
+
+ this.restApiClient = ExchangeRestProxyBuilder.forInterface(VertexApi.class, exchangeSpecification).build();
+
+ }
+
+
+ @Override
+ public StreamingMarketDataService getStreamingMarketDataService() {
+ if (this.streamingMarketDataService == null) {
+ this.streamingMarketDataService = new VertexStreamingMarketDataService(subscriptionStream, productInfo, this);
+ }
+ return streamingMarketDataService;
+ }
+
+ @Override
+ public VertexStreamingTradeService getStreamingTradeService() {
+ if (this.streamingTradeService == null) {
+ this.streamingTradeService = new VertexStreamingTradeService(requestResponseStream, subscriptionStream, getExchangeSpecification(), productInfo, chainId, bookContracts, this, endpointContract, getStreamingMarketDataService());
+ }
+ return streamingTradeService;
+ }
+
+ @Override
+ public TradeService getTradeService() {
+ return streamingTradeService;
+ }
+
+ @Override
+ public Observable connectionStateObservable() {
+ return subscriptionStream.subscribeConnectionState();
+ }
+
+ @Override
+ public Observable reconnectFailure() {
+ return subscriptionStream.subscribeReconnectFailure();
+ }
+
+ @Override
+ public Observable