fix #434: dont fetch price-info too often
This commit is contained in:
parent
ece5333ae8
commit
81cd3c54a6
|
@ -1,66 +1,100 @@
|
||||||
(ns commiteth.util.crypto-fiat-value
|
(ns commiteth.util.crypto-fiat-value
|
||||||
(:require [mount.core :as mount]
|
(:require [mount.core :as mount]
|
||||||
|
[clj-time.core :as t]
|
||||||
|
[clojure.edn :as edn]
|
||||||
[clojure.tools.logging :as log]
|
[clojure.tools.logging :as log]
|
||||||
[commiteth.config :refer [env]]
|
[commiteth.config :refer [env]]
|
||||||
[commiteth.util.util :refer [json-api-request]]))
|
[commiteth.util.util :refer [json-api-request]]))
|
||||||
|
|
||||||
|
|
||||||
(defn fiat-api-provider []
|
(defn- fiat-api-provider []
|
||||||
(env :fiat-api-provider :coinmarketcap))
|
(env :fiat-api-provider :coinmarketcap))
|
||||||
|
|
||||||
|
(defn- get-token-usd-price-cryptonator
|
||||||
(defn get-token-usd-price-cryptonator
|
|
||||||
"Get current USD value for a token using cryptonator API"
|
"Get current USD value for a token using cryptonator API"
|
||||||
[tla]
|
[tla]
|
||||||
|
(log/infof "%s: Getting price-data from Cryptonator" tla)
|
||||||
(let [token (subs (str tla) 1)
|
(let [token (subs (str tla) 1)
|
||||||
url (str "https://api.cryptonator.com/api/ticker/"
|
url (format "https://api.cryptonator.com/api/ticker/%s-usd" token)
|
||||||
token
|
|
||||||
"-usd")
|
|
||||||
m (json-api-request url)]
|
m (json-api-request url)]
|
||||||
(-> (get-in m ["ticker" "price"])
|
(-> (get-in m ["ticker" "price"])
|
||||||
(read-string))))
|
(edn/read-string))))
|
||||||
|
|
||||||
|
(defn- make-tla-to-id-mapping
|
||||||
(def tla-to-id-mapping (atom {}))
|
|
||||||
|
|
||||||
(defn make-tla-to-id-mapping
|
|
||||||
"Coinmarketcap API uses it's own IDs for tokens instead of TLAs"
|
"Coinmarketcap API uses it's own IDs for tokens instead of TLAs"
|
||||||
[]
|
[]
|
||||||
(let [data (json-api-request "https://api.coinmarketcap.com/v1/ticker/?limit=0")]
|
(->> (json-api-request "https://api.coinmarketcap.com/v1/ticker/?limit=0")
|
||||||
(into {} (map
|
(map (fn [x] [(keyword (get x "symbol")) (get x "id")]))
|
||||||
(fn [x] [(keyword (get x "symbol")) (get x "id")])
|
(into {})))
|
||||||
data))))
|
|
||||||
|
|
||||||
(defn get-token-usd-price-coinmarketcap
|
(defn- get-token-usd-price-coinmarketcap
|
||||||
"Get current USD value for a token using coinmarketcap API"
|
"Get current USD value for a token using coinmarketcap API"
|
||||||
[tla]
|
[tla token-id]
|
||||||
(let [token-id (get @tla-to-id-mapping tla)
|
{:pre [(some? token-id)]}
|
||||||
url (format "https://api.coinmarketcap.com/v1/ticker/%s" token-id)
|
(log/infof "%s: Getting price-data from CoinMarketCap (token-id %s)" tla token-id)
|
||||||
data (json-api-request url)]
|
(-> (json-api-request (format "https://api.coinmarketcap.com/v1/ticker/%s" token-id))
|
||||||
(-> (first data)
|
(first)
|
||||||
(get "price_usd")
|
(get "price_usd")
|
||||||
(read-string))))
|
(edn/read-string)))
|
||||||
|
|
||||||
(defn- get-price-fn []
|
(defrecord PriceInfo [tla usd date])
|
||||||
(let [fns {:cryptonator get-token-usd-price-cryptonator
|
|
||||||
:coinmarketcap get-token-usd-price-coinmarketcap}]
|
|
||||||
(get fns (fiat-api-provider))))
|
|
||||||
|
|
||||||
(defn bounty-usd-value
|
(defn recent? [price-info]
|
||||||
"Get current USD value of a bounty. bounty is a map of token-tla (keyword) to value"
|
(t/after? (:date price-info) (t/minus (t/now) (t/minutes 5))))
|
||||||
[bounty]
|
|
||||||
(let [get-token-usd-price (get-price-fn)]
|
|
||||||
(reduce + (map (fn [[tla value]]
|
|
||||||
(let [usd-price (get-token-usd-price tla)]
|
|
||||||
(* usd-price value)))
|
|
||||||
bounty))))
|
|
||||||
|
|
||||||
|
(defprotocol IFiatCryptoConverter
|
||||||
|
(start [_])
|
||||||
|
(convert-usd [_ tla amount]))
|
||||||
|
|
||||||
|
(defrecord FiatCryptoConverter [provider state]
|
||||||
|
IFiatCryptoConverter
|
||||||
|
(start [_]
|
||||||
|
(when (= :coinmarketcap provider)
|
||||||
|
(swap! state assoc :tla->id (make-tla-to-id-mapping))))
|
||||||
|
(convert-usd [_ tla amount]
|
||||||
|
(if-let [recent-price-info (and (some-> (get-in @state [:price-info tla]) recent?)
|
||||||
|
;; return actual price info
|
||||||
|
(get-in @state [:price-info tla]))]
|
||||||
|
(* (:usd recent-price-info) amount)
|
||||||
|
;; if we don't have price-info we need to fetch & store it
|
||||||
|
(let [price (case provider
|
||||||
|
:coinmarketcap (get-token-usd-price-coinmarketcap
|
||||||
|
tla
|
||||||
|
(get-in @state [:tla->id tla]))
|
||||||
|
:cryptonator (get-token-usd-price-cryptonator tla))]
|
||||||
|
(swap! state assoc-in [:price-info tla] (->PriceInfo tla price (t/now)))
|
||||||
|
(* price amount)))))
|
||||||
|
|
||||||
(mount/defstate
|
(mount/defstate
|
||||||
crypto-fiat-util
|
fiat-converter
|
||||||
:start
|
:start (let [provider (fiat-api-provider)]
|
||||||
(do
|
(log/infof "Starting FiatCryptoConverter %s" provider)
|
||||||
(reset! tla-to-id-mapping (make-tla-to-id-mapping))
|
(doto (->FiatCryptoConverter provider (atom {}))
|
||||||
(log/info "crypto-fiat-util started"))
|
(start)))
|
||||||
:stop
|
:stop (log/info "Stopping FiatCryptoConverter"))
|
||||||
(log/info "crypto-fiat-util stopped"))
|
|
||||||
|
;; public api ------------------------------------------------------------------
|
||||||
|
|
||||||
|
(defn bounty-usd-value
|
||||||
|
"Get current USD value for the crypto-amounts passed as argument.
|
||||||
|
Example: {:ETH 123, :SNT 456}"
|
||||||
|
[crypto-amounts]
|
||||||
|
(->> crypto-amounts
|
||||||
|
(map (fn [[tla value]]
|
||||||
|
(convert-usd fiat-converter tla value)))
|
||||||
|
(reduce + 0)))
|
||||||
|
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(fiat-api-provider)
|
||||||
|
|
||||||
|
(def fc (->FiatCryptoConverter (fiat-api-provider) (atom {})))
|
||||||
|
(start fc)
|
||||||
|
|
||||||
|
(convert-usd fc :SNT 400)
|
||||||
|
|
||||||
|
(bounty-usd-value {:ETH 2 :ANT 2 :SNT 5})
|
||||||
|
|
||||||
|
(mount/start)
|
||||||
|
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue