Changed marketPrice to spotPrice.
Using BigDecimal instead of Double.
This commit is contained in:
parent
07a7198455
commit
f252c1602b
7 changed files with 51 additions and 48 deletions
18
README.md
18
README.md
|
@ -2,32 +2,32 @@
|
||||||
|
|
||||||
[](https://snyk.io/test/github/ethauvin/cryptoprice?targetFile=pom.xml) [](https://sonarcloud.io/dashboard?id=ethauvin_cryptoprice) [](https://github.com/ethauvin/cryptoprice/actions/workflows/gradle.yml) [](https://circleci.com/gh/ethauvin/cryptoprice/tree/master)
|
[](https://snyk.io/test/github/ethauvin/cryptoprice?targetFile=pom.xml) [](https://sonarcloud.io/dashboard?id=ethauvin_cryptoprice) [](https://github.com/ethauvin/cryptoprice/actions/workflows/gradle.yml) [](https://circleci.com/gh/ethauvin/cryptoprice/tree/master)
|
||||||
|
|
||||||
# Retrieve cryptocurrencies current market prices
|
# Retrieve cryptocurrencies current prices
|
||||||
|
|
||||||
A simple Kotlin/Java/Android implementation of the spot price [Coinbase Public API](https://developers.coinbase.com/api/v2#get-spot-price).
|
A simple Kotlin/Java/Android implementation of the spot price [Coinbase Public API](https://developers.coinbase.com/api/v2#get-spot-price).
|
||||||
|
|
||||||
## Examples (TL;DR)
|
## Examples (TL;DR)
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
import net.thauvin.erik.crypto.CryptoPrice.Companion.marketPrice
|
import net.thauvin.erik.crypto.CryptoPrice.Companion.spotPrice
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
val btc = marketPrice("BTC") // Bitcoin
|
val btc = spotPrice("BTC") // Bitcoin
|
||||||
println(btc.amount)
|
println(btc.amount)
|
||||||
|
|
||||||
val eth = marketPrice("ETH", "EUR") // Ethereum in Euros
|
val eth = spotPrice("ETH", "EUR") // Ethereum in Euros
|
||||||
println(eth.amount)
|
println(eth.amount)
|
||||||
|
|
||||||
```
|
```
|
||||||
- View [Kotlin](https://github.com/ethauvin/cryptoprice/blob/master/examples/src/main/kotlin/com/example/CryptoPriceExample.kt) or [Java](https://github.com/ethauvin/cryptoprice/blob/master/examples/src/main/java/com/example/CryptoPriceSample.java) Examples.
|
- View [Kotlin](https://github.com/ethauvin/cryptoprice/blob/master/examples/src/main/kotlin/com/example/CryptoPriceExample.kt) or [Java](https://github.com/ethauvin/cryptoprice/blob/master/examples/src/main/java/com/example/CryptoPriceSample.java) Examples.
|
||||||
|
|
||||||
### Market Price
|
### Spot Price
|
||||||
|
|
||||||
The `marketPrice` function defines the following parameters:
|
The `spotPrice` function defines the following parameters:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
marketPrice(
|
spotPrice(
|
||||||
base: String, // Required
|
base: String, // Required
|
||||||
currency: String = "USD",
|
currency: String = "USD",
|
||||||
date: LocalDate? = null,
|
date: LocalDate? = null,
|
||||||
|
@ -43,14 +43,14 @@ Parameters | Description
|
||||||
A `CryptoPrice` is returned defined as follows:
|
A `CryptoPrice` is returned defined as follows:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
CryptoPrice(val base: String, val currency: String, val amount: Double)
|
CryptoPrice(val base: String, val currency: String, val amount: BigDecimal)
|
||||||
```
|
```
|
||||||
The parameter names match the [Coinbase API](https://developers.coinbase.com/api/v2#get-spot-price).
|
The parameter names match the [Coinbase API](https://developers.coinbase.com/api/v2#get-spot-price).
|
||||||
|
|
||||||
To display the amount as a fomatted currency use the `toCurrency` function:
|
To display the amount as a fomatted currency use the `toCurrency` function:
|
||||||
|
|
||||||
```kotlin
|
```kotlin
|
||||||
val price = CryptoPrice("BTC", "EUR", 12345.67)
|
val price = CryptoPrice("BTC", "EUR", 12345.67.toBigDecimal())
|
||||||
println(price.toCurrency()) // will print €12,345.67
|
println(price.toCurrency()) // will print €12,345.67
|
||||||
```
|
```
|
||||||
### Extending
|
### Extending
|
||||||
|
|
|
@ -18,7 +18,7 @@ plugins {
|
||||||
|
|
||||||
defaultTasks(ApplicationPlugin.TASK_RUN_NAME)
|
defaultTasks(ApplicationPlugin.TASK_RUN_NAME)
|
||||||
|
|
||||||
description = "Retrieve cryptocurrencies current market prices."
|
description = "Retrieve cryptocurrencies current prices."
|
||||||
group = "net.thauvin.erik"
|
group = "net.thauvin.erik"
|
||||||
version = "0.9.0-SNAPSHOT"
|
version = "0.9.0-SNAPSHOT"
|
||||||
|
|
||||||
|
|
|
@ -10,18 +10,18 @@ import java.util.List;
|
||||||
public class CryptoPriceSample {
|
public class CryptoPriceSample {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
try {
|
try {
|
||||||
// Get current Bitcoin market price.
|
// Get current Bitcoin spot price.
|
||||||
final CryptoPrice price = CryptoPrice.marketPrice("BTC");
|
final CryptoPrice price = CryptoPrice.spotPrice("BTC");
|
||||||
System.out.println("The current Bitcoin price is " + price.toCurrency());
|
System.out.println("The current Bitcoin price is " + price.toCurrency());
|
||||||
|
|
||||||
// Get current Bitcoin market price in Euros.
|
// Get current Bitcoin spot price in Euros.
|
||||||
final CryptoPrice euroPrice = CryptoPrice.marketPrice("BTC", "EUR");
|
final CryptoPrice euroPrice = CryptoPrice.spotPrice("BTC", "EUR");
|
||||||
System.out.println("The current Bitcoin price is " + euroPrice.toCurrency());
|
System.out.println("The current Bitcoin price is " + euroPrice.toCurrency());
|
||||||
|
|
||||||
System.out.println();
|
System.out.println();
|
||||||
|
|
||||||
// Get current Ethereum market price in Pound sterling.
|
// Get current Ethereum spot price in Pound sterling.
|
||||||
final CryptoPrice gbpPrice = CryptoPrice.marketPrice("ETH", "GBP");
|
final CryptoPrice gbpPrice = CryptoPrice.spotPrice("ETH", "GBP");
|
||||||
System.out.println("The current Ethereum price is " + gbpPrice.toCurrency());
|
System.out.println("The current Ethereum price is " + gbpPrice.toCurrency());
|
||||||
|
|
||||||
System.out.println();
|
System.out.println();
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
package com.example
|
package com.example
|
||||||
|
|
||||||
import net.thauvin.erik.crypto.CryptoPrice.Companion.apiCall
|
import net.thauvin.erik.crypto.CryptoPrice.Companion.apiCall
|
||||||
import net.thauvin.erik.crypto.CryptoPrice.Companion.marketPrice
|
import net.thauvin.erik.crypto.CryptoPrice.Companion.spotPrice
|
||||||
import net.thauvin.erik.crypto.CryptoPrice.Companion.toPrice
|
import net.thauvin.erik.crypto.CryptoPrice.Companion.toPrice
|
||||||
|
|
||||||
fun main(@Suppress("UNUSED_PARAMETER") args: Array<String>) {
|
fun main(@Suppress("UNUSED_PARAMETER") args: Array<String>) {
|
||||||
// Get current Bitcoin market price.
|
// Get current Bitcoin spot price.
|
||||||
val price = marketPrice("BTC")
|
val price = spotPrice("BTC")
|
||||||
println("The current Bitcoin price is ${price.toCurrency()}")
|
println("The current Bitcoin price is ${price.toCurrency()}")
|
||||||
|
|
||||||
// Get current Bitcoin market price in Euro.
|
// Get current Bitcoin spot price in Euro.
|
||||||
val euroPrice = marketPrice("BTC", "EUR")
|
val euroPrice = spotPrice("BTC", "EUR")
|
||||||
println("The current Bitcoin price is ${euroPrice.toCurrency()}")
|
println("The current Bitcoin price is ${euroPrice.toCurrency()}")
|
||||||
|
|
||||||
println()
|
println()
|
||||||
|
|
||||||
// Get current Ethereum market price in Pound sterling.
|
// Get current Ethereum spot price in Pound sterling.
|
||||||
val gbpPrice = marketPrice("ETH", "GBP")
|
val gbpPrice = spotPrice("ETH", "GBP")
|
||||||
println("The current Ehtereum price is ${gbpPrice.toCurrency()}")
|
println("The current Ehtereum price is ${gbpPrice.toCurrency()}")
|
||||||
|
|
||||||
println()
|
println()
|
||||||
|
|
2
pom.xml
2
pom.xml
|
@ -10,7 +10,7 @@
|
||||||
<artifactId>cryptoprice</artifactId>
|
<artifactId>cryptoprice</artifactId>
|
||||||
<version>0.9.0-SNAPSHOT</version>
|
<version>0.9.0-SNAPSHOT</version>
|
||||||
<name>cryptoprice</name>
|
<name>cryptoprice</name>
|
||||||
<description>Retrieve cryptocurrencies current market prices.</description>
|
<description>Retrieve cryptocurrencies current prices.</description>
|
||||||
<url>https://github.com/ethauvin/cryptoprice</url>
|
<url>https://github.com/ethauvin/cryptoprice</url>
|
||||||
<licenses>
|
<licenses>
|
||||||
<license>
|
<license>
|
||||||
|
|
|
@ -38,17 +38,18 @@ import okhttp3.Request
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.math.BigDecimal
|
||||||
import java.text.NumberFormat
|
import java.text.NumberFormat
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.util.Currency
|
import java.util.Currency
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A small Kotlin/Java library for retrieving cryptocurrencies current market prices.
|
* A small Kotlin/Java library for retrieving cryptocurrencies current spot prices.
|
||||||
*
|
*
|
||||||
* @author [Erik C. Thauvin](https://erik.thauvin.net/)
|
* @author [Erik C. Thauvin](https://erik.thauvin.net/)
|
||||||
*/
|
*/
|
||||||
open class CryptoPrice(val base: String, val currency: String, val amount: Double) {
|
open class CryptoPrice(val base: String, val currency: String, val amount: BigDecimal) {
|
||||||
companion object {
|
companion object {
|
||||||
// Coinbase API URL
|
// Coinbase API URL
|
||||||
private const val COINBASE_API_URL = "https://api.coinbase.com/v2/"
|
private const val COINBASE_API_URL = "https://api.coinbase.com/v2/"
|
||||||
|
@ -63,7 +64,7 @@ open class CryptoPrice(val base: String, val currency: String, val amount: Doubl
|
||||||
val json = JSONObject(this)
|
val json = JSONObject(this)
|
||||||
if (json.has("data")) {
|
if (json.has("data")) {
|
||||||
with(json.getJSONObject("data")) {
|
with(json.getJSONObject("data")) {
|
||||||
return CryptoPrice(getString("base"), getString("currency"), getString("amount").toDouble())
|
return CryptoPrice(getString("base"), getString("currency"), getString("amount").toBigDecimal())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw CryptoException(message = "Missing price data.")
|
throw CryptoException(message = "Missing price data.")
|
||||||
|
@ -115,14 +116,14 @@ open class CryptoPrice(val base: String, val currency: String, val amount: Doubl
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
args.forEach {
|
args.forEach {
|
||||||
with(marketPrice(it)) {
|
with(spotPrice(it)) {
|
||||||
println("$base:\t" + "%10s".format(toCurrency()))
|
println("$base:\t" + "%10s".format(toCurrency()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the current market price.
|
* Retrieve the current spot price.
|
||||||
*
|
*
|
||||||
* @param base The cryptocurrency ticker symbol. (`BTC`, `ETH`, `ETH2`, etc.)
|
* @param base The cryptocurrency ticker symbol. (`BTC`, `ETH`, `ETH2`, etc.)
|
||||||
* @param currency The fiat currency ISO 4217 code. (`USD`, `GPB`, `EUR`, etc.)
|
* @param currency The fiat currency ISO 4217 code. (`USD`, `GPB`, `EUR`, etc.)
|
||||||
|
@ -131,7 +132,7 @@ open class CryptoPrice(val base: String, val currency: String, val amount: Doubl
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
@Throws(CryptoException::class, IOException::class)
|
@Throws(CryptoException::class, IOException::class)
|
||||||
fun marketPrice(base: String, currency: String = "USD", date: LocalDate? = null): CryptoPrice {
|
fun spotPrice(base: String, currency: String = "USD", date: LocalDate? = null): CryptoPrice {
|
||||||
val params = if (date != null) mapOf("date" to "$date") else emptyMap()
|
val params = if (date != null) mapOf("date" to "$date") else emptyMap()
|
||||||
return apiCall(listOf("prices", "$base-$currency", "spot"), params).toPrice()
|
return apiCall(listOf("prices", "$base-$currency", "spot"), params).toPrice()
|
||||||
}
|
}
|
||||||
|
@ -145,6 +146,7 @@ open class CryptoPrice(val base: String, val currency: String, val amount: Doubl
|
||||||
fun toCurrency(locale: Locale = Locale.getDefault(Locale.Category.FORMAT)): String {
|
fun toCurrency(locale: Locale = Locale.getDefault(Locale.Category.FORMAT)): String {
|
||||||
return NumberFormat.getCurrencyInstance(locale).let {
|
return NumberFormat.getCurrencyInstance(locale).let {
|
||||||
it.setCurrency(Currency.getInstance(currency))
|
it.setCurrency(Currency.getInstance(currency))
|
||||||
|
it.setMinimumFractionDigits(2)
|
||||||
it.format(amount)
|
it.format(amount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package net.thauvin.erik.crypto
|
package net.thauvin.erik.crypto
|
||||||
|
|
||||||
import net.thauvin.erik.crypto.CryptoPrice.Companion.apiCall
|
import net.thauvin.erik.crypto.CryptoPrice.Companion.apiCall
|
||||||
import net.thauvin.erik.crypto.CryptoPrice.Companion.marketPrice
|
import net.thauvin.erik.crypto.CryptoPrice.Companion.spotPrice
|
||||||
import net.thauvin.erik.crypto.CryptoPrice.Companion.toPrice
|
import net.thauvin.erik.crypto.CryptoPrice.Companion.toPrice
|
||||||
|
import java.math.BigDecimal
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
@ -17,37 +18,37 @@ class CryptoPriceTest {
|
||||||
@Test
|
@Test
|
||||||
@Throws(CryptoException::class)
|
@Throws(CryptoException::class)
|
||||||
fun testBTCPrice() {
|
fun testBTCPrice() {
|
||||||
val price = marketPrice("BTC")
|
val price = spotPrice("BTC")
|
||||||
assertEquals("BTC", price.base, "BTC")
|
assertEquals("BTC", price.base, "BTC")
|
||||||
assertEquals("USD", price.currency, "is USD")
|
assertEquals("USD", price.currency, "is USD")
|
||||||
assertTrue(price.amount > 0.00, "BTC > 0")
|
assertTrue(price.amount.signum() > 0, "BTC > 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Throws(CryptoException::class)
|
@Throws(CryptoException::class)
|
||||||
fun testETHPrice() {
|
fun testETHPrice() {
|
||||||
val price = marketPrice("ETH", "EUR")
|
val price = spotPrice("ETH", "EUR")
|
||||||
assertEquals("ETH", price.base, "ETH")
|
assertEquals("ETH", price.base, "ETH")
|
||||||
assertEquals("EUR", price.currency, "is EUR")
|
assertEquals("EUR", price.currency, "is EUR")
|
||||||
assertTrue(price.amount > 0.00, "ETH > 0")
|
assertTrue(price.amount.signum() > 0, "ETH > 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Throws(CryptoException::class)
|
@Throws(CryptoException::class)
|
||||||
fun testETH2Price() {
|
fun testETH2Price() {
|
||||||
val price = marketPrice("ETH2", "GBP")
|
val price = spotPrice("ETH2", "GBP")
|
||||||
assertEquals("ETH2", price.base, "ETH2")
|
assertEquals("ETH2", price.base, "ETH2")
|
||||||
assertEquals("GBP", price.currency, "is GBP")
|
assertEquals("GBP", price.currency, "is GBP")
|
||||||
assertTrue(price.amount > 0.00, "GBP > 0")
|
assertTrue(price.amount.signum() > 0, "GBP > 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Throws(CryptoException::class)
|
@Throws(CryptoException::class)
|
||||||
fun testBCHPrice() {
|
fun testBCHPrice() {
|
||||||
val price = marketPrice("BCH", "GBP", LocalDate.now().minusDays(1))
|
val price = spotPrice("BCH", "GBP", LocalDate.now().minusDays(1))
|
||||||
assertEquals("BCH", price.base, "BCH")
|
assertEquals("BCH", price.base, "BCH")
|
||||||
assertEquals("GBP", price.currency, "is GBP")
|
assertEquals("GBP", price.currency, "is GBP")
|
||||||
assertTrue(price.amount > 0.00, "BCH > 0")
|
assertTrue(price.amount.signum() > 0, "BCH > 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -56,26 +57,26 @@ class CryptoPriceTest {
|
||||||
val price = apiCall(listOf("prices", "BTC-USD", "buy"), emptyMap()).toPrice()
|
val price = apiCall(listOf("prices", "BTC-USD", "buy"), emptyMap()).toPrice()
|
||||||
assertEquals("BTC", price.base, "buy BTC")
|
assertEquals("BTC", price.base, "buy BTC")
|
||||||
assertEquals("USD", price.currency, "buy BTC is USD")
|
assertEquals("USD", price.currency, "buy BTC is USD")
|
||||||
assertTrue(price.amount > 0.00, "buy BTC > 0")
|
assertTrue(price.amount.signum() > 0, "buy BTC > 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Throws(CryptoException::class)
|
@Throws(CryptoException::class)
|
||||||
fun testMarketPriceExceptions() {
|
fun testSpotPrice() {
|
||||||
assertFailsWith(
|
assertFailsWith(
|
||||||
message = "FOO did not fail",
|
message = "FOO did not fail",
|
||||||
exceptionClass = CryptoException::class,
|
exceptionClass = CryptoException::class,
|
||||||
block = { marketPrice("FOO") }
|
block = { spotPrice("FOO") }
|
||||||
)
|
)
|
||||||
|
|
||||||
assertFailsWith(
|
assertFailsWith(
|
||||||
message = "BAR did not fail",
|
message = "BAR did not fail",
|
||||||
exceptionClass = CryptoException::class,
|
exceptionClass = CryptoException::class,
|
||||||
block = { marketPrice("BTC", "BAR") }
|
block = { spotPrice("BTC", "BAR") }
|
||||||
)
|
)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
marketPrice("FOOBAR")
|
spotPrice("FOOBAR")
|
||||||
} catch (e: CryptoException) {
|
} catch (e: CryptoException) {
|
||||||
assertTrue(e.statusCode != 400, "FOOBAR status code is not 400")
|
assertTrue(e.statusCode != 400, "FOOBAR status code is not 400")
|
||||||
}
|
}
|
||||||
|
@ -84,7 +85,7 @@ class CryptoPriceTest {
|
||||||
@Test
|
@Test
|
||||||
@Throws(IllegalArgumentException::class)
|
@Throws(IllegalArgumentException::class)
|
||||||
fun testToCurrency() {
|
fun testToCurrency() {
|
||||||
val d = 12345.67
|
val d = 12345.67.toBigDecimal()
|
||||||
val usd = CryptoPrice("BTC", "USD", d)
|
val usd = CryptoPrice("BTC", "USD", d)
|
||||||
assertEquals("$12,345.67", usd.toCurrency(), "EUR format")
|
assertEquals("$12,345.67", usd.toCurrency(), "EUR format")
|
||||||
|
|
||||||
|
@ -101,18 +102,18 @@ class CryptoPriceTest {
|
||||||
assertEquals("12 345,67 €", fr.toCurrency(Locale.FRANCE), "EUR-FR format")
|
assertEquals("12 345,67 €", fr.toCurrency(Locale.FRANCE), "EUR-FR format")
|
||||||
|
|
||||||
val jp = CryptoPrice("BTC", "JPY", d)
|
val jp = CryptoPrice("BTC", "JPY", d)
|
||||||
assertEquals("¥12,346", jp.toCurrency(Locale.JAPAN), "EUR-JPY format")
|
assertEquals("¥12,345.67", jp.toCurrency(Locale.JAPAN), "EUR-JPY format")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Throws(CryptoException::class)
|
@Throws(CryptoException::class)
|
||||||
fun testToPrice() {
|
fun testToPrice() {
|
||||||
val d = 57515.69
|
val d = "57515.69"
|
||||||
val json = "{\"data\":{\"base\":\"BTC\",\"currency\":\"USD\",\"amount\":\"$d\"}}"
|
val json = "{\"data\":{\"base\":\"BTC\",\"currency\":\"USD\",\"amount\":\"$d\"}}"
|
||||||
val price = json.toPrice()
|
val price = json.toPrice()
|
||||||
assertEquals("BTC", price.base, "base is BTC")
|
assertEquals("BTC", price.base, "base is BTC")
|
||||||
assertEquals("USD", price.currency, "currency is USD")
|
assertEquals("USD", price.currency, "currency is USD")
|
||||||
assertEquals(d, price.amount, "amount is 57515.69")
|
assertEquals(d, price.amount.toString(), "amount is 57515.69")
|
||||||
|
|
||||||
assertFailsWith(
|
assertFailsWith(
|
||||||
message = "double conversion did not fail",
|
message = "double conversion did not fail",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue