architect_api/algo/
twap.rs

1use super::*;
2use crate::{symbology::ExecutionVenue, Dir, HumanDuration};
3use anyhow::{bail, Result};
4use chrono::{DateTime, Utc};
5use derive::grpc;
6use rust_decimal::Decimal;
7use rust_decimal_macros::dec;
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
11pub struct TwapAlgo;
12
13impl Algo for TwapAlgo {
14    type Params = TwapParams;
15    type Status = TwapStatus;
16}
17
18pub type TwapAlgoOrder = AlgoOrder<TwapAlgo>;
19
20#[grpc(package = "json.architect")]
21#[grpc(service = "Algo", name = "create_twap_algo_order", response = "TwapAlgoOrder")]
22pub type CreateTwapAlgoOrderRequest = CreateAlgoOrderRequest<TwapAlgo>;
23
24#[grpc(package = "json.architect")]
25#[grpc(service = "Algo", name = "modify_twap_algo_order", response = "TwapAlgoOrder")]
26pub type ModifyTwapAlgoOrderRequest = ModifyAlgoOrderRequest<TwapAlgo>;
27
28#[grpc(package = "json.architect")]
29#[grpc(service = "Algo", name = "twap_algo_order", response = "TwapAlgoOrder")]
30pub type TwapAlgoOrderRequest = AlgoOrderRequest;
31
32#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
33pub struct TwapParams {
34    pub symbol: String,
35    pub execution_venue: ExecutionVenue,
36    pub dir: Dir,
37    pub quantity: Decimal,
38    pub interval: HumanDuration,
39    pub end_time: DateTime<Utc>,
40    pub reject_lockout: HumanDuration,
41    pub take_through_frac: Option<Decimal>,
42}
43
44impl Validate for TwapParams {
45    fn validate(&self) -> Result<()> {
46        if !self.quantity.is_sign_positive() {
47            bail!("quantity must be positive");
48        }
49        if self.interval.num_milliseconds() < 100 {
50            bail!("interval must be >= 100ms");
51        }
52        if self.reject_lockout.num_milliseconds() < 500
53            || self.reject_lockout.num_seconds() > 300
54        {
55            bail!("reject lockout must be between 0.5 seconds and 300 seconds");
56        }
57        if let Some(take_through_frac) = self.take_through_frac {
58            if take_through_frac.is_sign_negative() || take_through_frac > dec!(0.05) {
59                bail!("take_through_frac must be between 0 and 5%");
60            }
61        }
62        Ok(())
63    }
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
67pub struct TwapStatus {
68    pub realized_twap: Option<Decimal>,
69    pub quantity_filled: Decimal,
70}