Skip to content

Commit 65b24e4

Browse files
committed
[resolves knowm#1205] Update Coinbase Api to use the new Coinbase Exchange api V2
1 parent 364e73f commit 65b24e4

File tree

63 files changed

+3966
-3
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+3966
-3
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ META-INF/
3030

3131
# externalized configuration file for keys
3232
exchangeConfiguration.json
33+
*secret.keys
3334

3435
# emacs
3536
*~
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package org.knowm.xchange.coinbase.v2;
2+
3+
import java.io.IOException;
4+
5+
import javax.ws.rs.GET;
6+
import javax.ws.rs.HeaderParam;
7+
import javax.ws.rs.Path;
8+
import javax.ws.rs.PathParam;
9+
import javax.ws.rs.Produces;
10+
import javax.ws.rs.QueryParam;
11+
import javax.ws.rs.core.MediaType;
12+
13+
import org.knowm.xchange.coinbase.v2.dto.CoinbaseException;
14+
import org.knowm.xchange.coinbase.v2.dto.marketdata.CoinbaseCurrencyData;
15+
import org.knowm.xchange.coinbase.v2.dto.marketdata.CoinbaseExchangeRateData;
16+
import org.knowm.xchange.coinbase.v2.dto.marketdata.CoinbasePriceData;
17+
import org.knowm.xchange.coinbase.v2.dto.marketdata.CoinbaseTimeData;
18+
import org.slf4j.Logger;
19+
import org.slf4j.LoggerFactory;
20+
21+
@Path("/")
22+
@Produces(MediaType.APPLICATION_JSON)
23+
public interface Coinbase {
24+
25+
public static Logger LOG = LoggerFactory.getLogger(Coinbase.class.getPackage().getName());
26+
27+
/**
28+
* All API calls should be made with a CB-VERSION header which guarantees that your call is using the correct API version.
29+
* <a href="https://developers.coinbase.com/api/v2#versioning">developers.coinbase.com/api/v2#versioning</a>
30+
*/
31+
final String CB_VERSION = "CB-VERSION";
32+
final String CB_VERSION_VALUE = "2017-11-26";
33+
34+
@GET
35+
@Path("currencies")
36+
CoinbaseCurrencyData getCurrencies(@HeaderParam(CB_VERSION) String apiVersion) throws IOException, CoinbaseException;
37+
38+
@GET
39+
@Path("exchange-rates")
40+
CoinbaseExchangeRateData getCurrencyExchangeRates(@HeaderParam(CB_VERSION) String apiVersion) throws IOException, CoinbaseException;
41+
42+
@GET
43+
@Path("prices/{pair}/buy")
44+
CoinbasePriceData getBuyPrice(@HeaderParam(CB_VERSION) String apiVersion, @PathParam("pair") String pair) throws IOException, CoinbaseException;
45+
46+
@GET
47+
@Path("prices/{pair}/sell")
48+
CoinbasePriceData getSellPrice(@HeaderParam(CB_VERSION) String apiVersion, @PathParam("pair") String pair) throws IOException, CoinbaseException;
49+
50+
@GET
51+
@Path("prices/{pair}/spot")
52+
CoinbasePriceData getSpotRate(@HeaderParam(CB_VERSION) String apiVersion, @PathParam("pair") String pair) throws IOException, CoinbaseException;
53+
54+
@GET
55+
@Path("prices/{pair}/spot")
56+
CoinbasePriceData getHistoricalSpotRate(@HeaderParam(CB_VERSION) String apiVersion, @PathParam("pair") String pair, @QueryParam("date") String date) throws IOException, CoinbaseException;
57+
58+
@GET
59+
@Path("time")
60+
CoinbaseTimeData getTime(@HeaderParam(CB_VERSION) String apiVersion) throws IOException, CoinbaseException;
61+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package org.knowm.xchange.coinbase.v2;
2+
3+
import java.io.IOException;
4+
import java.math.BigDecimal;
5+
6+
import javax.ws.rs.Consumes;
7+
import javax.ws.rs.GET;
8+
import javax.ws.rs.HeaderParam;
9+
import javax.ws.rs.POST;
10+
import javax.ws.rs.Path;
11+
import javax.ws.rs.PathParam;
12+
import javax.ws.rs.Produces;
13+
import javax.ws.rs.core.MediaType;
14+
15+
import org.knowm.xchange.coinbase.v2.dto.CoinbaseException;
16+
import org.knowm.xchange.coinbase.v2.dto.account.CoinbaseAccountData;
17+
import org.knowm.xchange.coinbase.v2.dto.account.CoinbaseAccountsData;
18+
import org.knowm.xchange.coinbase.v2.dto.account.CoinbaseBuyData;
19+
import org.knowm.xchange.coinbase.v2.dto.account.CoinbasePaymentMethodsData;
20+
import org.knowm.xchange.coinbase.v2.dto.account.CoinbaseSellData;
21+
22+
@Path("/")
23+
@Produces(MediaType.APPLICATION_JSON)
24+
public interface CoinbaseAuthenticated extends Coinbase {
25+
26+
/**
27+
* All API key requests must be signed and contain the following headers.
28+
*
29+
* All request bodies should have content type application/json and be valid JSON.
30+
*
31+
* The CB-ACCESS-SIGN header is generated by creating a sha256 HMAC using the secret key on the prehash string timestamp + method + requestPath + body (where + represents string concatenation).
32+
* The timestamp value is the same as the CB-ACCESS-TIMESTAMP header.
33+
*
34+
* The body is the request body string or omitted if there is no request body (typically for GET requests).
35+
*
36+
* The method should be UPPER CASE.
37+
*
38+
* <a href="https://developers.coinbase.com/api/v2#api-key">developers.coinbase.com/api/v2#api-key</a>
39+
*/
40+
final String CB_ACCESS_KEY = "CB-ACCESS-KEY";
41+
final String CB_ACCESS_SIGN = "CB-ACCESS-SIGN";
42+
final String CB_ACCESS_TIMESTAMP = "CB-ACCESS-TIMESTAMP";
43+
44+
final String CONTENT_TYPE = "Content-Type";
45+
46+
@GET
47+
@Path("accounts")
48+
CoinbaseAccountsData getAccounts(@HeaderParam(CB_VERSION) String apiVersion, @HeaderParam(CB_ACCESS_KEY) String apiKey, @HeaderParam(CB_ACCESS_SIGN) String signature,
49+
@HeaderParam(CB_ACCESS_TIMESTAMP) BigDecimal timestamp) throws IOException, CoinbaseException;
50+
51+
@GET
52+
@Path("accounts/{currency}")
53+
CoinbaseAccountData getAccount(@HeaderParam(CB_VERSION) String apiVersion, @HeaderParam(CB_ACCESS_KEY) String apiKey, @HeaderParam(CB_ACCESS_SIGN) String signature,
54+
@HeaderParam(CB_ACCESS_TIMESTAMP) BigDecimal timestamp, @PathParam("currency") String currency) throws IOException, CoinbaseException;
55+
56+
@POST
57+
@Path("accounts")
58+
@Consumes(MediaType.APPLICATION_JSON)
59+
CoinbaseAccountData createAccount(@HeaderParam(CONTENT_TYPE) String contentType, @HeaderParam(CB_VERSION) String apiVersion,
60+
@HeaderParam(CB_ACCESS_KEY) String apiKey, @HeaderParam(CB_ACCESS_SIGN) String signature, @HeaderParam(CB_ACCESS_TIMESTAMP) BigDecimal timestamp, Object payload)
61+
throws IOException, CoinbaseException;
62+
63+
@GET
64+
@Path("payment-methods")
65+
CoinbasePaymentMethodsData getPaymentMethods(@HeaderParam(CB_VERSION) String apiVersion, @HeaderParam(CB_ACCESS_KEY) String apiKey,
66+
@HeaderParam(CB_ACCESS_SIGN) String signature, @HeaderParam(CB_ACCESS_TIMESTAMP) BigDecimal timestamp) throws IOException, CoinbaseException;
67+
68+
@POST
69+
@Path("accounts/{account}/buys")
70+
@Consumes(MediaType.APPLICATION_JSON)
71+
CoinbaseBuyData buy(@HeaderParam(CONTENT_TYPE) String contentType, @HeaderParam(CB_VERSION) String apiVersion, @HeaderParam(CB_ACCESS_KEY) String apiKey,
72+
@HeaderParam(CB_ACCESS_SIGN) String signature, @HeaderParam(CB_ACCESS_TIMESTAMP) BigDecimal timestamp, @PathParam("account") String accountId, Object payload)
73+
throws IOException, CoinbaseException;
74+
75+
@POST
76+
@Path("accounts/{account}/sells")
77+
@Consumes(MediaType.APPLICATION_JSON)
78+
CoinbaseSellData sell(@HeaderParam(CONTENT_TYPE) String contentType, @HeaderParam(CB_VERSION) String apiVersion, @HeaderParam(CB_ACCESS_KEY) String apiKey,
79+
@HeaderParam(CB_ACCESS_SIGN) String signature, @HeaderParam(CB_ACCESS_TIMESTAMP) BigDecimal timestamp, @PathParam("account") String accountId, Object payload)
80+
throws IOException, CoinbaseException;
81+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package org.knowm.xchange.coinbase.v2;
2+
3+
import org.knowm.xchange.BaseExchange;
4+
import org.knowm.xchange.Exchange;
5+
import org.knowm.xchange.ExchangeSpecification;
6+
import org.knowm.xchange.coinbase.v2.service.CoinbaseAccountService;
7+
import org.knowm.xchange.coinbase.v2.service.CoinbaseMarketDataService;
8+
import org.knowm.xchange.coinbase.v2.service.CoinbaseTradeService;
9+
import org.knowm.xchange.utils.nonce.CurrentTimeNonceFactory;
10+
11+
import si.mazi.rescu.SynchronizedValueFactory;
12+
13+
public class CoinbaseExchange extends BaseExchange implements Exchange {
14+
15+
private SynchronizedValueFactory<Long> nonceFactory = new CurrentTimeNonceFactory();
16+
17+
@Override
18+
protected void initServices() {
19+
this.marketDataService = new CoinbaseMarketDataService(this);
20+
this.accountService = new CoinbaseAccountService(this);
21+
this.tradeService = new CoinbaseTradeService(this);
22+
}
23+
24+
@Override
25+
public ExchangeSpecification getDefaultExchangeSpecification() {
26+
27+
final ExchangeSpecification exchangeSpecification = new ExchangeSpecification(this.getClass().getCanonicalName());
28+
exchangeSpecification.setSslUri("https://api.coinbase.com/v2");
29+
exchangeSpecification.setHost("api.coinbase.com");
30+
exchangeSpecification.setExchangeName("Coinbase");
31+
exchangeSpecification.setExchangeDescription(
32+
"Founded in June of 2012, Coinbase is a bitcoin wallet and platform where merchants and consumers can transact with the new digital currency bitcoin.");
33+
return exchangeSpecification;
34+
}
35+
36+
@Override
37+
public SynchronizedValueFactory<Long> getNonceFactory() {
38+
39+
return nonceFactory;
40+
}
41+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package org.knowm.xchange.coinbase.v2.dto;
2+
3+
import java.math.BigDecimal;
4+
5+
import org.knowm.xchange.utils.Assert;
6+
7+
import com.fasterxml.jackson.annotation.JsonCreator;
8+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
9+
import com.fasterxml.jackson.annotation.JsonProperty;
10+
11+
@JsonIgnoreProperties(ignoreUnknown = true)
12+
public class CoinbaseAmount {
13+
14+
private final String currency;
15+
private final BigDecimal amount;
16+
private final String toString;
17+
18+
@JsonCreator
19+
public CoinbaseAmount(@JsonProperty("currency") String currency, @JsonProperty("amount") BigDecimal amount) {
20+
Assert.notNull(currency, "Null currency");
21+
Assert.notNull(amount, "Null amount");
22+
this.currency = currency;
23+
this.amount = amount;
24+
25+
toString = String.format("%.8f %s", amount, currency);
26+
}
27+
28+
public String getCurrency() {
29+
return currency;
30+
}
31+
32+
public BigDecimal getAmount() {
33+
return amount;
34+
}
35+
36+
@Override
37+
public int hashCode() {
38+
return toString().hashCode();
39+
}
40+
41+
@Override
42+
public boolean equals(Object obj) {
43+
if (this == obj) return true;
44+
if (obj == null) return false;
45+
if (getClass() != obj.getClass()) return false;
46+
CoinbaseAmount other = (CoinbaseAmount) obj;
47+
return amount.compareTo(other.amount) == 0 && currency.equals(other.currency);
48+
}
49+
50+
@Override
51+
public String toString() {
52+
return toString;
53+
}
54+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.knowm.xchange.coinbase.v2.dto;
2+
3+
import java.util.List;
4+
5+
import com.fasterxml.jackson.annotation.JsonProperty;
6+
7+
import si.mazi.rescu.HttpStatusExceptionSupport;
8+
9+
@SuppressWarnings("serial")
10+
public class CoinbaseException extends HttpStatusExceptionSupport {
11+
12+
public CoinbaseException(@JsonProperty("errors") List<CoinbaseError> errors) {
13+
super(errors.get(0).message);
14+
}
15+
16+
static class CoinbaseError {
17+
18+
@JsonProperty
19+
String id;
20+
@JsonProperty
21+
String message;
22+
23+
@Override
24+
public String toString() {
25+
return "CoinbaseError [id=" + id + ", message=" + message + "]";
26+
}
27+
}
28+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package org.knowm.xchange.coinbase.v2.dto;
2+
3+
import java.math.BigDecimal;
4+
5+
import org.knowm.xchange.currency.Currency;
6+
import org.knowm.xchange.utils.Assert;
7+
8+
import com.fasterxml.jackson.annotation.JsonCreator;
9+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
10+
import com.fasterxml.jackson.annotation.JsonProperty;
11+
12+
@JsonIgnoreProperties(ignoreUnknown = true)
13+
public class CoinbasePrice {
14+
15+
private final Currency currency;
16+
private final BigDecimal amount;
17+
private final String toString;
18+
19+
@JsonCreator
20+
public CoinbasePrice(@JsonProperty("amount") BigDecimal amount, @JsonProperty("currency") String currency) {
21+
this(amount, Currency.getInstance(currency));
22+
}
23+
24+
public CoinbasePrice(BigDecimal amount, Currency currency) {
25+
Assert.notNull(currency, "Null currency");
26+
Assert.notNull(amount, "Null amount");
27+
this.currency = currency;
28+
this.amount = amount;
29+
30+
toString = String.format("%.2f %s", amount, currency);
31+
}
32+
33+
public Currency getCurrency() {
34+
return currency;
35+
}
36+
37+
public BigDecimal getAmount() {
38+
return amount;
39+
}
40+
41+
@Override
42+
public int hashCode() {
43+
return toString().hashCode();
44+
}
45+
46+
@Override
47+
public boolean equals(Object obj) {
48+
if (this == obj) return true;
49+
if (obj == null) return false;
50+
if (getClass() != obj.getClass()) return false;
51+
CoinbasePrice other = (CoinbasePrice) obj;
52+
return amount.compareTo(other.amount) == 0 && currency.equals(other.currency);
53+
}
54+
55+
@Override
56+
public String toString() {
57+
return toString;
58+
}
59+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package org.knowm.xchange.coinbase.v2.dto.account;
2+
3+
import org.knowm.xchange.coinbase.v2.dto.CoinbaseAmount;
4+
5+
import com.fasterxml.jackson.annotation.JsonCreator;
6+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
7+
import com.fasterxml.jackson.annotation.JsonProperty;
8+
9+
@JsonIgnoreProperties(ignoreUnknown = true)
10+
public class CoinbaseAccountData {
11+
12+
private final CoinbaseAccount data;
13+
14+
private CoinbaseAccountData(@JsonProperty("data") CoinbaseAccount data) {
15+
this.data = data;
16+
}
17+
18+
public CoinbaseAccount getData() {
19+
return data;
20+
}
21+
22+
@Override
23+
public String toString() {
24+
return "" + data;
25+
}
26+
27+
@JsonIgnoreProperties(ignoreUnknown = true)
28+
public static class CoinbaseAccount {
29+
30+
private final String id;
31+
private final String name;
32+
private final CoinbaseAmount balance;
33+
34+
@JsonCreator
35+
CoinbaseAccount(@JsonProperty("id") String id, @JsonProperty("name") String name, @JsonProperty("balance") CoinbaseAmount balance) {
36+
this.id = id;
37+
this.name = name;
38+
this.balance = balance;
39+
}
40+
41+
public String getId() {
42+
return id;
43+
}
44+
45+
public String getName() {
46+
return name;
47+
}
48+
49+
public CoinbaseAmount getBalance() {
50+
return balance;
51+
}
52+
53+
@Override
54+
public String toString() {
55+
return "CoinbaseAccount [id=" + id + ", name=" + name + ", balance=" + balance + "]";
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)