2021-01-03 15:54:36 +00:00
|
|
|
use core::fmt;
|
2021-01-04 12:07:03 +00:00
|
|
|
use std::borrow::Cow;
|
2021-01-14 18:56:31 +00:00
|
|
|
use std::fmt::{Display, Formatter};
|
2021-01-24 20:53:33 +00:00
|
|
|
use std::str::FromStr;
|
2021-01-05 14:51:03 +00:00
|
|
|
|
|
|
|
use regex::Regex;
|
|
|
|
|
|
|
|
use crate::BoxError;
|
2021-01-03 15:54:36 +00:00
|
|
|
|
2021-01-05 19:50:14 +00:00
|
|
|
#[derive(Clone, PartialEq, Hash, Debug, Eq)]
|
2021-01-04 12:07:03 +00:00
|
|
|
pub struct Symbol {
|
2021-01-05 14:51:03 +00:00
|
|
|
name: Cow<'static, str>,
|
2021-01-03 15:54:36 +00:00
|
|
|
}
|
2021-01-02 19:01:39 +00:00
|
|
|
|
2021-01-05 14:51:03 +00:00
|
|
|
impl<S> From<S> for Symbol
|
|
|
|
where
|
|
|
|
S: Into<String>,
|
|
|
|
{
|
2021-01-04 10:45:54 +00:00
|
|
|
fn from(item: S) -> Self {
|
2021-01-04 12:07:03 +00:00
|
|
|
Symbol::new(item.into())
|
2021-01-04 10:45:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-02 19:01:39 +00:00
|
|
|
impl Symbol {
|
2021-01-04 12:07:03 +00:00
|
|
|
pub const XMR: Symbol = Symbol::new_static("XMR");
|
|
|
|
pub const BTC: Symbol = Symbol::new_static("BTC");
|
|
|
|
pub const ETH: Symbol = Symbol::new_static("ETH");
|
|
|
|
pub const LTC: Symbol = Symbol::new_static("LTC");
|
2021-01-26 16:19:00 +00:00
|
|
|
pub const DOT: Symbol = Symbol::new_static("DOT");
|
|
|
|
|
|
|
|
// Paper trading
|
2021-01-05 19:50:14 +00:00
|
|
|
pub const TESTBTC: Symbol = Symbol::new_static("TESTBTC");
|
|
|
|
pub const TESTUSD: Symbol = Symbol::new_static("TESTUSD");
|
2021-01-26 16:19:00 +00:00
|
|
|
|
|
|
|
// Fiat coins
|
2021-01-04 12:07:03 +00:00
|
|
|
pub const USD: Symbol = Symbol::new_static("USD");
|
|
|
|
pub const GBP: Symbol = Symbol::new_static("GBP");
|
|
|
|
pub const EUR: Symbol = Symbol::new_static("EUR");
|
|
|
|
|
|
|
|
pub fn new(name: String) -> Self {
|
2021-01-05 14:51:03 +00:00
|
|
|
Symbol {
|
|
|
|
name: Cow::from(name),
|
|
|
|
}
|
2021-01-04 12:07:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub const fn new_static(name: &'static str) -> Self {
|
2021-01-05 14:51:03 +00:00
|
|
|
Symbol {
|
|
|
|
name: Cow::Borrowed(name),
|
|
|
|
}
|
2021-01-04 10:45:54 +00:00
|
|
|
}
|
|
|
|
|
2021-01-03 15:54:36 +00:00
|
|
|
pub fn name(&self) -> &str {
|
|
|
|
&self.name
|
|
|
|
}
|
2021-01-02 19:01:39 +00:00
|
|
|
}
|
|
|
|
|
2021-01-03 15:54:36 +00:00
|
|
|
impl Display for Symbol {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
|
|
write!(f, "{}", self.name)
|
|
|
|
}
|
2021-01-02 19:01:39 +00:00
|
|
|
}
|
|
|
|
|
2021-01-05 19:50:14 +00:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
2021-01-04 12:07:03 +00:00
|
|
|
pub struct SymbolPair {
|
|
|
|
quote: Symbol,
|
|
|
|
base: Symbol,
|
2021-01-02 19:01:39 +00:00
|
|
|
}
|
|
|
|
|
2021-01-03 15:54:36 +00:00
|
|
|
impl SymbolPair {
|
2021-01-04 10:45:54 +00:00
|
|
|
pub fn new(quote: Symbol, base: Symbol) -> Self {
|
|
|
|
SymbolPair { quote, base }
|
|
|
|
}
|
|
|
|
pub fn trading_repr(&self) -> String {
|
2021-01-03 15:54:36 +00:00
|
|
|
format!("t{}{}", self.quote, self.base)
|
2021-01-02 19:01:39 +00:00
|
|
|
}
|
2021-01-04 10:45:54 +00:00
|
|
|
pub fn funding_repr(&self) -> String {
|
2021-01-03 15:54:36 +00:00
|
|
|
format!("f{}{}", self.quote, self.base)
|
2021-01-02 19:01:39 +00:00
|
|
|
}
|
2021-01-03 15:54:36 +00:00
|
|
|
pub fn quote(&self) -> &Symbol {
|
|
|
|
&self.quote
|
2021-01-02 19:01:39 +00:00
|
|
|
}
|
2021-01-03 15:54:36 +00:00
|
|
|
pub fn base(&self) -> &Symbol {
|
|
|
|
&self.base
|
2021-01-02 19:01:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-04 12:07:03 +00:00
|
|
|
impl Into<String> for SymbolPair {
|
|
|
|
fn into(self) -> String {
|
2021-01-05 19:50:14 +00:00
|
|
|
format!("{}/{}", self.base, self.quote)
|
2021-01-04 12:07:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-22 16:08:03 +00:00
|
|
|
impl FromStr for SymbolPair {
|
|
|
|
type Err = BoxError;
|
2021-01-05 14:51:03 +00:00
|
|
|
|
2021-01-22 16:08:03 +00:00
|
|
|
fn from_str(value: &str) -> Result<Self, Self::Err> {
|
2021-01-05 19:50:14 +00:00
|
|
|
const REGEX: &str = r"^[t|f](?P<base>\w{3,7}):?(?P<quote>\w{3,7})";
|
2021-01-05 14:51:03 +00:00
|
|
|
|
|
|
|
let captures = Regex::new(REGEX)?.captures(&value).ok_or("Invalid input")?;
|
|
|
|
let quote = captures.name("quote").ok_or("Quote not found")?.as_str();
|
|
|
|
let base = captures.name("base").ok_or("Base not found")?.as_str();
|
|
|
|
|
|
|
|
Ok(SymbolPair {
|
|
|
|
quote: quote.into(),
|
|
|
|
base: base.into(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-04 12:07:03 +00:00
|
|
|
impl Display for SymbolPair {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
2021-01-05 19:50:14 +00:00
|
|
|
write!(f, "{}/{}", self.base, self.quote)
|
2021-01-04 12:07:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-02 19:01:39 +00:00
|
|
|
#[derive(Clone)]
|
|
|
|
enum WalletKind {
|
|
|
|
Margin,
|
|
|
|
Exchange,
|
|
|
|
Funding,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
2021-01-04 12:07:03 +00:00
|
|
|
struct Balance {
|
|
|
|
pair: SymbolPair,
|
2021-01-03 15:54:36 +00:00
|
|
|
base_price: f64,
|
|
|
|
base_amount: f64,
|
2021-01-02 19:01:39 +00:00
|
|
|
quote_equivalent: f64,
|
|
|
|
wallet: WalletKind,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Balance {
|
2021-01-03 15:54:36 +00:00
|
|
|
pub fn new(pair: SymbolPair, base_price: f64, base_amount: f64, wallet: WalletKind) -> Self {
|
2021-01-05 14:51:03 +00:00
|
|
|
Balance {
|
|
|
|
pair,
|
|
|
|
base_price,
|
|
|
|
base_amount,
|
|
|
|
quote_equivalent: base_amount * base_price,
|
|
|
|
wallet,
|
|
|
|
}
|
2021-01-02 19:01:39 +00:00
|
|
|
}
|
|
|
|
|
2021-01-03 15:54:36 +00:00
|
|
|
pub fn pair(&self) -> &SymbolPair {
|
|
|
|
&self.pair
|
2021-01-02 19:01:39 +00:00
|
|
|
}
|
2021-01-03 15:54:36 +00:00
|
|
|
pub fn base_price(&self) -> f64 {
|
|
|
|
self.base_price
|
|
|
|
}
|
|
|
|
pub fn base_amount(&self) -> f64 {
|
|
|
|
self.base_amount
|
2021-01-02 19:01:39 +00:00
|
|
|
}
|
|
|
|
pub fn quote_equivalent(&self) -> f64 {
|
|
|
|
self.quote_equivalent
|
|
|
|
}
|
|
|
|
pub fn wallet(&self) -> &WalletKind {
|
|
|
|
&self.wallet
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-04 12:07:03 +00:00
|
|
|
struct BalanceGroup {
|
2021-01-02 19:01:39 +00:00
|
|
|
quote_equivalent: f64,
|
2021-01-04 12:07:03 +00:00
|
|
|
balances: Vec<Balance>,
|
2021-01-02 19:01:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl BalanceGroup {
|
2021-01-03 15:54:36 +00:00
|
|
|
pub fn new() -> Self {
|
2021-01-05 14:51:03 +00:00
|
|
|
BalanceGroup {
|
|
|
|
balances: Vec::new(),
|
|
|
|
quote_equivalent: 0f64,
|
|
|
|
}
|
2021-01-02 19:01:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_balance(&mut self, balance: &Balance) {
|
|
|
|
self.balances.push(balance.clone());
|
|
|
|
|
|
|
|
self.quote_equivalent += balance.quote_equivalent()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn currency_names(&self) -> Vec<String> {
|
2021-01-05 14:51:03 +00:00
|
|
|
self.balances
|
|
|
|
.iter()
|
2021-01-03 15:54:36 +00:00
|
|
|
.map(|x| x.pair().base().name().into())
|
2021-01-02 19:01:39 +00:00
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn balances(&self) -> &Vec<Balance> {
|
|
|
|
&self.balances
|
|
|
|
}
|
|
|
|
}
|