Overhauled data module to revolve around traits rather than standardized models | Added timeseries/candle struct and traits

dev
Griffiths Lott 3 years ago
parent 1ae5eb25db
commit 4fb67445a9
  1. 41
      src/data.rs
  2. 49
      src/data/crypto.rs
  3. 58
      src/data/data_service.rs
  4. 51
      src/data/equity.rs
  5. 163
      src/data/options.rs
  6. 56
      src/data/price_history.rs
  7. 60
      src/data/quotes.rs
  8. 78
      src/data/timeseries.rs
  9. 5
      src/lib.rs
  10. 47
      src/order.rs

@ -1,11 +1,32 @@
mod equity;
mod crypto;
mod options;
mod price_history;
mod data_service;
pub enum AssetDataObject {
Equity(equity::Equity),
Crypro(crypto::Crypto),
OptionContract(options::OptionContract),
pub mod quotes;
pub mod options;
pub mod timeseries;
use chrono::{DateTime, Utc};
use super::DynResult;
pub trait TimeStamp {
fn timestamp(&self) -> DateTime<Utc>;
}
pub trait Volume {
fn volume(&self) -> Option<u64>;
}
pub fn to_datetime(timestamp: i64) {
}
pub enum Period {
Second,
Minute,
Hour,
Day,
TradeDay,
Week,
TradeWeek,
Month,
Year,
Ytd,
AssetLife
}

@ -1,49 +0,0 @@
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>;
}

@ -1,58 +0,0 @@
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>;
}

@ -1,51 +0,0 @@
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>;
}

