use bitcode::{Decode, Encode};
use chrono::{DateTime, Local, NaiveDateTime, Utc};
use polars::{
frame::DataFrame,
prelude::{DataType, Field, Schema},
};
use crate::Direction;
#[derive(Debug, PartialEq, Encode, Decode, Clone)]
pub struct Tic {
pub ts_nanos: i64,
pub direction: Direction,
pub lots: u32,
pub price: f64,
pub value: f64,
}
impl Tic {
pub fn new(
ts_nanos: i64,
direction: Direction,
lots: u32,
price: f64,
value: f64,
) -> Self {
Tic {
ts_nanos,
direction,
lots,
price,
value,
}
}
pub fn from_df(df: &DataFrame) -> Result<Vec<Tic>, String> {
let ts_nanos = df
.column("ts_nanos")
.unwrap()
.i64()
.unwrap()
.into_no_null_iter();
let mut direction = df
.column("direction")
.unwrap()
.str()
.unwrap()
.into_no_null_iter();
let mut lots = df
.column("lots")
.unwrap()
.i64()
.unwrap()
.into_no_null_iter();
let mut price = df
.column("price")
.unwrap()
.f64()
.unwrap()
.into_no_null_iter();
let mut value = df
.column("value")
.unwrap()
.f64()
.unwrap()
.into_no_null_iter();
let mut tics: Vec<Tic> = Vec::with_capacity(df.height());
for ts in ts_nanos {
let tic = Tic::new(
ts,
Direction::from(direction.next().unwrap()),
lots.next().unwrap() as u32,
price.next().unwrap(),
value.next().unwrap(),
);
tics.push(tic);
}
Ok(tics)
}
pub fn schema() -> Schema {
Schema::from_iter(vec![
Field::new("ts_nanos".into(), DataType::Int64),
Field::new("direction".into(), DataType::String),
Field::new("lots".into(), DataType::Int64),
Field::new("price".into(), DataType::Float64),
Field::new("value".into(), DataType::Float64),
Field::new("session".into(), DataType::Int8),
Field::new("tradeno".into(), DataType::Int64),
])
}
pub fn dt(&self) -> DateTime<Utc> {
DateTime::from_timestamp_nanos(self.ts_nanos)
}
pub fn dt_local(&self) -> NaiveDateTime {
let utc = DateTime::from_timestamp_nanos(self.ts_nanos);
let local: DateTime<Local> = DateTime::from(utc);
local.naive_local()
}
pub fn is_buy(&self) -> bool {
self.direction == Direction::Buy
}
pub fn is_sell(&self) -> bool {
self.direction == Direction::Sell
}
}
impl std::fmt::Display for Tic {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"Tic: {} {} {}x{}={}",
self.dt_local(),
self.direction.to_str(),
self.lots,
self.price,
self.value,
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new() {
let tic = Tic::new(100500, Direction::Buy, 10, 300.0, 3000.0);
assert_eq!(tic.direction, Direction::Buy);
assert_eq!(tic.lots, 10);
assert_eq!(tic.price, 300.0);
assert_eq!(tic.value, 3000.0);
assert!(tic.is_buy());
assert!(!tic.is_sell());
}
}