use crate::{Direction, Order, OrderKind};
use pine_core::Bar;
pub trait FillModel {
fn fill(&self, order: &Order, bar: &Bar) -> Option<f64>;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct PineFills {
pub slippage: f64,
pub mintick: f64,
}
impl PineFills {
fn slip(&self, direction: Direction, price: f64) -> f64 {
price + direction.sign() * self.slippage * self.mintick
}
}
impl FillModel for PineFills {
fn fill(&self, order: &Order, bar: &Bar) -> Option<f64> {
let raw = match order.kind {
OrderKind::Market => bar.open,
OrderKind::Limit(price) => {
let reached = match order.direction {
Direction::Long => bar.low <= price,
Direction::Short => bar.high >= price,
};
if !reached {
return None;
}
match order.direction {
Direction::Long => bar.open.min(price),
Direction::Short => bar.open.max(price),
}
}
OrderKind::Stop(price) => {
let reached = match order.direction {
Direction::Long => bar.high >= price,
Direction::Short => bar.low <= price,
};
if !reached {
return None;
}
match order.direction {
Direction::Long => bar.open.max(price),
Direction::Short => bar.open.min(price),
}
}
OrderKind::StopLimit { stop, limit } => {
let armed = match order.direction {
Direction::Long => bar.high >= stop,
Direction::Short => bar.low <= stop,
};
if !armed {
return None;
}
let reached = match order.direction {
Direction::Long => bar.low <= limit,
Direction::Short => bar.high >= limit,
};
if !reached {
return None;
}
limit
}
};
Some(self.slip(order.direction, raw))
}
}