liveBook · Manning

Currency exchange rate

As explained in Learn Go with Pocket-Sized Projects

An exchange rate is a numeric ratio specifying how much of one currency corresponds to a unit of another currency.

A currency exchange rate specifies how much target currency corresponds to one unit of source currency. A money-conversion CLI uses the rate to turn an input Amount into a new Amount in the requested currency; the input amount remains unchanged. section 6.0 section 6.3.1

Keep obtaining and applying the rate separate:

  • Represent the rate with a dedicated ExchangeRate type. Multiply it by the amount’s decimal quantity, then adjust the result to the target currency’s precision. The illustrated implementation drops excess decimal places by division; it does not demonstrate conventional rounding. section 6.3.1
  • Fetch the rate through a separate bank dependency rather than embedding an HTTP call in money conversion. This permits a hardcoded rate during development and replacement with a bank-backed implementation. section 6.3 section 6.5
  • Report a failure when the response cannot be decoded or either currency’s rate is absent. section 6.5.4

Converting an ECB reference rate

The sample European Central Bank response lists USD at 1.0674 per EUR. At that sample rate, 10 EUR produces 10.674 USD before adjustment to USD’s two decimal places; the illustrated precision adjustment yields 10.67 USD. This is a worked software example, not a rate for a real transaction. section 6.5.4 section 6.3.1 section 6.0

ECB reference rates express each listed currency against one euro. Add EUR at a rate of 1, then calculate a source-to-target rate as targetFactor / sourceFactor. For example, converting CAD to ZAR uses the two EUR-based factors rather than requiring a separately published CAD-to-ZAR rate. section 6.5.4

Listing 6.45 envelope.go: Computing the exchange rate
// exchangeRate reads the change rate from the Envelope's contents.
func (e envelope) exchangeRate(
    source, target string) (money.ExchangeRate, error) {
    if source == target {
        return 1., nil #1
    }

    rates := e.mappedChangeRates()

    sourceFactor, sourceFound := rates[source] #2
    if !sourceFound {
        return 0, fmt.Errorf("failed to find the source currency %s", 
            source) #3
    }

    targetFactor, targetFound := rates[target] #4
    if !targetFound {
        return 0, fmt.Errorf("failed to find target currency %s", target)
    }

    return targetFactor / sourceFactor, nil #5
}

The rate-calculation listing shows the same-currency rate of 1, checks for missing currencies, and divides the target factor by the source factor. section 6.5.4

Test rate application with identity rates, very small or large rates, and target currencies with different precisions. The XML-decoding example reads rate attributes as float64, while the conversion design calls for decimal multiplication; the supplied fragments do not show a complete, consistent handoff between those representations. section 6.3.1 section 6.5.4

How Learn Go with Pocket-Sized Projects covers it

How deep it goes
Works through rate representation, multiplication, target precision, ECB fetching, and cross-currency calculation; stops short of a consistent decoding-to-decimal handoff.
Examples
Tests identity, tiny, and oversized rates, and derives cross-currency rates from ECB euro-based XML data.
What it assumes
Assumes valid Amount and Currency values and introduces a dedicated ExchangeRate type before adding remote retrieval.
What you can do after
Build it from scratch: apply a fetched rate to an amount and test precision changes and missing-rate failures.
How it connects
Connects exchange rates to decimal arithmetic, currency precision, dependency inversion, HTTP, and XML decoding.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Go with Pocket-Sized Projects. The section links point to the parts of the book it draws on.