use std::{
fmt::{Debug, Display},
ops::{Add, Sub},
};
use bevy::prelude::Deref;
use num_traits::FromPrimitive;
use rust_decimal::Decimal;
use crate::instrument::{AddDecimal, AsDecimal, FromDecimal, InstrumentSpec, SubDecimal, XSpec};
mod corrected;
mod ladder;
mod price_type;
pub use corrected::*;
pub use ladder::*;
pub use price_type::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Price<IS: InstrumentSpec> {
Absolute(AbsolutePrice<IS>),
Relative(RelativePrice<IS>),
}
impl<IS: InstrumentSpec> Price<IS> {
pub fn as_absolute(&self) -> Option<&AbsolutePrice<IS>> {
self.into()
}
pub fn into_absolute(self) -> Option<AbsolutePrice<IS>> {
self.into()
}
pub fn as_relative(&self) -> Option<&RelativePrice<IS>> {
self.into()
}
pub fn into_relative(self) -> Option<RelativePrice<IS>> {
self.into()
}
}
impl<IS: InstrumentSpec> From<AbsolutePrice<IS>> for Price<IS> {
fn from(value: AbsolutePrice<IS>) -> Self {
Self::Absolute(value)
}
}
impl<IS: InstrumentSpec> From<&AbsolutePrice<IS>> for Price<IS> {
fn from(value: &AbsolutePrice<IS>) -> Self {
(*value).into()
}
}
impl<IS: InstrumentSpec> From<RelativePrice<IS>> for Price<IS> {
fn from(value: RelativePrice<IS>) -> Self {
Self::Relative(value)
}
}
impl<IS: InstrumentSpec> From<&RelativePrice<IS>> for Price<IS> {
fn from(value: &RelativePrice<IS>) -> Self {
(*value).into()
}
}
#[derive(Deref, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct RelativePrice<IS: InstrumentSpec>(IS::PriceType);
impl<IS: InstrumentSpec> RelativePrice<IS> {
pub fn new_from_tick_count(tick_count: i64) -> Self {
let relative_price_type = Decimal::from_i64(tick_count).unwrap();
let price_type = IS::PriceType::from_decimal(relative_price_type);
Self(price_type)
}
pub fn as_price(&self) -> Price<IS> {
self.into()
}
pub fn into_price(self) -> Price<IS> {
self.into()
}
}
impl<IS: InstrumentSpec> Add for RelativePrice<IS> {
type Output = Self;
fn add(
mut self,
rhs: Self,
) -> Self::Output {
self.0 += rhs.0;
self
}
}
impl<IS: InstrumentSpec> Sub for RelativePrice<IS> {
type Output = Result<Self, ()>;
fn sub(
mut self,
rhs: Self,
) -> Self::Output {
self.0 -= rhs.0;
Ok(self)
}
}
impl<IS: InstrumentSpec> From<Price<IS>> for Option<RelativePrice<IS>> {
fn from(value: Price<IS>) -> Self {
let Price::Relative(relative_price) = value else {
return None;
};
Some(relative_price)
}
}
impl<'a, IS: InstrumentSpec> From<&'a Price<IS>> for Option<&'a RelativePrice<IS>> {
fn from(value: &'a Price<IS>) -> Self {
let Price::Relative(relative_price) = value else {
return None;
};
Some(relative_price)
}
}
#[derive(Deref, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct AbsolutePrice<IS: InstrumentSpec>(IS::PriceType);
impl<IS: InstrumentSpec> AbsolutePrice<IS> {
pub fn new(price: IS::PriceType) -> Self {
Self(price)
}
pub fn as_price(&self) -> Price<IS> {
self.into()
}
pub fn into_price(self) -> Price<IS> {
self.into()
}
pub fn as_decimal(&self) -> Decimal {
self.0.as_decimal()
}
pub fn as_underlying(&self) -> IS::PriceType {
self.0
}
pub fn with_const_level_offset<const TICK_OFFSET: i64>(mut self) -> Self {
let decimal_offset = IS::PriceSpec::TICK_VALUE
* Decimal::from_u64(IS::PriceSpec::TICKS_PER_POINT).unwrap()
* Decimal::from_i64(TICK_OFFSET).unwrap();
self.add_decimal(&decimal_offset);
self
}
}
impl<IS: InstrumentSpec> Display for AbsolutePrice<IS> {
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
let price = self.as_decimal();
write!(f, "{}", price)
}
}
impl<IS: InstrumentSpec> Debug for AbsolutePrice<IS> {
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
<Self as Display>::fmt(&self, f)
}
}
impl<IS: InstrumentSpec> Add<RelativePrice<IS>> for AbsolutePrice<IS> {
type Output = Self;
fn add(
mut self,
rhs: RelativePrice<IS>,
) -> Self::Output {
self.0 += rhs.0;
self
}
}
impl<IS: InstrumentSpec> AddDecimal for AbsolutePrice<IS> {
fn add_decimal(
&mut self,
decimal: &Decimal,
) {
self.0.add_decimal(decimal);
}
}
impl<IS: InstrumentSpec> SubDecimal for AbsolutePrice<IS> {
fn sub_decimal(
&mut self,
decimal: &Decimal,
) {
self.0.sub_decimal(decimal);
}
}
impl<IS: InstrumentSpec> From<Price<IS>> for Option<AbsolutePrice<IS>> {
fn from(value: Price<IS>) -> Self {
let Price::Absolute(absolute_price) = value else {
return None;
};
Some(absolute_price)
}
}
impl<'a, IS: InstrumentSpec> From<&'a Price<IS>> for Option<&'a AbsolutePrice<IS>> {
fn from(value: &'a Price<IS>) -> Self {
let Price::Absolute(absolute_price) = value else {
return None;
};
Some(absolute_price)
}
}