architect_api/cpty/
kalshi.rs

1use crate::{folio::FolioMessage, orderflow::*, MaybeSecret, OrderId};
2use chrono::{DateTime, Utc};
3#[cfg(feature = "netidx")]
4use derive::FromValue;
5#[cfg(feature = "netidx")]
6use netidx_derive::Pack;
7use rust_decimal::Decimal;
8use schemars::JsonSchema;
9use serde_derive::{Deserialize, Serialize};
10use std::ops::Deref;
11
12#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
13pub struct KalshiCredentials {
14    /// API key UUID from Kalshi
15    pub api_key: String,
16    /// PEM encoded RSA private key from Kalshi
17    pub api_private_key: MaybeSecret<String>,
18}
19
20#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema)]
21#[cfg_attr(feature = "netidx", derive(Pack))]
22pub struct KalshiOrder {
23    #[serde(flatten)]
24    pub order: Order,
25}
26
27impl Deref for KalshiOrder {
28    type Target = Order;
29
30    fn deref(&self) -> &Self::Target {
31        &self.order
32    }
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
36#[cfg_attr(feature = "netidx", derive(Pack))]
37pub struct KalshiTrade {
38    pub order_id: OrderId,
39    pub exec_id: String,
40    pub scaled_price: i64,
41    pub qty: Decimal,
42    pub time: DateTime<Utc>,
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema)]
46#[cfg_attr(feature = "netidx", derive(Pack))]
47pub enum KalshiOrderStatus {
48    Canceled,
49    Executed,
50    Resting,
51    Pending,
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
55#[cfg_attr(feature = "netidx", derive(Pack))]
56pub struct KalshiOrderState {
57    pub internal_order_id: OrderId,
58    pub last_update_time: Option<DateTime<Utc>>,
59    pub status: KalshiOrderStatus,
60    pub fills: Vec<Result<Fill, AberrantFill>>,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
64#[cfg_attr(feature = "netidx", derive(Pack))]
65#[cfg_attr(feature = "netidx", derive(FromValue))]
66pub enum KalshiMessage {
67    Order(KalshiOrder),
68    Cancel(Cancel),
69    CancelAll,
70    Ack(Ack),
71    Out(Out),
72    Fill(Result<Fill, AberrantFill>),
73    Reject(Reject),
74    Folio(FolioMessage),
75    PollOrders,
76    ExchangeAck { order_id: OrderId, kalshi_order_id: String },
77    ExchangeOrderState(KalshiOrderState),
78}
79
80impl TryInto<OrderflowMessage> for &KalshiMessage {
81    type Error = ();
82
83    fn try_into(self) -> Result<OrderflowMessage, ()> {
84        match self {
85            KalshiMessage::Order(o) => Ok(OrderflowMessage::Order(**o)),
86            KalshiMessage::Cancel(c) => Ok(OrderflowMessage::Cancel(*c)),
87            KalshiMessage::CancelAll => {
88                Ok(OrderflowMessage::CancelAll(CancelAll { venue_id: None }))
89            }
90            KalshiMessage::Ack(a) => Ok(OrderflowMessage::Ack(*a)),
91            KalshiMessage::Out(o) => Ok(OrderflowMessage::Out(*o)),
92            KalshiMessage::Fill(f) => Ok(OrderflowMessage::Fill(*f)),
93            KalshiMessage::Reject(r) => Ok(OrderflowMessage::Reject(r.clone())),
94            KalshiMessage::Folio(_)
95            | KalshiMessage::PollOrders
96            | KalshiMessage::ExchangeAck { .. }
97            | KalshiMessage::ExchangeOrderState(_) => Err(()),
98        }
99    }
100}
101
102impl TryInto<KalshiMessage> for &OrderflowMessage {
103    type Error = ();
104
105    fn try_into(self) -> Result<KalshiMessage, ()> {
106        match self {
107            OrderflowMessage::Order(o) => {
108                Ok(KalshiMessage::Order(KalshiOrder { order: *o }))
109            }
110            OrderflowMessage::Cancel(c) => Ok(KalshiMessage::Cancel(*c)),
111            OrderflowMessage::CancelAll(_) => Ok(KalshiMessage::CancelAll),
112            OrderflowMessage::Ack(a) => Ok(KalshiMessage::Ack(*a)),
113            OrderflowMessage::Out(o) => Ok(KalshiMessage::Out(*o)),
114            OrderflowMessage::Reject(r) => Ok(KalshiMessage::Reject(r.clone())),
115            OrderflowMessage::Fill(f) => Ok(KalshiMessage::Fill(*f)),
116        }
117    }
118}
119
120impl TryInto<FolioMessage> for &KalshiMessage {
121    type Error = ();
122
123    fn try_into(self) -> Result<FolioMessage, ()> {
124        match self {
125            KalshiMessage::Folio(f) => Ok(f.clone()),
126            _ => Err(()),
127        }
128    }
129}
130
131impl TryFrom<&FolioMessage> for KalshiMessage {
132    type Error = ();
133
134    fn try_from(f: &FolioMessage) -> Result<Self, ()> {
135        Ok(Self::Folio(f.clone()))
136    }
137}