Rewrite ExchangeRate to use BigDecimal

Rewrite ExchangeRate to use BigDecimal for the quantity multiplication, to ensure that there is no loss of precision during the conversion process. The previous version using double-precision floating point maths inherently means that the precision is not fixed, but is floating.

Change ExchangeRate to an abstract class rather than an interface, so the functions on it can be implemented directly rather than being extension functions, to improve Java compatibility.
This commit is contained in:
Ross Nicoll 2017-08-31 17:29:58 +01:00 committed by GitHub
parent 574c476709
commit b1df11acfa
2 changed files with 20 additions and 15 deletions

View File

@ -3,25 +3,30 @@ package net.corda.client.jfx.model
import javafx.beans.property.SimpleObjectProperty
import javafx.beans.value.ObservableValue
import net.corda.core.contracts.Amount
import java.math.BigDecimal
import java.math.RoundingMode
import java.util.*
interface ExchangeRate {
fun rate(from: Currency, to: Currency): Double
}
fun ExchangeRate.exchangeAmount(amount: Amount<Currency>, to: Currency) =
Amount(exchangeDouble(amount, to).toLong(), to)
fun ExchangeRate.exchangeDouble(amount: Amount<Currency>, to: Currency) =
rate(amount.token, to) * amount.quantity
/**
* This model provides an exchange rate from arbitrary currency to arbitrary currency.
* TODO hook up an actual oracle
*/
abstract class ExchangeRate {
/**
* Convert the given amount of a currency into the target currency.
*
* @return the original amount converted to an amount in the target currency.
*/
fun exchangeAmount(amount: Amount<Currency>, to: Currency) = Amount.fromDecimal(amount.toDecimal().multiply(rate(amount.token, to)), to)
abstract fun rate(from: Currency, to: Currency): BigDecimal
}
/**
* Default implementation of an exchange rate model, which uses a fixed exchange rate.
*/
// TODO hook up an actual oracle
class ExchangeRateModel {
val exchangeRate: ObservableValue<ExchangeRate> = SimpleObjectProperty<ExchangeRate>(object : ExchangeRate {
override fun rate(from: Currency, to: Currency) = 1.0
val exchangeRate: ObservableValue<ExchangeRate> = SimpleObjectProperty<ExchangeRate>(object : ExchangeRate() {
override fun rate(from: Currency, to: Currency) = BigDecimal.ONE
})
}

View File

@ -29,7 +29,7 @@ object AmountBindings {
return EasyBind.combine(observableCurrency, observableExchangeRate) { currency, exchangeRate ->
Pair<Currency, (Amount<Currency>) -> Long>(
currency,
{ (quantity, _, token) -> (exchangeRate.rate(token, currency) * quantity).toLong() }
{ amount -> exchangeRate.exchangeAmount(amount, currency).quantity }
)
}
}