use urlencoding::encode;
use super::parameter::Market;
const SERVER_TRADER: &str = "https://api.schwabapi.com/trader/v1";
const SERVER_MARKETDATA: &str = "https://api.schwabapi.com/marketdata/v1";
#[derive(Debug)]
pub(crate) enum EndpointAccount {
AccountNumbers,
Accounts,
Account { account_number: String },
}
impl EndpointAccount {
pub(crate) fn url_endpoint(&self) -> String {
match self {
EndpointAccount::AccountNumbers => "/accounts/accountNumbers".to_string(),
EndpointAccount::Accounts => "/accounts".to_string(),
EndpointAccount::Account { account_number } => {
let account_number = encode(account_number);
format!("/accounts/{account_number}")
}
}
}
pub(crate) fn url(&self) -> String {
format!("{SERVER_TRADER}{}", self.url_endpoint())
}
}
#[derive(Debug)]
pub(crate) enum EndpointOrder {
OrdersAccount {
account_number: String,
},
Order {
account_number: String,
order_id: i64,
},
Orders,
PreviewOrderAccount {
account_number: String,
},
}
impl EndpointOrder {
pub(crate) fn url_endpoint(&self) -> String {
match self {
EndpointOrder::OrdersAccount { account_number } => {
let account_number = encode(account_number);
format!("/accounts/{account_number}/orders")
}
EndpointOrder::Order {
account_number,
order_id,
} => {
let account_number = encode(account_number);
format!("/accounts/{account_number}/orders/{order_id}")
}
EndpointOrder::Orders => "/orders".to_string(),
EndpointOrder::PreviewOrderAccount { account_number } => {
let account_number = encode(account_number);
format!("/accounts/{account_number}/previewOrder")
}
}
}
pub(crate) fn url(&self) -> String {
format!("{SERVER_TRADER}{}", self.url_endpoint())
}
}
#[derive(Debug)]
pub(crate) enum EndpointTransaction {
TransactionsAccount {
account_number: String,
},
Transaction {
account_number: String,
transaction_id: i64,
},
}
impl EndpointTransaction {
pub(crate) fn url_endpoint(&self) -> String {
match self {
EndpointTransaction::TransactionsAccount { account_number } => {
let account_number = encode(account_number);
format!("/accounts/{account_number}/transactions")
}
EndpointTransaction::Transaction {
account_number,
transaction_id,
} => {
let account_number = encode(account_number);
format!("/accounts/{account_number}/transactions/{transaction_id}")
}
}
}
pub(crate) fn url(&self) -> String {
format!("{SERVER_TRADER}{}", self.url_endpoint())
}
}
#[derive(Debug)]
pub(crate) enum EndpointUserPreference {
UserPreference,
}
impl EndpointUserPreference {
pub(crate) fn url_endpoint(&self) -> String {
match self {
EndpointUserPreference::UserPreference => "/userPreference".to_string(),
}
}
pub(crate) fn url(&self) -> String {
format!("{SERVER_TRADER}{}", self.url_endpoint())
}
}
#[derive(Debug)]
pub(crate) enum EndpointQuote {
Quotes,
Quote { symbol_id: String },
}
impl EndpointQuote {
pub(crate) fn url_endpoint(&self) -> String {
match self {
EndpointQuote::Quotes => "/quotes".to_string(),
EndpointQuote::Quote { symbol_id } => {
let symbol_id = encode(symbol_id);
format!("/{symbol_id}/quotes")
}
}
}
pub(crate) fn url(&self) -> String {
format!("{SERVER_MARKETDATA}{}", self.url_endpoint())
}
}
#[derive(Debug)]
pub(crate) enum EndpointOptionChain {
Chains,
}
impl EndpointOptionChain {
pub(crate) fn url_endpoint(&self) -> String {
match self {
EndpointOptionChain::Chains => "/chains".to_string(),
}
}
pub(crate) fn url(&self) -> String {
format!("{SERVER_MARKETDATA}{}", self.url_endpoint())
}
}
#[derive(Debug)]
pub(crate) enum EndpointOptionExpirationChain {
ExpirationChain,
}
impl EndpointOptionExpirationChain {
pub(crate) fn url_endpoint(&self) -> String {
match self {
EndpointOptionExpirationChain::ExpirationChain => "/expirationchain".to_string(),
}
}
pub(crate) fn url(&self) -> String {
format!("{SERVER_MARKETDATA}{}", self.url_endpoint())
}
}
#[derive(Debug)]
pub(crate) enum EndpointPriceHistory {
PriceHistory,
}
impl EndpointPriceHistory {
pub(crate) fn url_endpoint(&self) -> String {
match self {
EndpointPriceHistory::PriceHistory => "/pricehistory".to_string(),
}
}
pub(crate) fn url(&self) -> String {
format!("{SERVER_MARKETDATA}{}", self.url_endpoint())
}
}
#[derive(Debug)]
pub(crate) enum EndpointMover {
Mover { symbol_id: String },
}
impl EndpointMover {
pub(crate) fn url_endpoint(&self) -> String {
match self {
EndpointMover::Mover { symbol_id } => {
let symbol_id = encode(symbol_id);
format!("/movers/{symbol_id}")
}
}
}
pub(crate) fn url(&self) -> String {
format!("{SERVER_MARKETDATA}{}", self.url_endpoint())
}
}
#[derive(Debug)]
pub(crate) enum EndpointMarketHour {
Markets,
Market { market_id: Market },
}
impl EndpointMarketHour {
pub(crate) fn url_endpoint(&self) -> String {
match self {
EndpointMarketHour::Markets => "/markets".to_string(),
EndpointMarketHour::Market { market_id } => {
let market_id = serde_json::to_value(market_id).expect("value");
let market_id = market_id.as_str().expect("value is a str");
let market_id = encode(market_id);
format!("/markets/{market_id}")
}
}
}
pub(crate) fn url(&self) -> String {
format!("{SERVER_MARKETDATA}{}", self.url_endpoint())
}
}
#[derive(Debug)]
pub(crate) enum EndpointInstrument {
Instruments,
Instrutment { cusip_id: String },
}
impl EndpointInstrument {
pub(crate) fn url_endpoint(&self) -> String {
match self {
EndpointInstrument::Instruments => "/instruments".to_string(),
EndpointInstrument::Instrutment { cusip_id } => {
let cusip_id = encode(cusip_id);
format!("/instruments/{cusip_id}")
}
}
}
pub(crate) fn url(&self) -> String {
format!("{SERVER_MARKETDATA}{}", self.url_endpoint())
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn test_endpoint_account() {
assert_eq!(
"https://api.schwabapi.com/trader/v1/accounts/accountNumbers",
EndpointAccount::AccountNumbers.url()
);
assert_eq!(
"https://api.schwabapi.com/trader/v1/accounts",
EndpointAccount::Accounts.url()
);
assert_eq!(
"https://api.schwabapi.com/trader/v1/accounts/123456",
EndpointAccount::Account {
account_number: "123456".to_string()
}
.url()
);
}
#[test]
fn test_endpoint_order() {
assert_eq!(
"https://api.schwabapi.com/trader/v1/accounts/123456/orders",
EndpointOrder::OrdersAccount {
account_number: "123456".to_string()
}
.url()
);
assert_eq!(
"https://api.schwabapi.com/trader/v1/accounts/123456/orders/789",
EndpointOrder::Order {
account_number: "123456".to_string(),
order_id: 789
}
.url()
);
assert_eq!(
"https://api.schwabapi.com/trader/v1/orders",
EndpointOrder::Orders.url()
);
assert_eq!(
"https://api.schwabapi.com/trader/v1/accounts/123456/previewOrder",
EndpointOrder::PreviewOrderAccount {
account_number: "123456".to_string()
}
.url()
);
}
#[test]
fn test_endpoint_transaction() {
assert_eq!(
"https://api.schwabapi.com/trader/v1/accounts/123456/transactions",
EndpointTransaction::TransactionsAccount {
account_number: "123456".to_string()
}
.url()
);
assert_eq!(
"https://api.schwabapi.com/trader/v1/accounts/123456/transactions/789",
EndpointTransaction::Transaction {
account_number: "123456".to_string(),
transaction_id: 789
}
.url()
);
}
#[test]
fn test_endpoint_user_preference() {
assert_eq!(
"https://api.schwabapi.com/trader/v1/userPreference",
EndpointUserPreference::UserPreference.url()
);
}
#[test]
fn test_endpoint_quote() {
assert_eq!(
"https://api.schwabapi.com/marketdata/v1/quotes",
EndpointQuote::Quotes.url()
);
assert_eq!(
"https://api.schwabapi.com/marketdata/v1/ABC/quotes",
EndpointQuote::Quote {
symbol_id: "ABC".to_string()
}
.url()
);
}
#[test]
fn test_endpoint_option_chain() {
assert_eq!(
"https://api.schwabapi.com/marketdata/v1/chains",
EndpointOptionChain::Chains.url()
);
}
#[test]
fn test_endpoint_option_expiration_chain() {
assert_eq!(
"https://api.schwabapi.com/marketdata/v1/expirationchain",
EndpointOptionExpirationChain::ExpirationChain.url()
);
}
#[test]
fn test_endpoint_price_history() {
assert_eq!(
"https://api.schwabapi.com/marketdata/v1/pricehistory",
EndpointPriceHistory::PriceHistory.url()
);
}
#[test]
fn test_endpoint_mover() {
assert_eq!(
"https://api.schwabapi.com/marketdata/v1/movers/ABC",
EndpointMover::Mover {
symbol_id: "ABC".to_string()
}
.url()
);
}
#[test]
fn test_endpoint_market_hour() {
assert_eq!(
"https://api.schwabapi.com/marketdata/v1/markets",
EndpointMarketHour::Markets.url()
);
assert_eq!(
"https://api.schwabapi.com/marketdata/v1/markets/equity",
EndpointMarketHour::Market {
market_id: Market::Equity,
}
.url()
);
}
#[test]
fn test_endpoint_instrument() {
assert_eq!(
"https://api.schwabapi.com/marketdata/v1/instruments",
EndpointInstrument::Instruments.url()
);
assert_eq!(
"https://api.schwabapi.com/marketdata/v1/instruments/123456",
EndpointInstrument::Instrutment {
cusip_id: "123456".to_string()
}
.url()
);
}
}