master
commit
a7079454a2
@ -0,0 +1,3 @@ |
|||||||
|
/target |
||||||
|
/Cargo.lock |
||||||
|
to-do.txt |
||||||
@ -0,0 +1,11 @@ |
|||||||
|
[package] |
||||||
|
name = "RustyTrader" |
||||||
|
version = "0.1.0" |
||||||
|
edition = "2021" |
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
||||||
|
|
||||||
|
[dependencies] |
||||||
|
chrono = "0.4.23" |
||||||
|
regex = "1.7.0" |
||||||
|
polars = "0.25.1" |
||||||
@ -0,0 +1,5 @@ |
|||||||
|
mod equity; |
||||||
|
mod crypto; |
||||||
|
mod options; |
||||||
|
mod price_history; |
||||||
|
mod data_service; |
||||||
@ -0,0 +1,49 @@ |
|||||||
|
use std::fmt::Display; |
||||||
|
use crate::DynResult; |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
pub struct CryptoError { |
||||||
|
_error: String |
||||||
|
} |
||||||
|
impl CryptoError { |
||||||
|
pub fn new(error_msg: &str) -> Self { |
||||||
|
CryptoError { _error: error_msg.to_owned() } |
||||||
|
} |
||||||
|
} |
||||||
|
impl Display for CryptoError { |
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
||||||
|
write!(f, "Crypto Error Placeholder") |
||||||
|
} |
||||||
|
} |
||||||
|
impl std::error::Error for CryptoError {} |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
pub struct Crypto { |
||||||
|
pub symbol: String, |
||||||
|
pub exchange: Option<String>, |
||||||
|
pub base_crypto: String, // being purchased (top)
|
||||||
|
pub quote_crypto: String, |
||||||
|
pub bid: f64, |
||||||
|
pub mid: f64, |
||||||
|
pub ask: f64, |
||||||
|
pub last: Option<f64>, |
||||||
|
pub bid_size: Option<usize>, |
||||||
|
pub ask_size: Option<usize>, |
||||||
|
pub volume: Option<usize>, |
||||||
|
pub high: Option<f64>, |
||||||
|
pub open: Option<f64>, |
||||||
|
pub low: Option<f64>, |
||||||
|
pub close: Option<f64>, |
||||||
|
pub marginable: Option<bool>, |
||||||
|
pub quote_time: i64 |
||||||
|
} |
||||||
|
impl Crypto { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub trait ToCrypto { |
||||||
|
fn to_crypto(&self) -> DynResult<Crypto>; |
||||||
|
} |
||||||
@ -0,0 +1,58 @@ |
|||||||
|
use crate::data::*; |
||||||
|
use crate::DynResult; |
||||||
|
|
||||||
|
/* |
||||||
|
A data service must implement at lease one of the following traits |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Important to note that Paramaters can be typed as Option<P> during implemenation |
||||||
|
and that the actual strucut/type passed into these is flexable. This should allow |
||||||
|
each services library to implement a paramates trait that works for them, or
|
||||||
|
leave paramaters as 'None' |
||||||
|
|
||||||
|
This way you can lock down what paramaters are required for each indiviudual service |
||||||
|
while still allowing the RustyTrade framework to reliably obtain the expected struct |
||||||
|
from each trait interface. |
||||||
|
|
||||||
|
struct ExamplePriceHistoryParams { |
||||||
|
start_date: i64, |
||||||
|
end_date: i64 |
||||||
|
} |
||||||
|
|
||||||
|
struct ExampleDataService {}; |
||||||
|
impl GetPriceHistory for ExampleDataService { |
||||||
|
type Paramaters = ExamplePriceHistoryParmas; |
||||||
|
fn get_price_history(&mut self, paramaters: Self::Paramaters)-> DynResult<PriceHistory> { |
||||||
|
|
||||||
|
}
|
||||||
|
} |
||||||
|
|
||||||
|
*/ |
||||||
|
pub trait GetEquity { |
||||||
|
type Paramaters; |
||||||
|
fn get_equity(&mut self, paramaters: Self::Paramaters) -> DynResult<equity::Equity>; |
||||||
|
} |
||||||
|
pub trait GetCrypto { |
||||||
|
type Paramaters; |
||||||
|
fn get_crypto(&mut self, paramaters: Self::Paramaters) -> DynResult<crypto::Crypto>; |
||||||
|
} |
||||||
|
pub trait GetOptionContract { |
||||||
|
type Paramaters; |
||||||
|
fn get_option_contract(&mut self, paramaters: Self::Paramaters) -> DynResult<options::OptionContract>; |
||||||
|
} |
||||||
|
pub trait GetOptionChain { |
||||||
|
type Paramaters; |
||||||
|
fn get_options_chain_vec(&mut self, paramaters: Self::Paramaters) -> DynResult<Vec<options::OptionContract>>; |
||||||
|
fn get_options_chain_dataframe(&mut self, paramaters: Self::Paramaters) -> DynResult<options::OptionChainDataFrame>; |
||||||
|
} |
||||||
|
pub trait GetPriceHistory{ |
||||||
|
type Paramaters; |
||||||
|
fn get_price_history(&mut self, paramaters: Self::Paramaters)-> DynResult<price_history::PriceHistory>; |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,51 @@ |
|||||||
|
use std::fmt::Display; |
||||||
|
use crate::DynResult; |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
pub struct EquityError { |
||||||
|
error: String |
||||||
|
} |
||||||
|
impl EquityError { |
||||||
|
pub fn new(error_msg: &str) -> Self { |
||||||
|
EquityError { error: error_msg.to_owned() } |
||||||
|
} |
||||||
|
} |
||||||
|
impl Display for EquityError { |
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
||||||
|
write!(f, "Equity Error Placeholder") |
||||||
|
} |
||||||
|
} |
||||||
|
impl std::error::Error for EquityError {} |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
pub struct Equity { |
||||||
|
pub symbol: String, |
||||||
|
pub cusip : Option<String>, |
||||||
|
pub exchange: Option<String>, |
||||||
|
pub bid: f64, |
||||||
|
pub mid: f64, |
||||||
|
pub ask: f64, |
||||||
|
pub last: Option<f64>, |
||||||
|
pub bid_size: Option<usize>, |
||||||
|
pub ask_size: Option<usize>, |
||||||
|
pub volume: Option<usize>, |
||||||
|
pub high: Option<f64>, |
||||||
|
pub open: Option<f64>, |
||||||
|
pub low: Option<f64>, |
||||||
|
pub close: Option<f64>, |
||||||
|
pub shortable: Option<bool>, |
||||||
|
pub marginable: Option<bool>, |
||||||
|
pub quote_time: i64 |
||||||
|
} |
||||||
|
impl Equity { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub trait ToEquity { |
||||||
|
fn to_equity(&self) -> DynResult<Equity>; |
||||||
|
} |
||||||
@ -0,0 +1,193 @@ |
|||||||
|
use std::fmt::Display; |
||||||
|
use chrono::{TimeZone, LocalResult, DateTime}; |
||||||
|
use polars::{prelude::DataFrame, df, prelude::{NamedFrom}}; |
||||||
|
use regex::Regex; |
||||||
|
|
||||||
|
|
||||||
|
use crate::DynResult; |
||||||
|
|
||||||
|
#[derive(Debug)] |
||||||
|
pub struct OptionContractError { |
||||||
|
error: String |
||||||
|
} |
||||||
|
impl OptionContractError { |
||||||
|
pub fn new(error_msg: &str) -> Self { |
||||||
|
OptionContractError { error: error_msg.to_owned() } |
||||||
|
} |
||||||
|
} |
||||||
|
impl Display for OptionContractError { |
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
||||||
|
write!(f, "OptionContract Error Placeholder") |
||||||
|
} |
||||||
|
} |
||||||
|
impl std::error::Error for OptionContractError {} |
||||||
|
|
||||||
|
pub enum OptionKind { |
||||||
|
Call, |
||||||
|
Put |
||||||
|
} |
||||||
|
impl OptionKind { |
||||||
|
fn from_str(option_kind: &str) -> Result<OptionKind, OptionContractError>{ |
||||||
|
let call = Regex::new("(?i)call|(?i)c").expect("call regex failed:\noptions.rs:\t(?i)call|(?i)c"); |
||||||
|
let put = Regex::new("(?i)put|(?i)p").expect("put regex failed:\noptions.rs:\t(?i)put|(?i)p"); |
||||||
|
|
||||||
|
if call.find(option_kind).is_some() { |
||||||
|
return Ok(OptionKind::Call) |
||||||
|
} else if put.find(option_kind).is_some() { |
||||||
|
return Ok(OptionKind::Put)} |
||||||
|
|
||||||
|
return Err(OptionContractError::new(&format!("Could not convert {option_kind} to an OptionKind (Call/Put)"))) |
||||||
|
} |
||||||
|
} |
||||||
|
impl ToString for OptionKind { |
||||||
|
fn to_string(&self) -> String { |
||||||
|
match &self { |
||||||
|
Self::Call => "Call".to_string(), |
||||||
|
Self::Put => "Put".to_string() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
pub struct OptionContract { |
||||||
|
pub symbol: String, |
||||||
|
pub underlying: String, |
||||||
|
pub exchange: Option<String>, |
||||||
|
pub kind: OptionKind, |
||||||
|
pub strike_price: f64, |
||||||
|
pub expiration: i64, // mls since epoch
|
||||||
|
pub dte: u32, // days to expiration time of quote
|
||||||
|
pub bid: f64, |
||||||
|
pub mid: f64, |
||||||
|
pub ask: f64, |
||||||
|
pub last: Option<f64>, |
||||||
|
pub bid_size: Option<u64>, |
||||||
|
pub ask_size: Option<u64>, |
||||||
|
pub volume: Option<u64>, |
||||||
|
pub high: Option<f64>, |
||||||
|
pub open: Option<f64>, |
||||||
|
pub low: Option<f64>, |
||||||
|
pub close: Option<f64>, |
||||||
|
pub greeks: Option<Greeks>, |
||||||
|
pub volatility: Option<f64> |
||||||
|
} |
||||||
|
impl OptionContract { |
||||||
|
pub fn expiration_as_date(&self) -> LocalResult<DateTime<chrono::Utc>> { |
||||||
|
chrono::Utc.timestamp_millis_opt(self.expiration) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
pub trait ToOptionContract { |
||||||
|
fn to_option_contract(&self) -> DynResult<OptionContract>; |
||||||
|
} |
||||||
|
|
||||||
|
pub struct Greeks { |
||||||
|
delta: Option<f64>, |
||||||
|
gamma: Option<f64>, |
||||||
|
theta: Option<f64>, |
||||||
|
vega: Option<f64>, |
||||||
|
rho: Option<f64>, |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub type OptionChainDataFrame = DataFrame;
|
||||||
|
pub fn create_optionchain_dataframe(options: Vec<OptionContract>) -> DynResult<OptionChainDataFrame> { |
||||||
|
let mut symbols = vec![];
|
||||||
|
let mut underlyings = vec![] ; |
||||||
|
let mut exchanges = vec![] ; |
||||||
|
let mut kinds = vec![] ; |
||||||
|
let mut strike_prices = vec![] ; |
||||||
|
let mut expirations = vec![] ; |
||||||
|
let mut dtes = vec![] ; |
||||||
|
let mut bids = vec![] ; |
||||||
|
let mut mids = vec![] ; |
||||||
|
let mut asks = vec![] ; |
||||||
|
let mut lasts = vec![] ; |
||||||
|
let mut bid_sizes = vec![] ; |
||||||
|
let mut ask_sizes = vec![] ; |
||||||
|
let mut volumes = vec![] ; |
||||||
|
let mut highs = vec![] ; |
||||||
|
let mut opens = vec![] ; |
||||||
|
let mut lows = vec![] ; |
||||||
|
let mut closes = vec![] ; |
||||||
|
let mut deltas = vec![]; |
||||||
|
let mut gammas = vec![] ; |
||||||
|
let mut thetas = vec![] ; |
||||||
|
let mut vegas = vec![] ; |
||||||
|
let mut rhos = vec![] ; |
||||||
|
let mut volatilitys = vec![] ; |
||||||
|
for op in options { |
||||||
|
symbols.push(op.symbol); |
||||||
|
underlyings.push(op.underlying); |
||||||
|
exchanges.push(op.exchange); |
||||||
|
kinds.push(op.kind.to_string()); |
||||||
|
strike_prices.push(op.strike_price); |
||||||
|
expirations.push(op.expiration); |
||||||
|
dtes.push(op.dte); |
||||||
|
bids.push(op.bid); |
||||||
|
mids.push(op.mid); |
||||||
|
asks.push(op.ask); |
||||||
|
lasts.push(op.last); |
||||||
|
bid_sizes.push(op.bid_size); |
||||||
|
ask_sizes.push(op.ask_size); |
||||||
|
volumes.push(op.volume); |
||||||
|
highs.push(op.high); |
||||||
|
opens.push(op.open); |
||||||
|
lows.push(op.low); |
||||||
|
closes.push(op.close); |
||||||
|
deltas.push(match &op.greeks { |
||||||
|
Some(greeks) => greeks.delta, |
||||||
|
None => None |
||||||
|
}); |
||||||
|
deltas.push(match &op.greeks { |
||||||
|
Some(greeks) => greeks.delta, |
||||||
|
None => None |
||||||
|
}); |
||||||
|
gammas.push(match &op.greeks { |
||||||
|
Some(greeks) => greeks.gamma, |
||||||
|
None => None |
||||||
|
}); |
||||||
|
thetas.push(match &op.greeks { |
||||||
|
Some(greeks) => greeks.theta, |
||||||
|
None => None |
||||||
|
}); |
||||||
|
vegas.push(match &op.greeks { |
||||||
|
Some(greeks) => greeks.vega, |
||||||
|
None => None |
||||||
|
}); |
||||||
|
rhos.push(match &op.greeks { |
||||||
|
Some(greeks) => greeks.rho, |
||||||
|
None => None |
||||||
|
}); |
||||||
|
volatilitys.push(op.volatility); |
||||||
|
} |
||||||
|
Ok(df!( |
||||||
|
"Symbol" => &symbols, |
||||||
|
"Underlying" => &underlyings, |
||||||
|
"Exchange" => &exchanges, |
||||||
|
"Kind" => &kinds, |
||||||
|
"StrikePrice" => &strike_prices, |
||||||
|
"Expiration" => &expirations, |
||||||
|
"DaysToExpiry" => &dtes, |
||||||
|
"Bid" => &bids, |
||||||
|
"Mid" => &mids, |
||||||
|
"Ask" => &asks, |
||||||
|
"Last" => &lasts, |
||||||
|
"BidSize" => &bid_sizes, |
||||||
|
"AskSize" => &ask_sizes, |
||||||
|
"Volume" => &volumes, |
||||||
|
"High" => &highs, |
||||||
|
"Open" => &opens, |
||||||
|
"Low" => &lows, |
||||||
|
"Close" => &closes, |
||||||
|
"Delta" => &deltas, |
||||||
|
"Gamma" => &gammas, |
||||||
|
"Theta" => &thetas, |
||||||
|
"Vegas" => &vegas, |
||||||
|
"Rho" => &rhos, |
||||||
|
"Volatility" => &volatilitys, |
||||||
|
|
||||||
|
)?) |
||||||
|
} |
||||||
@ -0,0 +1,56 @@ |
|||||||
|
use polars::{prelude::DataFrame, df, prelude::{NamedFrom}}; |
||||||
|
|
||||||
|
use crate::DynResult; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Candle { |
||||||
|
pub high: f64, |
||||||
|
pub open: f64, |
||||||
|
pub low: f64, |
||||||
|
pub close: f64, |
||||||
|
pub volume: Option<u64>, |
||||||
|
pub timestamp: i64 // mls since epoch
|
||||||
|
} |
||||||
|
impl Candle { |
||||||
|
pub fn new(high: f64, open: f64, low: f64, close: f64, volume: Option<u64>, timestamp: i64) -> Self { |
||||||
|
Candle { high, open, low, close, volume, timestamp } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct PriceHistory { |
||||||
|
symbol: String, |
||||||
|
candles: Vec<Candle> |
||||||
|
} |
||||||
|
|
||||||
|
pub trait ToPriceHistory { |
||||||
|
fn to_pricehistorty(&self) -> DynResult<PriceHistory>; |
||||||
|
} |
||||||
|
|
||||||
|
pub fn create_timeseries_dataframe(timeseries_data: &Vec<Candle>) -> DynResult<DataFrame> { |
||||||
|
let mut high = vec![]; |
||||||
|
let mut open = vec![]; |
||||||
|
let mut low = vec![]; |
||||||
|
let mut close = vec![]; |
||||||
|
let mut volume = vec![]; |
||||||
|
let mut timestamp = vec![]; |
||||||
|
|
||||||
|
for candle in timeseries_data { |
||||||
|
high.push(candle.high); |
||||||
|
open.push(candle.open); |
||||||
|
low.push(candle.low); |
||||||
|
close.push(candle.close); |
||||||
|
volume.push(candle.volume); |
||||||
|
timestamp.push(candle.timestamp); |
||||||
|
} |
||||||
|
|
||||||
|
Ok(df!( |
||||||
|
"High" => &high, |
||||||
|
"Open" => &open, |
||||||
|
"Low" => &low, |
||||||
|
"Close"=> &close, |
||||||
|
"Volume"=> &volume, |
||||||
|
"TimeStamp" => ×tamp |
||||||
|
)?) |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,11 @@ |
|||||||
|
mod data; |
||||||
|
|
||||||
|
pub type DynResult<T> = Result<T, Box< dyn std::error::Error>>; |
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)] |
||||||
|
mod tests { |
||||||
|
use super::*; |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue