use std::borrow::Borrow;
use std::cmp;
use apple_quant_core::{
log::error, AddChecked, AddReleaseUnchecked, AddUnchecked, SubChecked,
SubReleaseUnchecked, SubUnchecked,
};
use num_traits::{Signed, Zero};
use crate::{
instrument::{AsDecimal, InstrumentSpec},
points::{Subpoints, WholePoints},
};
use super::{
AggressiveVolume, DirectionalIntent, DirectionlessVolume, FromVolumeType,
FromVolumeTypeError, RestingVolume, VolumeConstruct, ZeroableVolume,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct DirectionalIntentVolume<IS: InstrumentSpec> {
pub directional_intent: DirectionalIntent,
pub directionless_volume: DirectionlessVolume<IS>,
}
impl<IS: InstrumentSpec> DirectionalIntentVolume<IS> {
pub fn from_volume_type_positive_unchecked(
volume_type: IS::VolumeType,
) -> Self {
debug_assert!(volume_type.is_positive() || volume_type.is_zero());
Self {
directional_intent: DirectionalIntent::Positive,
directionless_volume: DirectionlessVolume::<IS>::new_unchecked(volume_type),
}
}
pub fn from_volume_type_negative_unchecked(
volume_type: IS::VolumeType,
) -> Self {
debug_assert!(volume_type.is_positive() || volume_type.is_zero());
Self {
directional_intent: DirectionalIntent::Negative,
directionless_volume: DirectionlessVolume::<IS>::new_unchecked(volume_type),
}
}
pub fn as_flipped(
&self,
) -> Self {
Self {
directional_intent: self.directional_intent.as_flipped(),
directionless_volume: self.directionless_volume,
}
}
pub fn as_volume_type_signed(
&self,
) -> IS::VolumeType {
let volume_type = self.directionless_volume.as_volume_type();
debug_assert!(volume_type.is_positive() || volume_type.is_zero());
if self.directional_intent.is_positive() {
return volume_type;
} else {
return -volume_type;
}
}
}
impl<IS: InstrumentSpec> VolumeConstruct<
(
DirectionalIntent,
DirectionlessVolume<IS>,
),
(),
> for DirectionalIntentVolume<IS> {
fn new_checked(
t: impl Into<(
DirectionalIntent,
DirectionlessVolume<IS>,
)>,
) -> Result<Self, ()>
where
Self: Sized,
{
Ok(Self::new_unchecked(t))
}
fn new_unchecked(
t: impl Into<(
DirectionalIntent,
DirectionlessVolume<IS>,
)>,
) -> Self {
let (
directional_intent,
directionless_volume,
) = t.into();
Self {
directional_intent,
directionless_volume,
}
}
}
impl<IS: InstrumentSpec> FromVolumeType<IS> for DirectionalIntentVolume<IS> {
fn from_volume_type_checked(
volume_type: impl Into<IS::VolumeType>,
) -> Result<Self, FromVolumeTypeError>
where
Self: Sized,
{
let volume_type = volume_type.into();
if volume_type.is_zero() {
return Err(FromVolumeTypeError::new(volume_type.as_decimal()));
}
Ok(Self::from_volume_type_unchecked(volume_type))
}
fn from_volume_type_unchecked(
volume_type: impl Into<IS::VolumeType>,
) -> Self {
let volume_type = volume_type.into();
if volume_type.is_positive() {
return Self::from_volume_type_positive_unchecked(volume_type);
}
Self::from_volume_type_negative_unchecked(volume_type.abs())
}
}
impl<IS: InstrumentSpec> ZeroableVolume for DirectionalIntentVolume<IS> {
const ZERO: Self = DirectionalIntentVolume {
directional_intent: DirectionalIntent::Positive,
directionless_volume: DirectionlessVolume::ZERO,
};
fn is_zero(
&self,
) -> bool {
self.directionless_volume == DirectionlessVolume::ZERO
}
}
impl<IS: InstrumentSpec> From<AggressiveVolume<IS>> for DirectionalIntentVolume<IS> {
fn from(
value: AggressiveVolume<IS>,
) -> Self {
let directional_intent = value.as_aggressor_side().into();
let directionless_volume = value.into_directionless_volume();
Self {
directional_intent,
directionless_volume,
}
}
}
impl<IS: InstrumentSpec> From<&AggressiveVolume<IS>> for DirectionalIntentVolume<IS> {
fn from(
value: &AggressiveVolume<IS>,
) -> Self {
Self::from(*value)
}
}
impl<IS: InstrumentSpec> From<RestingVolume<IS>> for DirectionalIntentVolume<IS> {
fn from(
value: RestingVolume<IS>,
) -> Self {
let directional_intent = value.as_resting_side().into();
let directionless_volume = value.into_directionless_volume();
Self {
directional_intent,
directionless_volume,
}
}
}
impl<IS: InstrumentSpec> From<&RestingVolume<IS>> for DirectionalIntentVolume<IS> {
fn from(
value: &RestingVolume<IS>,
) -> Self {
Self::from(*value)
}
}
impl<IS: InstrumentSpec> PartialOrd for DirectionalIntentVolume<IS> {
fn partial_cmp(
&self,
other: &Self,
) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<IS: InstrumentSpec> Ord for DirectionalIntentVolume<IS> {
fn cmp(
&self,
other: &Self,
) -> cmp::Ordering {
let lhs = self.as_volume_type_signed();
let rhs = other.as_volume_type_signed();
lhs.cmp(&rhs)
}
}
impl<IS: InstrumentSpec> From<WholePoints> for DirectionalIntentVolume<IS> {
fn from(
value: WholePoints,
) -> Self {
match Self::from_volume_type_unchecked_release(
value.into_subpoints::<IS::VolumeSpec>(),
) {
Ok(
directional_intent_volume,
) => directional_intent_volume,
Err(e) => {
error!("{e}");
panic!();
},
}
}
}
impl<IS: InstrumentSpec> From<&WholePoints> for DirectionalIntentVolume<IS> {
fn from(
value: &WholePoints,
) -> Self {
(*value).into()
}
}
impl<IS: InstrumentSpec> From<Subpoints> for DirectionalIntentVolume<IS> {
fn from(
value: Subpoints,
) -> Self {
match Self::from_volume_type_unchecked_release(value) {
Ok(
directional_intent_volume,
) => directional_intent_volume,
Err(e) => {
error!("{e}");
panic!();
},
}
}
}
impl<IS: InstrumentSpec> From<&Subpoints> for DirectionalIntentVolume<IS> {
fn from(
value: &Subpoints,
) -> Self {
(*value).into()
}
}
impl<IS: InstrumentSpec> From<DirectionalIntentVolume<IS>> for Result<
DirectionalIntentVolume<IS>,
FromVolumeTypeError,
> {
fn from(
value: DirectionalIntentVolume<IS>,
) -> Self {
Ok(value)
}
}
impl_volume_binop!(
DirectionalIntentVolume,
AddReleaseUnchecked,
AddChecked,
add_checked,
AddUnchecked,
add_unchecked,
|lhs: DirectionalIntentVolume<IS>, rhs: DirectionalIntentVolume<IS>| { let lhs =
lhs.as_volume_type_signed(); let rhs = rhs.as_volume_type_signed(); let volume_type =
lhs + rhs; DirectionalIntentVolume::<IS>::from_volume_type_checked(volume_type) },
|lhs: DirectionalIntentVolume<IS>, rhs: DirectionalIntentVolume<IS>| { let lhs =
lhs.as_volume_type_signed(); let rhs = rhs.as_volume_type_signed(); let volume_type =
lhs + rhs; DirectionalIntentVolume::<IS>::from_volume_type_unchecked(volume_type) },
FromVolumeTypeError,
IS,
InstrumentSpec
);
impl_volume_binop!(
DirectionalIntentVolume,
SubReleaseUnchecked,
SubChecked,
sub_checked,
SubUnchecked,
sub_unchecked,
|lhs: DirectionalIntentVolume<IS>, rhs: DirectionalIntentVolume<IS>| { let lhs =
lhs.as_volume_type_signed(); let rhs = rhs.as_volume_type_signed(); let volume_type =
lhs - rhs; DirectionalIntentVolume::<IS>::from_volume_type_checked(volume_type) },
|lhs: DirectionalIntentVolume<IS>, rhs: DirectionalIntentVolume<IS>| { let lhs =
lhs.as_volume_type_signed(); let rhs = rhs.as_volume_type_signed(); let volume_type =
lhs - rhs; DirectionalIntentVolume::<IS>::from_volume_type_unchecked(volume_type) },
FromVolumeTypeError,
IS,
InstrumentSpec
);