architect_api/algo/
spreader.rs1use super::*;
2use crate::{
3 symbology::{ExecutionVenue, MarketdataVenue},
4 AccountIdOrName, Dir, HumanDuration,
5};
6use anyhow::{bail, Result};
7use rust_decimal::Decimal;
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
11pub struct Spreader;
12
13impl Algo for Spreader {
14 const NAME: &'static str = "SPREADER";
15
16 type Params = SpreaderParams;
17 type Status = SpreaderStatus;
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
21pub struct SpreaderParams {
22 pub dir: Dir,
23 pub quantity: Decimal,
24 pub limit_price: Decimal,
25 pub order_lockout: HumanDuration,
26 pub leg1_symbol: String,
27 pub leg1_account: Option<AccountIdOrName>,
28 pub leg1_marketdata_venue: MarketdataVenue,
29 pub leg1_execution_venue: Option<ExecutionVenue>,
30 pub leg1_price_ratio: Decimal,
31 pub leg1_price_offset: Decimal,
32 pub leg1_quantity_ratio: Decimal,
33 pub leg2_symbol: String,
34 pub leg2_account: Option<AccountIdOrName>,
35 pub leg2_marketdata_venue: MarketdataVenue,
36 pub leg2_execution_venue: Option<ExecutionVenue>,
37 pub leg2_price_ratio: Decimal,
38 pub leg2_price_offset: Decimal,
39 pub leg2_quantity_ratio: Decimal,
40}
41
42impl DisplaySymbols for SpreaderParams {
43 fn display_symbols(&self) -> Option<Vec<String>> {
44 Some(vec![self.leg1_symbol.clone(), self.leg2_symbol.clone()])
45 }
46}
47
48impl Validate for SpreaderParams {
49 fn validate(&self) -> Result<()> {
50 if self.leg1_price_ratio.is_zero() {
52 bail!("leg1_price_ratio must not be zero");
53 }
54 if self.leg2_price_ratio.is_zero() {
55 bail!("leg2_price_ratio must not be zero");
56 }
57 if self.leg1_quantity_ratio.is_zero() {
58 bail!("leg1_quantity_ratio must not be zero");
59 }
60 if self.leg2_quantity_ratio.is_zero() {
61 bail!("leg2_quantity_ratio must not be zero");
62 }
63 if !self.quantity.is_sign_positive() {
64 bail!("quantity must be positive");
65 }
66 if self.order_lockout.is_zero() {
67 bail!("order_lockout must not be zero");
68 }
69 Ok(())
70 }
71}
72
73#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
74pub struct SpreaderStatus {
75 pub leg1_fill_quantity: Decimal,
76 pub leg2_fill_quantity: Decimal,
77 pub implied_spread_vwap: Option<Decimal>,
78 pub current_spreader_phase: SpreaderPhase,
79}
80
81#[derive(
82 Debug, Copy, Clone, Serialize, Deserialize, Default, JsonSchema, PartialEq, Eq,
83)]
84pub enum SpreaderPhase {
85 #[default]
86 ScanningForTakes,
87 AwaitingOrderResults,
88 OrderLockout,
89 NoBbo,
90 NotEnoughBboSize,
91 DoneOverfilled,
92 DoneAndFullyHedged,
93 DoneAndGivingUp,
94}