2023-03-14 19:58:13 -07:00
|
|
|
use crate::CoinConfig;
|
2022-11-23 20:47:34 -08:00
|
|
|
use anyhow::anyhow;
|
2021-08-09 07:13:10 -07:00
|
|
|
use chrono::NaiveDateTime;
|
|
|
|
|
2021-08-16 06:07:04 -07:00
|
|
|
const DAY_SEC: i64 = 24 * 3600;
|
2021-08-09 07:13:10 -07:00
|
|
|
|
2021-08-16 06:07:04 -07:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Quote {
|
|
|
|
pub timestamp: i64,
|
|
|
|
pub price: f64,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn fetch_historical_prices(
|
2023-03-14 07:57:55 -07:00
|
|
|
coin: u8,
|
2021-08-16 06:07:04 -07:00
|
|
|
now: i64,
|
|
|
|
days: u32,
|
|
|
|
currency: &str,
|
|
|
|
) -> anyhow::Result<Vec<Quote>> {
|
2023-03-14 07:57:55 -07:00
|
|
|
let c = CoinConfig::get(coin);
|
|
|
|
let chain = c.chain;
|
2021-09-06 17:53:54 -07:00
|
|
|
let json_error = || anyhow::anyhow!("Invalid JSON");
|
2021-08-16 06:07:04 -07:00
|
|
|
let today = now / DAY_SEC;
|
|
|
|
let from_day = today - days as i64;
|
2023-03-14 07:57:55 -07:00
|
|
|
let latest_quote = {
|
|
|
|
let db = c.db()?;
|
|
|
|
db.get_latest_quote(currency)?
|
|
|
|
};
|
2021-08-16 06:07:04 -07:00
|
|
|
let latest_day = if let Some(latest_quote) = latest_quote {
|
|
|
|
latest_quote.timestamp / DAY_SEC
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
};
|
|
|
|
let latest_day = latest_day.max(from_day);
|
|
|
|
|
|
|
|
let mut quotes: Vec<Quote> = vec![];
|
2023-03-14 19:58:13 -07:00
|
|
|
let from = (latest_day + 1) * DAY_SEC;
|
|
|
|
let to = today * DAY_SEC;
|
|
|
|
if from != to {
|
2021-08-16 06:07:04 -07:00
|
|
|
let client = reqwest::Client::new();
|
|
|
|
let url = format!(
|
|
|
|
"https://api.coingecko.com/api/v3/coins/{}/market_chart/range",
|
2022-03-07 06:47:06 -08:00
|
|
|
chain.ticker()
|
2021-08-16 06:07:04 -07:00
|
|
|
);
|
|
|
|
let params = [
|
|
|
|
("from", from.to_string()),
|
|
|
|
("to", to.to_string()),
|
|
|
|
("vs_currency", currency.to_string()),
|
|
|
|
];
|
|
|
|
let req = client.get(url).query(¶ms);
|
|
|
|
let res = req.send().await?;
|
2023-03-14 19:58:13 -07:00
|
|
|
let t = res.text().await?;
|
|
|
|
let r: serde_json::Value = serde_json::from_str(&t)?;
|
|
|
|
let status = &r["status"]["error_code"];
|
|
|
|
if status.is_null() {
|
|
|
|
let prices = r["prices"].as_array().ok_or_else(json_error)?;
|
|
|
|
let mut prev_timestamp = 0i64;
|
|
|
|
for p in prices.iter() {
|
|
|
|
let p = p.as_array().ok_or_else(json_error)?;
|
|
|
|
let ts = p[0].as_i64().ok_or_else(json_error)? / 1000;
|
|
|
|
let price = p[1].as_f64().ok_or_else(json_error)?;
|
|
|
|
// rounded to daily
|
|
|
|
let date = NaiveDateTime::from_timestamp_opt(ts, 0)
|
|
|
|
.ok_or(anyhow!("Invalid Date"))?
|
|
|
|
.date()
|
|
|
|
.and_hms_opt(0, 0, 0)
|
|
|
|
.ok_or(anyhow!("Invalid Date"))?;
|
|
|
|
let timestamp = date.timestamp();
|
|
|
|
if timestamp != prev_timestamp {
|
|
|
|
let quote = Quote { timestamp, price };
|
|
|
|
quotes.push(quote);
|
|
|
|
}
|
|
|
|
prev_timestamp = timestamp;
|
2021-08-16 06:07:04 -07:00
|
|
|
}
|
2021-08-09 07:13:10 -07:00
|
|
|
}
|
|
|
|
}
|
2021-08-16 06:07:04 -07:00
|
|
|
|
|
|
|
Ok(quotes)
|
2021-08-09 07:13:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use crate::db::DEFAULT_DB_PATH;
|
2021-08-16 06:07:04 -07:00
|
|
|
use crate::prices::fetch_historical_prices;
|
|
|
|
use crate::DbAdapter;
|
|
|
|
use std::time::SystemTime;
|
2022-03-07 06:47:06 -08:00
|
|
|
use zcash_params::coin::CoinType;
|
2021-08-09 07:13:10 -07:00
|
|
|
|
|
|
|
#[tokio::test]
|
2021-08-16 06:07:04 -07:00
|
|
|
async fn test_fetch_quotes() {
|
2021-08-09 07:13:10 -07:00
|
|
|
let currency = "EUR";
|
2022-04-19 09:47:08 -07:00
|
|
|
let mut db = DbAdapter::new(CoinType::Zcash, DEFAULT_DB_PATH).unwrap();
|
2021-08-16 06:07:04 -07:00
|
|
|
let now = SystemTime::now()
|
|
|
|
.duration_since(SystemTime::UNIX_EPOCH)
|
|
|
|
.unwrap()
|
|
|
|
.as_secs() as i64;
|
|
|
|
let quotes = fetch_historical_prices(now, 365, currency, &db)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
for q in quotes.iter() {
|
|
|
|
println!("{:?}", q);
|
|
|
|
}
|
|
|
|
db.store_historical_prices("es, currency).unwrap();
|
2021-08-09 07:13:10 -07:00
|
|
|
}
|
2021-08-16 06:07:04 -07:00
|
|
|
}
|