pub mod alphavantage;
pub mod binance;
pub mod bithumb;
pub mod coinone;
pub mod currencylayer;
pub mod dunamu;
pub mod gdac;
pub mod gopax;
pub mod imf_sdr;
use self::{
alphavantage::AlphavantageSource, binance::BinanceSource, bithumb::BithumbSource,
coinone::CoinoneSource, currencylayer::CurrencylayerSource, dunamu::DunamuSource,
gdac::GdacSource, gopax::GopaxSource, imf_sdr::ImfSdrSource,
};
use crate::{
config::{source::AlphavantageConfig, DelphiConfig},
Error, Price, PriceQuantity,
};
use rust_decimal::Decimal;
pub struct Sources {
pub alphavantage: AlphavantageSource,
pub binance: BinanceSource,
pub coinone: CoinoneSource,
pub dunamu: DunamuSource,
pub gdac: GdacSource,
pub gopax: GopaxSource,
pub imf_sdr: ImfSdrSource,
pub bithumb: BithumbSource,
pub currencylayer: CurrencylayerSource,
}
impl Sources {
pub fn new(config: &DelphiConfig) -> Result<Self, Error> {
let alphavantage = AlphavantageSource::new(
&config
.source
.alphavantage
.as_ref()
.unwrap_or(&AlphavantageConfig {
apikey: "default key".to_string(),
})
.apikey,
&config.https,
)?;
let binance = BinanceSource::new(&config.https)?;
let coinone = CoinoneSource::new(&config.https)?;
let gdac = GdacSource::new(&config.https)?;
let dunamu = DunamuSource::new(&config.https)?;
let gopax = GopaxSource::new(&config.https)?;
let imf_sdr = ImfSdrSource::new(&config.https)?;
let bithumb = BithumbSource::new(&config.https)?;
let currencylayer = CurrencylayerSource::new(
&config
.source
.currencylayer
.as_ref()
.expect("missing currencylayer config")
.access_key,
&config.https,
)?;
Ok(Sources {
alphavantage,
binance,
coinone,
dunamu,
gdac,
gopax,
imf_sdr,
bithumb,
currencylayer,
})
}
}
pub trait AskBook {
fn asks(&self) -> Result<Vec<PriceQuantity>, Error>;
}
pub trait BidBook {
fn bids(&self) -> Result<Vec<PriceQuantity>, Error>;
}
pub fn weighted_avg_ask<T: AskBook>(asks: &T) -> Result<Price, Error> {
let asks = asks.asks()?;
let mut price_sum_product = Decimal::from(0u8);
let mut total = Decimal::from(0u8);
for ask in asks {
price_sum_product += *ask.price * ask.quantity;
total += ask.quantity;
}
let weighted_avg = Price::new(price_sum_product / total)?;
Ok(weighted_avg)
}
pub fn weighted_avg_bid<T: BidBook>(bids: &T) -> Result<Price, Error> {
let bids = bids.bids()?;
let mut price_sum_product = Decimal::from(0u8);
let mut total = Decimal::from(0u8);
for bid in bids {
price_sum_product += *bid.price * bid.quantity;
total += bid.quantity;
}
let weighted_avg = Price::new(price_sum_product / total)?;
Ok(weighted_avg)
}
pub fn lowest_ask<T: AskBook>(asks: &T) -> Result<Price, Error> {
let mut asks = asks.asks()?;
asks.sort();
Ok(asks.first().unwrap().price)
}
pub fn highest_bid<T: BidBook>(bids: &T) -> Result<Price, Error> {
let mut bids = bids.bids()?;
bids.sort();
Ok(bids.last().unwrap().price)
}
pub fn midpoint<T: AskBook + BidBook>(book: &T) -> Result<Price, Error> {
let lowest_ask = lowest_ask(book)?;
let highest_bid = highest_bid(book)?;
Ok((lowest_ask + highest_bid) / 2)
}