use crate::param::{Asset, PositionSize};
use crate::pretrade::policy::{field_access_error_account_adjustment_reject, PolicyName};
use crate::pretrade::{AccountBlock, Reject, RejectCode, RejectScope, Rejects};
use crate::PnlHaltReason;
pub(super) fn account_pnl_barrier_currency_mismatch_block(
account_currency: Option<&Asset>,
barrier: &super::SpotFundsPnlBoundsBarrier,
) -> Option<AccountBlock> {
let account_currency = account_currency.filter(|currency| *currency != &barrier.currency)?;
Some(
super::super::pnl_bounds::pnl_barrier_currency_mismatch_account_block(
super::SPOT_FUNDS_POLICY_NAME,
format!(
"account currency {account_currency}, barrier currency {}",
barrier.currency,
),
),
)
}
pub(super) fn account_pnl_block_for_state(
account_currency: Option<&Asset>,
state: crate::PnlState,
barrier: &super::SpotFundsPnlBoundsBarrier,
provenance: Option<u64>,
) -> Option<AccountBlock> {
if let Some(block) = account_pnl_barrier_currency_mismatch_block(account_currency, barrier) {
return Some(block);
}
let block = match state {
crate::PnlState::Value(absolute) => {
let sides = super::super::pnl_bounds::breached_sides(
barrier.lower_bound,
barrier.upper_bound,
absolute,
);
(!sides.is_empty()).then(|| {
super::super::pnl_bounds::pnl_breach_account_block(
super::SPOT_FUNDS_POLICY_NAME,
super::super::pnl_bounds::barrier_breach_details(
&sides,
barrier.lower_bound,
barrier.upper_bound,
absolute,
"currency",
&barrier.currency,
),
)
})
}
crate::PnlState::Halted(reason) => Some(account_pnl_halted_block(
super::SPOT_FUNDS_POLICY_NAME,
reason,
)),
};
block.map(|block| block.with_provenance(provenance))
}
pub(super) fn insufficient_funds_reject(
policy: &str,
asset: &Asset,
available: PositionSize,
requested: PositionSize,
) -> Reject {
Reject::new(
policy,
RejectScope::Order,
RejectCode::InsufficientFunds,
"spot funds insufficient",
format!("asset {asset}: available {available}, requested {requested}"),
)
}
pub(super) fn adj_field<P: PolicyName + ?Sized, T>(
policy: &P,
name: &str,
result: Result<T, crate::RequestFieldAccessError>,
) -> Result<T, Rejects> {
result.map_err(|e| {
Rejects::from(field_access_error_account_adjustment_reject(
policy, name, &e,
))
})
}
pub(super) fn order_value_calculation_failed_reject(
policy: &str,
details: impl Into<String>,
) -> Reject {
Reject::new(
policy,
RejectScope::Order,
RejectCode::OrderValueCalculationFailed,
"order value calculation failed",
details.into(),
)
}
pub(super) fn account_pnl_halted_block(policy: &str, reason: PnlHaltReason) -> AccountBlock {
AccountBlock::new(
policy,
RejectCode::PnlKillSwitchTriggered,
"account pnl calculation halted",
format!("halt reason {reason:?}"),
)
}
pub(super) fn arithmetic_overflow_reject(
policy: &str,
scope: RejectScope,
details: impl Into<String>,
) -> Reject {
Reject::new(
policy,
scope,
RejectCode::ArithmeticOverflow,
"arithmetic overflow",
details.into(),
)
}
pub(super) fn arithmetic_overflow_account_block(
policy: &str,
details: impl Into<String>,
) -> AccountBlock {
AccountBlock::new(
policy,
RejectCode::ArithmeticOverflow,
"arithmetic overflow",
details.into(),
)
}
pub(super) fn account_adjustment_bounds_exceeded_reject(
policy: &str,
asset: &Asset,
field: &str,
actual: PositionSize,
lower: Option<PositionSize>,
upper: Option<PositionSize>,
) -> Reject {
Reject::new(
policy,
RejectScope::Account,
RejectCode::AccountAdjustmentBoundsExceeded,
"account adjustment bounds exceeded",
format!(
"asset {asset}: {field} {actual}, \
lower {lower:?}, upper {upper:?}"
),
)
}