use super::Price;
use crate::{
config::HttpsConfig,
error::{Error, ErrorKind},
prelude::*,
Currency, TradingPair,
};
use iqhttp::{HttpsClient, Query};
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
pub const API_HOST: &str = "quotation-api-cdn.dunamu.com";
pub struct DunamuSource {
https_client: HttpsClient,
}
impl DunamuSource {
#[allow(clippy::new_without_default)]
pub fn new(config: &HttpsConfig) -> Result<Self, Error> {
let https_client = config.new_client(API_HOST)?;
Ok(Self { https_client })
}
pub async fn trading_pairs(&self, pair: &TradingPair) -> Result<Price, Error> {
if pair.0 != Currency::Krw && pair.1 != Currency::Krw {
fail!(ErrorKind::Currency, "trading pair must be with KRW");
}
let mut query = Query::new();
query.add("codes", format!("FRX.{}{}", pair.0, pair.1));
let api_response: Response = self
.https_client
.get_json("/v1/forex/recent", &query)
.await?;
let price: Decimal = api_response[0].base_price.to_string().parse()?;
Ok(Price::new(price)?)
}
}
pub type Response = Vec<ResponseElement>;
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ResponseElement {
code: String,
currency_code: String,
currency_name: String,
country: String,
name: String,
date: String,
time: String,
recurrence_count: i64,
base_price: f64,
opening_price: f64,
high_price: f64,
low_price: f64,
change: String,
change_price: f64,
cash_buying_price: f64,
cash_selling_price: f64,
tt_buying_price: f64,
tt_selling_price: f64,
tc_buying_price: Option<serde_json::Value>,
fc_selling_price: Option<serde_json::Value>,
exchange_commission: f64,
us_dollar_rate: f64,
#[serde(rename = "high52wPrice")]
high52_w_price: f64,
#[serde(rename = "high52wDate")]
high52_w_date: String,
#[serde(rename = "low52wPrice")]
low52_w_price: f64,
#[serde(rename = "low52wDate")]
low52_w_date: String,
currency_unit: i64,
provider: String,
timestamp: i64,
id: i64,
created_at: String,
modified_at: String,
change_rate: f64,
signed_change_price: f64,
signed_change_rate: f64,
}
#[cfg(test)]
mod tests {
use super::DunamuSource;
#[tokio::test]
#[ignore]
async fn trading_pairs_ok() {
let pair = "KRW/USD".parse().unwrap();
let _response = DunamuSource::new(&Default::default())
.unwrap()
.trading_pairs(&pair)
.await
.unwrap();
}
#[tokio::test]
#[ignore]
async fn trading_pairs_404() {
let pair = "N/A".parse().unwrap();
let _err = DunamuSource::new(&Default::default())
.unwrap()
.trading_pairs(&pair)
.await
.err()
.unwrap();
}
}