@ -1,11 +1,13 @@
use std::fmt::Display;
use chrono::{TimeZone, LocalResult, DateTime};
use chrono::{TimeZone, LocalResult, DateTime, Utc};
use polars::{prelude::DataFrame, df, prelude::{NamedFrom}};
use regex::Regex;
use crate::DynResult;
use super::quotes::{QuoteData, AssetIdentifier, VolumeData, PriceSpreadData};
#[derive(Debug)]
pub struct OptionContractError {
error: String
@ -22,6 +24,7 @@ impl Display for OptionContractError {
}
impl std::error::Error for OptionContractError {}
#[derive(Debug, Clone)]
pub enum OptionKind {
Call,
Put
@ -61,25 +64,125 @@ pub struct OptionContract {
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>
pub bid_size: u64,
pub ask_size: u64,
pub last_size: u64,
pub volume: u64,
pub high: f64,
pub open: f64,
pub low: f64,
pub close: f64,
pub greeks: Greeks,
pub volatility: f64,
pub quote_time: i64
}
impl QuoteData for OptionContract {
fn asset_symbol(&self) -> AssetIdentifier {
AssetIdentifier::Ticker(self.symbol.clone())
}
fn exchange(&self) -> Option<String> {
self.exchange.clone()
}
fn quote_time(&self) -> DateTime<chrono::Utc> {
Utc.timestamp_millis_opt(self.quote_time).unwrap()
}
fn retrieve_time(&self) ->DateTime<Utc> {
self.quote_time()
}
}
impl VolumeData for OptionContract {
fn ask_size(&self) -> u64 {
self.ask_size
}
fn bid_size(&self) -> u64 {
self.bid_size
}
fn last_size(&self) -> Option<u64> {
Some(self.last_size)
}
fn total_volume(&self) -> u64 {
self.volume
}
fn volume_period(&self) -> super::Period {
super::Period::Day
}
}
impl PriceSpreadData for OptionContract {
fn ask(&self) -> f64 {
self.ask
}
fn bid(&self) -> f64 {
self.bid
}
fn mid(&self) -> f64 {
self.mid
}
}
impl OptionContract {
pub fn expiration_as_date(&self) -> LocalResult<DateTime<chrono::Utc>> {
chrono::Utc.timestamp_millis_opt(self.expiration)
impl OptionsData for OptionContract {
fn days_to_expirations(&self) -> i32 {
self.dte as i32
}
fn expiration(&self) -> DateTime<Utc> {
Utc.timestamp_millis_opt(self.expiration).unwrap()
}
fn implied_volatility(&self) -> Option<f64> {
Some(self.volatility)
}
fn underlying(&self) -> AssetIdentifier {
AssetIdentifier::Ticker(self.underlying.clone())
}
fn option_type(&self) -> OptionKind {
self.kind.clone()
}
fn strike_price(&self) -> f64 {
self.strike_price
}
}
impl GreeksData for OptionContract {
fn delta(&self) -> Option<f64> {
self.greeks.delta
}
fn gamma(&self) -> Option<f64> {
self.greeks.gamma
}
fn theta(&self) -> Option<f64> {
self.greeks.theta
}
fn rho(&self) -> Option<f64> {
self.greeks.rho
}
fn vega(&self) -> Option<f64> {
self.greeks.vega
}
fn valid_greek(greek: f64) -> bool {
greek >= -1.0 && greek <= 1.0
}
}
pub trait ToOptionContract {
fn to_option_contract(&self) -> DynResult<OptionContract>;
pub trait OptionsData {
/// Gives the underlying asset of an options
fn underlying(&self) -> AssetIdentifier;
/// Returns the options type
fn option_type(&self) -> OptionKind;
/// Returns strike price
fn strike_price(&self) -> f64;
fn expiration(&self) -> DateTime<Utc>;
fn days_to_expirations(&self) -> i32;
fn implied_volatility(&self) -> Option<f64>;
}
/// Methods for accessing Greeks
pub trait GreeksData {
fn delta(&self) -> Option<f64>;
fn gamma(&self) -> Option<f64>;
fn theta(&self) -> Option<f64>;
fn vega(&self) -> Option<f64>;
fn rho(&self) -> Option<f64>;
fn valid_greek(greek: f64) -> bool {
greek >= -1.0 && greek <= 1.0
}
}
pub struct Greeks {
@ -137,30 +240,12 @@ pub fn create_optionchain_dataframe(options: Vec<OptionContract>) -> DynResult<O
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
});
deltas.push(op.greeks.delta);
deltas.push(op.greeks.delta);
gammas.push(op.greeks.gamma);
thetas.push(op.greeks.theta);
vegas.push(op.greeks.vega);
rhos.push(op.greeks.rho);
volatilitys.push(op.volatility);
}
Ok(df!(

@ -1,56 +0,0 @@
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" => &timestamp
)?)
}

@ -0,0 +1,60 @@
use chrono::{Utc, DateTime};
use super::Period;
use super::options::OptionKind;
pub enum AssetIdentifier{
Ticker(String),
Cusip(String),
Other(String)
}
///Information about what this quote it, where it came from and when
///
pub trait QuoteData {
/// Gives the symbol/ticker/cusip of this asset
fn asset_symbol(&self) -> AssetIdentifier;
/// Gives the timestamp of when the quote data is valid
fn quote_time(&self) -> DateTime<Utc>;
/// Gives the timestamp of when the quote was created
fn retrieve_time(&self) ->DateTime<Utc>;
/// Gives the exchange which the data was sources from
fn exchange(&self) -> Option<String>;
// TO DO: Gives the datasource used
}
///Standard volume information
///
pub trait VolumeData {
/// Gives the period over which this volume is valid
fn volume_period(&self) -> Period;
/// Total volume seem in that period
fn total_volume(&self) -> u64;
/// Gives the current bid size of the asset
fn bid_size(&self) -> u64;
// Gives the current as size of the asset
fn ask_size(&self) -> u64;
// Gives the size of the last trade
fn last_size(&self) -> Option<u64>;
}
///Standard information about price spread
///
pub trait PriceSpreadData {
/// Give the bid price of an asset
fn bid(&self) -> f64;
/// Gives the mid price of an asset
fn mid(&self) -> f64;
/// Gives the ask price of an asset
fn ask(&self) -> f64;
}
pub trait Marginable {
/// Gives the margin cost as a yearly interest cost. Returns none if not marginable
fn margin_cost(&self) -> Option<f64>;
/// Returns true if we can use margin on this instrument
fn is_marginable(&self) -> bool;
}
pub trait CryptoData {
fn base_crypto(&self) -> String;
fn quote_crypto(&self) -> String;
}

@ -0,0 +1,78 @@
use chrono::{DateTime, Utc};
use super::{Volume, TimeStamp, DynResult};
use polars::{prelude::DataFrame, df, prelude::{NamedFrom}};
pub struct Candle {
pub high: f64,
pub open: f64,
pub low: f64,
pub close: f64,
pub volume: Option<u64>,
pub timestamp: DateTime<Utc>
}
impl Candle {
fn from<SourceData>(data: SourceData) -> Self
where SourceData: HOLC + TimeStamp + Volume {
Candle { high: data.high(),
open: data.open(),
low: data.low(),
close: data.close(),
volume: data.volume(),
timestamp: data.timestamp(),
}
}
}
pub trait HOLC {
fn high(&self) -> f64;
fn open(&self) -> f64;
fn low(&self) -> f64;
fn close(&self) -> f64;
}
pub struct TimeSeries {
candles: Vec<Candle>
}
impl TimeSeries {
fn new(candles: Vec<Candle>) -> Self {
TimeSeries { candles: candles }
}
fn from<C>(data: Vec<C>) -> Self
where C: HOLC + TimeStamp + Volume
{
let mut candles: Vec<Candle> = Vec::new();
for d in data {
candles.push(Candle::from(d))
}
TimeSeries::new(candles)
}
}
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.timestamp_millis());
}
Ok(df!(
"High" => &high,
"Open" => &open,
"Low" => &low,
"Close"=> &close,
"Volume"=> &volume,
"TimeStamp" => &timestamp
)?)
}

@ -6,7 +6,8 @@ pub type DynResult<T> = Result<T, Box< dyn std::error::Error>>;
#[cfg(test)]
mod tests {
use super::*;
use super::*;
}

@ -1,47 +0,0 @@
use crate::data::AssetDataObject;
pub enum Direction {
Buy,
Sell
}
impl ToString for Direction {
fn to_string(&self) -> String {
match &self {
Self::Buy => "Buy".to_string(),
Self::Sell => "Sell".to_string()
}
}
}
pub enum OrderType {
Market,
Limit,
Stop,
TrailingStop
}
impl ToString for OrderType {
fn to_string(&self) -> String {
match &self {
Self::Market => "Market".to_string(),
Self::Limit => "Limit".to_string(),
Self::Stop => "Stop".to_string(),
Self::TrailingStop => "TrailingStop".to_string()
}
}
}
pub struct SimpleOrder {
pub asset: AssetDataObject,
pub price_to_pay: f64,
pub direction: Direction,
pub order_type: OrderType,
pub good_until: i64,
pub approved: bool
}
pub struct CompoundOrder {
pub orders: Vec<SimpleOrder>,
pub approved: bool
}
Loading…
Cancel
Save