use super::{Context, Mutations, Reject};
pub trait CheckPreTradeStartPolicy<O, R> {
fn name(&self) -> &'static str;
fn check_pre_trade_start(&self, order: &O) -> Result<(), Reject>;
fn apply_execution_report(&self, report: &R) -> bool;
}
pub trait Policy<O, R> {
fn name(&self) -> &'static str;
fn perform_pre_trade_check(
&self,
ctx: &Context<'_, O>,
mutations: &mut Mutations,
rejects: &mut Vec<Reject>,
);
fn apply_execution_report(&self, report: &R) -> bool;
}
#[cfg(test)]
mod tests {
use crate::core::{
ExecutionReportOperation, FinancialImpact, OrderOperation, WithExecutionReportOperation,
WithFinancialImpact,
};
use crate::param::{Asset, Fee, Pnl, Quantity, Side, TradeAmount};
use crate::pretrade::Reject;
use super::{CheckPreTradeStartPolicy, Context, Mutations, Policy};
struct StartPolicyNoop;
type TestOrder = OrderOperation;
type TestReport = WithExecutionReportOperation<WithFinancialImpact<()>>;
impl CheckPreTradeStartPolicy<TestOrder, TestReport> for StartPolicyNoop {
fn name(&self) -> &'static str {
"StartPolicyNoop"
}
fn check_pre_trade_start(&self, _order: &TestOrder) -> Result<(), Reject> {
Ok(())
}
fn apply_execution_report(&self, _report: &TestReport) -> bool {
false
}
}
struct MainPolicyNoop;
impl Policy<TestOrder, TestReport> for MainPolicyNoop {
fn name(&self) -> &'static str {
"MainPolicyNoop"
}
fn perform_pre_trade_check(
&self,
_ctx: &Context<'_, TestOrder>,
_mutations: &mut Mutations,
_rejects: &mut Vec<Reject>,
) {
}
fn apply_execution_report(&self, _report: &TestReport) -> bool {
false
}
}
#[test]
fn post_trade_hooks_return_false() {
let report = WithExecutionReportOperation {
inner: WithFinancialImpact {
inner: (),
financial_impact: FinancialImpact {
pnl: Pnl::from_str("0").expect("pnl must be valid"),
fee: Fee::ZERO,
},
},
operation: ExecutionReportOperation {
instrument: crate::Instrument::new(
Asset::new("AAPL").expect("asset code must be valid"),
Asset::new("USD").expect("asset code must be valid"),
),
side: Side::Buy,
},
};
assert!(!StartPolicyNoop.apply_execution_report(&report));
assert!(!MainPolicyNoop.apply_execution_report(&report));
}
#[test]
fn required_trait_methods_can_be_invoked_without_side_effects() {
let order = OrderOperation {
instrument: crate::Instrument::new(
Asset::new("AAPL").expect("asset code must be valid"),
Asset::new("USD").expect("asset code must be valid"),
),
side: Side::Buy,
trade_amount: TradeAmount::Quantity(
Quantity::from_str("1").expect("quantity must be valid"),
),
price: None,
};
let ctx = Context::new(&order);
let mut mutations = Mutations::new();
let mut rejects = Vec::new();
assert_eq!(StartPolicyNoop.name(), "StartPolicyNoop");
assert!(StartPolicyNoop.check_pre_trade_start(&order).is_ok());
assert_eq!(MainPolicyNoop.name(), "MainPolicyNoop");
MainPolicyNoop.perform_pre_trade_check(&ctx, &mut mutations, &mut rejects);
assert!(mutations.as_slice().is_empty());
assert!(rejects.is_empty());
}
}