architect_api/algo/
mod.rs

1use crate::{OrderId, TraderIdOrEmail, UserId};
2use anyhow::Result;
3use chrono::{DateTime, Utc};
4use derive::grpc;
5use derive_more::{Display, FromStr};
6use schemars::{JsonSchema, JsonSchema_repr};
7use serde::{de::DeserializeOwned, Deserialize, Serialize};
8use serde_json::value::RawValue;
9use serde_repr::{Deserialize_repr, Serialize_repr};
10use strum::FromRepr;
11pub mod builder;
12pub mod common_params;
13pub mod release_at_time;
14pub mod spreader;
15pub mod twap;
16
17pub trait Algo {
18    const NAME: &'static str;
19
20    type Params: std::fmt::Debug
21        + Clone
22        + Validate
23        + DisplaySymbols
24        + Serialize
25        + DeserializeOwned
26        + JsonSchema
27        + Send
28        + 'static;
29
30    type Status: std::fmt::Debug
31        + Clone
32        + Default
33        + Serialize
34        + DeserializeOwned
35        + JsonSchema;
36}
37
38pub trait DisplaySymbols {
39    fn display_symbols(&self) -> Option<Vec<String>> {
40        None
41    }
42}
43
44impl DisplaySymbols for () {}
45
46#[grpc(package = "json.architect")]
47#[grpc(service = "Algo", name = "create_algo_order", response = "AlgoOrder")]
48#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
49pub struct CreateAlgoOrderRequest {
50    pub algo: String,
51    pub id: Option<OrderId>,
52    pub parent_id: Option<OrderId>,
53    pub trader: Option<TraderIdOrEmail>,
54    pub params: Box<RawValue>,
55}
56
57#[grpc(package = "json.architect")]
58#[grpc(service = "AlgoHelper", name = "_algo_param_types", response = "AlgoParamTypes")]
59#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
60/// this is used to coerce creation of the params in the schema.json
61pub struct AlgoParamTypes {
62    pub spreader: (spreader::SpreaderParams, spreader::SpreaderStatus),
63}
64
65impl CreateAlgoOrderRequest {
66    pub fn builder(algo: impl AsRef<str>) -> builder::CreateAlgoOrderRequestBuilder {
67        builder::CreateAlgoOrderRequestBuilder::new(algo)
68    }
69}
70
71#[grpc(package = "json.architect")]
72#[grpc(service = "Algo", name = "modify_algo_order", response = "AlgoOrder")]
73#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
74pub struct ModifyAlgoOrderRequest {
75    pub algo_order_id: OrderId,
76    pub params: Box<RawValue>,
77}
78
79#[grpc(package = "json.architect")]
80#[grpc(service = "Algo", name = "start_algo", response = "StartAlgoResponse")]
81#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
82pub struct StartAlgoRequest {
83    pub algo_order_id: OrderId,
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
87pub struct StartAlgoResponse {}
88
89#[grpc(package = "json.architect")]
90#[grpc(service = "Algo", name = "pause_algo", response = "PauseAlgoResponse")]
91#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
92pub struct PauseAlgoRequest {
93    pub algo_order_id: OrderId,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
97pub struct PauseAlgoResponse {}
98
99#[grpc(package = "json.architect")]
100#[grpc(service = "Algo", name = "stop_algo", response = "StopAlgoResponse")]
101#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
102pub struct StopAlgoRequest {
103    pub algo_order_id: OrderId,
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
107pub struct StopAlgoResponse {}
108
109/// Get generic algo run status
110#[grpc(package = "json.architect")]
111#[grpc(service = "Algo", name = "algo_order", response = "AlgoOrder")]
112#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
113pub struct AlgoOrderRequest {
114    pub algo_order_id: OrderId,
115}
116
117/// Find all algo orders matching the given criteria.
118///
119/// If limit is not specified, it will default to 100.
120#[grpc(package = "json.architect")]
121#[grpc(service = "Algo", name = "algo_orders", response = "AlgoOrdersResponse")]
122#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
123pub struct AlgoOrdersRequest {
124    pub algo: Option<String>,
125    pub parent_order_id: Option<OrderId>,
126    pub trader: Option<TraderIdOrEmail>,
127    pub display_symbol: Option<String>,
128    pub status: Option<Vec<AlgoOrderStatus>>,
129    pub from_inclusive: Option<DateTime<Utc>>,
130    pub to_exclusive: Option<DateTime<Utc>>,
131    pub limit: Option<u32>,
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
135pub struct AlgoOrdersResponse {
136    pub algo_orders: Vec<AlgoOrder>,
137}
138
139impl Algo for () {
140    const NAME: &'static str = "UNKNOWN";
141
142    type Params = ();
143    type Status = ();
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
147pub struct AlgoOrder {
148    pub algo: String,
149    pub id: OrderId,
150    pub parent_id: Option<OrderId>,
151    pub create_time: DateTime<Utc>,
152    /// If the algo order is stopped, the time at which it was stopped.
153    pub finish_time: Option<DateTime<Utc>>,
154    /// If the algo order is stopped, whether the stop was successful.
155    pub finish_success: Option<bool>,
156    pub status: AlgoOrderStatus,
157    pub status_details: Box<RawValue>,
158    /// If algo order status is rejected, contains the reject reason;
159    /// for algo orders that finished unsuccessfully, contains the error reason.
160    pub reject_or_error_reason: Option<String>,
161    pub display_symbols: Option<Vec<String>>,
162    pub trader: UserId,
163    pub params: Box<RawValue>,
164    /// Progress of the algo, 0.0 to 1.0, if computable
165    pub working_progress: Option<f64>,
166    pub num_sent_orders: u32,
167    pub num_open_orders: u32,
168    pub num_rejects: u32,
169    pub num_errors: u32,
170}
171
172#[derive(
173    Debug,
174    Display,
175    FromStr,
176    FromRepr,
177    Clone,
178    Copy,
179    PartialEq,
180    Eq,
181    Serialize_repr,
182    Deserialize_repr,
183    JsonSchema_repr,
184)]
185#[cfg_attr(feature = "graphql", derive(juniper::GraphQLEnum))]
186#[serde(rename_all = "snake_case")]
187#[repr(u8)]
188pub enum AlgoOrderStatus {
189    // Pending = 0,
190    Working = 1,
191    Rejected = 2,
192    Paused = 63,
193    // Pausing = 64,
194    // Stopping = 128,
195    Stopped = 127, // same as paused but final
196}
197
198impl AlgoOrderStatus {
199    pub fn is_alive(&self) -> bool {
200        matches!(self, AlgoOrderStatus::Working | AlgoOrderStatus::Paused)
201    }
202}
203
204// CR-someday alee: use something more akin to the validator crate
205pub trait Validate {
206    fn validate(&self) -> Result<()> {
207        Ok(())
208    }
209}
210
211impl Validate for () {}
212
213#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
214pub struct AlgoLog {}