fix #434: dont fetch price-info too often

This commit is contained in:
Martin Klepsch 2018-04-25 17:11:19 +02:00 committed by Tetiana Churikova
parent ece5333ae8
commit 81cd3c54a6
1 changed files with 76 additions and 42 deletions

View File

@ -1,66 +1,100 @@
(ns commiteth.util.crypto-fiat-value
(:require [mount.core :as mount]
[clj-time.core :as t]
[clojure.edn :as edn]
[clojure.tools.logging :as log]
[commiteth.config :refer [env]]
[commiteth.util.util :refer [json-api-request]]))
(defn fiat-api-provider []
(defn- fiat-api-provider []
(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"
[tla]
(log/infof "%s: Getting price-data from Cryptonator" tla)
(let [token (subs (str tla) 1)
url (str "https://api.cryptonator.com/api/ticker/"
token
"-usd")
url (format "https://api.cryptonator.com/api/ticker/%s-usd" token)
m (json-api-request url)]
(-> (get-in m ["ticker" "price"])
(read-string))))
(edn/read-string))))
(def tla-to-id-mapping (atom {}))
(defn make-tla-to-id-mapping
(defn- make-tla-to-id-mapping
"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")]
(into {} (map
(fn [x] [(keyword (get x "symbol")) (get x "id")])
data))))
(->> (json-api-request "https://api.coinmarketcap.com/v1/ticker/?limit=0")
(map (fn [x] [(keyword (get x "symbol")) (get x "id")]))
(into {})))
(defn get-token-usd-price-coinmarketcap
(defn- get-token-usd-price-coinmarketcap
"Get current USD value for a token using coinmarketcap API"
[tla]
(let [token-id (get @tla-to-id-mapping tla)
url (format "https://api.coinmarketcap.com/v1/ticker/%s" token-id)
data (json-api-request url)]
(-> (first data)
[tla token-id]
{:pre [(some? token-id)]}
(log/infof "%s: Getting price-data from CoinMarketCap (token-id %s)" tla token-id)
(-> (json-api-request (format "https://api.coinmarketcap.com/v1/ticker/%s" token-id))
(first)
(get "price_usd")
(read-string))))
(edn/read-string)))
(defn- get-price-fn []
(let [fns {:cryptonator get-token-usd-price-cryptonator
:coinmarketcap get-token-usd-price-coinmarketcap}]
(get fns (fiat-api-provider))))
(defrecord PriceInfo [tla usd date])
(defn bounty-usd-value
"Get current USD value of a bounty. bounty is a map of token-tla (keyword) to value"
[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))))
(defn recent? [price-info]
(t/after? (:date price-info) (t/minus (t/now) (t/minutes 5))))
(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
crypto-fiat-util
:start
(do
(reset! tla-to-id-mapping (make-tla-to-id-mapping))
(log/info "crypto-fiat-util started"))
:stop
(log/info "crypto-fiat-util stopped"))
fiat-converter
:start (let [provider (fiat-api-provider)]
(log/infof "Starting FiatCryptoConverter %s" provider)
(doto (->FiatCryptoConverter provider (atom {}))
(start)))
:stop (log/info "Stopping FiatCryptoConverter"))
;; 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)
)