113 lines
2.8 KiB
Go
113 lines
2.8 KiB
Go
|
package coindesk
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// Asset is a cryptocurrency, like Bitcoin, Ethereum, etc.
|
||
|
type Asset string
|
||
|
|
||
|
const (
|
||
|
// BTC is the Bitcoin asset.
|
||
|
BTC Asset = "BTC"
|
||
|
// ETH is the Ethereum asset.
|
||
|
ETH Asset = "ETH"
|
||
|
)
|
||
|
|
||
|
// Response represents the general top-level format of Coindesk API responses.
|
||
|
type Response[T any] struct {
|
||
|
StatusCode int `json:"statusCode"`
|
||
|
Message string `json:"message"`
|
||
|
Data T `json:"data"`
|
||
|
}
|
||
|
|
||
|
// PriceValues contains a series of timestamped prices for a particular asset.
|
||
|
type PriceValues struct {
|
||
|
ISO Asset `json:"iso"`
|
||
|
Name string `json:"name"`
|
||
|
Slug string `json:"slug"`
|
||
|
IngestionStart Date `json:"ingestionStart"`
|
||
|
Entries []TimestampPrice `json:"entries"`
|
||
|
}
|
||
|
|
||
|
// AssetTickers is a map from an asset to its ticker data.
|
||
|
type AssetTickers map[Asset]AssetTicker
|
||
|
|
||
|
// AssetTicker is a snapshot of pricing data for an asset.
|
||
|
type AssetTicker struct {
|
||
|
ISO Asset `json:"iso"`
|
||
|
Name string `json:"name"`
|
||
|
Slug string `json:"slug"`
|
||
|
Change struct {
|
||
|
Percent float64 `json:"percent"`
|
||
|
Value float64 `json:"value"`
|
||
|
} `json:"change"`
|
||
|
OHLC struct {
|
||
|
Opening Price `json:"o"`
|
||
|
High Price `json:"h"`
|
||
|
Low Price `json:"l"`
|
||
|
Closing Price `json:"c"`
|
||
|
} `json:"ohlc"`
|
||
|
CirculatingSupply float64 `json:"circulatingSupply"`
|
||
|
MarketCap Price `json:"marketCap"`
|
||
|
Timestamp Timestamp `json:"ts"`
|
||
|
}
|
||
|
|
||
|
// TimestampPrice represents a JSON array with two elements: an integer Unix
|
||
|
// timestamp expressed in milliseconds, and a floating-point USD price.
|
||
|
type TimestampPrice struct {
|
||
|
Timestamp Timestamp
|
||
|
Price Price
|
||
|
}
|
||
|
|
||
|
func (t *TimestampPrice) UnmarshalJSON(b []byte) error {
|
||
|
a := []interface{}{&t.Timestamp, &t.Price}
|
||
|
return json.Unmarshal(b, &a)
|
||
|
}
|
||
|
|
||
|
// Timestamp represents an integer Unix timestamp expressed in milliseconds
|
||
|
// which has been converted into a Golang time.Time object.
|
||
|
type Timestamp time.Time
|
||
|
|
||
|
func (t *Timestamp) UnmarshalJSON(b []byte) error {
|
||
|
s := string(b)
|
||
|
n := len(s)
|
||
|
secsStr := s[0 : n-3]
|
||
|
millisStr := s[n-3:]
|
||
|
secs, err := strconv.ParseInt(secsStr, 10, 64)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
millis, err := strconv.ParseInt(millisStr, 10, 64)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
converted := time.Unix(secs, millis*1e6)
|
||
|
*t = Timestamp(converted)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Price represents the USD price of an asset.
|
||
|
type Price float64
|
||
|
|
||
|
// Date represents a date-only string which has been converted into a Golang
|
||
|
// time.Time object.
|
||
|
type Date time.Time
|
||
|
|
||
|
func (d *Date) UnmarshalJSON(b []byte) error {
|
||
|
s := string(b)
|
||
|
s, _ = strings.CutPrefix(s, "\"")
|
||
|
s, _ = strings.CutSuffix(s, "\"")
|
||
|
t, err := time.Parse(time.DateOnly, s)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
*d = Date(t)
|
||
|
return nil
|
||
|
}
|