Changed marketPrice to spotPrice.

Using BigDecimal instead of Double.
This commit is contained in:
Erik C. Thauvin 2021-05-26 03:11:55 -07:00
parent 07a7198455
commit f252c1602b
7 changed files with 51 additions and 48 deletions

View file

@ -38,17 +38,18 @@ import okhttp3.Request
import org.json.JSONException
import org.json.JSONObject
import java.io.IOException
import java.math.BigDecimal
import java.text.NumberFormat
import java.time.LocalDate
import java.util.Currency
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/)
*/
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 {
// Coinbase API URL
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)
if (json.has("data")) {
with(json.getJSONObject("data")) {
return CryptoPrice(getString("base"), getString("currency"), getString("amount").toDouble())
return CryptoPrice(getString("base"), getString("currency"), getString("amount").toBigDecimal())
}
} else {
throw CryptoException(message = "Missing price data.")
@ -115,14 +116,14 @@ open class CryptoPrice(val base: String, val currency: String, val amount: Doubl
@JvmStatic
fun main(args: Array<String>) {
args.forEach {
with(marketPrice(it)) {
with(spotPrice(it)) {
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 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
@JvmOverloads
@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()
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 {
return NumberFormat.getCurrencyInstance(locale).let {
it.setCurrency(Currency.getInstance(currency))
it.setMinimumFractionDigits(2)
it.format(amount)
}
}

View file

@ -1,8 +1,9 @@
package net.thauvin.erik.crypto
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 java.math.BigDecimal
import java.time.LocalDate
import java.util.Locale
import kotlin.test.Test
@ -17,37 +18,37 @@ class CryptoPriceTest {
@Test
@Throws(CryptoException::class)
fun testBTCPrice() {
val price = marketPrice("BTC")
val price = spotPrice("BTC")
assertEquals("BTC", price.base, "BTC")
assertEquals("USD", price.currency, "is USD")
assertTrue(price.amount > 0.00, "BTC > 0")
assertTrue(price.amount.signum() > 0, "BTC > 0")
}
@Test
@Throws(CryptoException::class)
fun testETHPrice() {
val price = marketPrice("ETH", "EUR")
val price = spotPrice("ETH", "EUR")
assertEquals("ETH", price.base, "ETH")
assertEquals("EUR", price.currency, "is EUR")
assertTrue(price.amount > 0.00, "ETH > 0")
assertTrue(price.amount.signum() > 0, "ETH > 0")
}
@Test
@Throws(CryptoException::class)
fun testETH2Price() {
val price = marketPrice("ETH2", "GBP")
val price = spotPrice("ETH2", "GBP")
assertEquals("ETH2", price.base, "ETH2")
assertEquals("GBP", price.currency, "is GBP")
assertTrue(price.amount > 0.00, "GBP > 0")
assertTrue(price.amount.signum() > 0, "GBP > 0")
}
@Test
@Throws(CryptoException::class)
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("GBP", price.currency, "is GBP")
assertTrue(price.amount > 0.00, "BCH > 0")
assertTrue(price.amount.signum() > 0, "BCH > 0")
}
@Test
@ -56,26 +57,26 @@ class CryptoPriceTest {
val price = apiCall(listOf("prices", "BTC-USD", "buy"), emptyMap()).toPrice()
assertEquals("BTC", price.base, "buy BTC")
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
@Throws(CryptoException::class)
fun testMarketPriceExceptions() {
fun testSpotPrice() {
assertFailsWith(
message = "FOO did not fail",
exceptionClass = CryptoException::class,
block = { marketPrice("FOO") }
block = { spotPrice("FOO") }
)
assertFailsWith(
message = "BAR did not fail",
exceptionClass = CryptoException::class,
block = { marketPrice("BTC", "BAR") }
block = { spotPrice("BTC", "BAR") }
)
try {
marketPrice("FOOBAR")
spotPrice("FOOBAR")
} catch (e: CryptoException) {
assertTrue(e.statusCode != 400, "FOOBAR status code is not 400")
}
@ -84,7 +85,7 @@ class CryptoPriceTest {
@Test
@Throws(IllegalArgumentException::class)
fun testToCurrency() {
val d = 12345.67
val d = 12345.67.toBigDecimal()
val usd = CryptoPrice("BTC", "USD", d)
assertEquals("$12,345.67", usd.toCurrency(), "EUR format")
@ -101,18 +102,18 @@ class CryptoPriceTest {
assertEquals("12345,67 ", fr.toCurrency(Locale.FRANCE), "EUR-FR format")
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
@Throws(CryptoException::class)
fun testToPrice() {
val d = 57515.69
val d = "57515.69"
val json = "{\"data\":{\"base\":\"BTC\",\"currency\":\"USD\",\"amount\":\"$d\"}}"
val price = json.toPrice()
assertEquals("BTC", price.base, "base is BTC")
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(
message = "double conversion did not fail",