1use crate::api_models::{
2 OptionsChainStrikeRow, PortfolioGreeksAggregate, PositionGreeksLeg, PositionWithMetrics,
3 SpanMarginSummary,
4};
5use crate::{Side, WalletAddress};
6use rust_decimal::Decimal;
7use serde::{Deserialize, Serialize};
8use std::fmt;
9use std::str::FromStr;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
13#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
14pub enum CandleResolution {
15 #[serde(rename = "1m")]
16 OneMinute,
17 #[serde(rename = "5m")]
18 FiveMinutes,
19 #[serde(rename = "15m")]
20 FifteenMinutes,
21 #[serde(rename = "1h")]
22 OneHour,
23 #[serde(rename = "4h")]
24 FourHours,
25 #[serde(rename = "1d")]
26 OneDay,
27}
28
29impl CandleResolution {
30 pub fn as_str(self) -> &'static str {
31 match self {
32 Self::OneMinute => "1m",
33 Self::FiveMinutes => "5m",
34 Self::FifteenMinutes => "15m",
35 Self::OneHour => "1h",
36 Self::FourHours => "4h",
37 Self::OneDay => "1d",
38 }
39 }
40
41 pub fn interval_ms(self) -> i64 {
42 match self {
43 Self::OneMinute => 60_000,
44 Self::FiveMinutes => 300_000,
45 Self::FifteenMinutes => 900_000,
46 Self::OneHour => 3_600_000,
47 Self::FourHours => 14_400_000,
48 Self::OneDay => 86_400_000,
49 }
50 }
51}
52
53impl fmt::Display for CandleResolution {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 f.write_str(self.as_str())
56 }
57}
58
59impl FromStr for CandleResolution {
60 type Err = String;
61
62 fn from_str(s: &str) -> Result<Self, Self::Err> {
63 match s {
64 "1m" => Ok(Self::OneMinute),
65 "5m" => Ok(Self::FiveMinutes),
66 "15m" => Ok(Self::FifteenMinutes),
67 "1h" => Ok(Self::OneHour),
68 "4h" => Ok(Self::FourHours),
69 "1d" => Ok(Self::OneDay),
70 _ => Err(format!("Unsupported candle resolution: {}", s)),
71 }
72 }
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct WsOrderRequest {
77 pub price: Decimal,
78 pub size: Decimal,
79 pub symbol: String,
80 pub side: Side,
81 pub tif: crate::TimeInForce,
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct WsOrderMessage {
86 pub order_id: Option<u64>,
87 pub request: WsOrderRequest,
88 pub status: crate::OrderUpdateStatus,
89 pub timestamp: u64,
90 pub reason: Option<String>,
91 pub wallet_address: WalletAddress,
92 #[serde(default = "default_instrument_type")]
93 pub instrument_type: String,
94}
95
96fn default_instrument_type() -> String {
97 "option".to_string()
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
101#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
102#[serde(tag = "type")]
103#[cfg_attr(feature = "asyncapi", derive(asyncapi_rust::ToAsyncApiMessage))]
104pub enum WsMessage {
105 Subscribe {
107 channel: String,
108 #[serde(default, skip_serializing_if = "Option::is_none")]
109 symbols: Option<Vec<String>>,
110 #[serde(default, skip_serializing_if = "Option::is_none")]
111 expiry: Option<String>,
112 #[serde(default, skip_serializing_if = "Option::is_none")]
113 option_type: Option<String>,
114 },
115 Unsubscribe {
117 channel: String,
118 #[serde(default, skip_serializing_if = "Option::is_none")]
119 symbols: Option<Vec<String>>,
120 #[serde(default, skip_serializing_if = "Option::is_none")]
121 expiry: Option<String>,
122 #[serde(default, skip_serializing_if = "Option::is_none")]
123 option_type: Option<String>,
124 },
125 #[cfg_attr(feature = "schemars", schemars(with = "serde_json::Value"))]
127 OrderUpdate(WsOrderMessage),
128 OrderbookUpdate(WsOrderbookUpdate),
130 Fill(WsFillUpdate),
132 Trade(WsTradeUpdate),
134 CandleUpdate(WsCandleUpdate),
136 MarketUpdate(WsMarketUpdate),
138 OptionsChainUpdate(WsOptionsChainUpdate),
140 IndexPriceUpdate(WsIndexPriceUpdate),
142 #[cfg_attr(feature = "schemars", schemars(with = "serde_json::Value"))]
144 PortfolioUpdate(PortfolioUpdate),
145 PositionExpired(WsPositionExpired),
147 LiquidationStateChange(WsLiquidationStateChange),
149 CompetitionUpdate(WsCompetitionUpdate),
151 CompetitionPnlSummary(WsCompetitionPnlSummary),
153 CompetitionFinalStats(WsCompetitionFinalStats),
155 CompetitionRankChange(WsCompetitionRankChange),
157 CompetitionGapUpdate(WsCompetitionGapUpdate),
159 CompetitionFinalStanding(WsCompetitionFinalStanding),
161 Authenticate { wallet: String },
163 Authenticated { wallet: String },
165 Error { message: String },
167 Subscribed { channel: String },
169 Unsubscribed { channel: String },
171 IndicativeMarketData(WsIndicativeMarketData),
173 RfqQuotes(WsRfqQuotes),
175 RfqStatusUpdate(WsRfqStatusUpdate),
177 SubmitRfq {
179 rfq_id: String,
180 legs: Vec<WsRfqLegRequest>,
181 wallet_address: String,
182 nonce: u64,
183 signature: String,
184 },
185 SubmitAutoExecuteRfq {
188 rfq_id: String,
189 legs: Vec<WsRfqLegRequest>,
190 wallet_address: String,
191 limit_price: String,
194 nonce: u64,
195 signature: String,
196 },
197 AcceptRfqQuote {
199 rfq_id: String,
200 quote_id: String,
201 wallet_address: String,
202 nonce: u64,
203 signature: String,
204 },
205 RfqAcceptResult {
207 rfq_id: String,
208 quote_id: String,
209 status: String,
210 fill_id: Option<String>,
211 #[serde(skip, default)]
215 #[cfg_attr(feature = "schemars", schemars(skip))]
216 taker_wallet: Option<WalletAddress>,
217 },
218 PlaceOrder {
220 wallet: String,
221 symbol: String,
222 side: String,
223 size: String,
224 price: String,
225 #[serde(default, skip_serializing_if = "Option::is_none")]
226 tif: Option<String>,
227 #[serde(default, skip_serializing_if = "Option::is_none")]
228 client_id: Option<String>,
229 nonce: u64,
230 signature: String,
231 #[serde(default)]
232 mmp_enabled: Option<bool>,
233 #[serde(default, skip_serializing_if = "Option::is_none")]
234 builder_code_address: Option<String>,
235 },
236 OrderResult(WsOrderResult),
238 #[serde(other)]
239 Other,
240}
241
242#[derive(Debug, Clone, Serialize, Deserialize)]
243#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
244pub struct WsOrderResult {
245 pub order_id: Option<u64>,
246 pub status: String,
247 pub symbol: String,
248 pub side: String,
249 pub price: String,
250 pub size: String,
251 #[serde(skip_serializing_if = "Option::is_none")]
252 pub reason: Option<String>,
253}
254
255#[derive(Debug, Clone, Serialize, Deserialize)]
256#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
257pub struct WsIndicativeMarketData {
258 pub instrument: String,
259 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
260 #[serde(skip_serializing_if = "Option::is_none")]
261 pub best_bid: Option<Decimal>,
262 #[serde(skip_serializing_if = "Option::is_none")]
263 pub bid_iv: Option<f64>,
264 #[serde(skip_serializing_if = "Option::is_none")]
265 pub ask_iv: Option<f64>,
266 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
267 #[serde(skip_serializing_if = "Option::is_none")]
268 pub best_ask: Option<Decimal>,
269 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
270 #[serde(skip_serializing_if = "Option::is_none")]
271 pub indicative_bid_size: Option<Decimal>,
272 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
273 #[serde(skip_serializing_if = "Option::is_none")]
274 pub indicative_ask_size: Option<Decimal>,
275 pub num_providers: u32,
276 pub timestamp: u64,
277}
278
279#[derive(Debug, Clone, Serialize, Deserialize)]
280#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
281pub struct WsRfqQuotes {
282 pub rfq_id: String,
283 pub quotes: Vec<WsRfqQuoteEntry>,
284 pub status: String,
285 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
286 pub taker_wallet: WalletAddress,
287}
288
289#[derive(Debug, Clone, Serialize, Deserialize)]
290#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
291pub struct WsRfqQuoteEntry {
292 pub quote_id: String,
293 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
294 pub net_premium: Decimal,
295 pub expires_at: u64,
296}
297
298#[derive(Debug, Clone, Serialize, Deserialize)]
299#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
300pub struct WsRfqStatusUpdate {
301 pub rfq_id: String,
302 pub status: String,
303 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
304 pub taker_wallet: WalletAddress,
305}
306
307#[derive(Debug, Clone, Serialize, Deserialize)]
308#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
309pub struct WsRfqLegRequest {
310 pub instrument: String,
311 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
312 pub side: Side,
313 pub size: String,
314}
315
316#[derive(Debug, Clone, Serialize, Deserialize)]
317#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
318pub struct WsOrderbookUpdate {
319 pub symbol: String,
320 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
321 pub option_token_address: Option<WalletAddress>,
322 #[cfg_attr(feature = "schemars", schemars(with = "Vec<(String, String)>"))]
323 pub bids: Vec<(Decimal, Decimal)>,
324 #[cfg_attr(feature = "schemars", schemars(with = "Vec<(String, String)>"))]
325 pub asks: Vec<(Decimal, Decimal)>,
326 pub timestamp: i64,
327}
328
329#[derive(Debug, Clone, Serialize, Deserialize)]
330#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
331pub struct WsFillUpdate {
332 pub order_id: i64,
333 pub fill_id: i64,
334 pub symbol: String,
335 pub side: String,
336 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
337 pub price: Decimal,
338 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
339 pub size: Decimal,
340 pub timestamp: i64,
341 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
342 pub wallet_address: WalletAddress,
343 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
344 pub fee: Decimal,
345 pub trade_id: i64,
346 pub is_taker: bool,
347 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
348 pub builder_code_address: Option<WalletAddress>,
349 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
350 pub builder_code_fee: Option<Decimal>,
351 #[serde(default = "default_ws_instrument_type")]
352 pub instrument_type: String,
353}
354
355fn default_ws_instrument_type() -> String {
356 "option".to_string()
357}
358
359#[derive(Debug, Clone, Serialize, Deserialize)]
360#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
361pub struct WsTradeUpdate {
362 pub symbol: String,
363 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
364 pub price: Decimal,
365 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
366 pub size: Decimal,
367 pub side: String,
368 pub timestamp: i64,
369}
370
371#[derive(Debug, Clone, Serialize, Deserialize)]
372#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
373pub struct WsCandleUpdate {
374 pub underlying: String,
375 pub resolution: CandleResolution,
376 pub start_time_ms: i64,
377 pub end_time_ms: i64,
378 pub open: f64,
379 pub high: f64,
380 pub low: f64,
381 pub close: f64,
382 pub volume: f64,
383}
384
385#[derive(Debug, Clone, Serialize, Deserialize)]
386#[serde(tag = "type")]
387pub enum PortfolioUpdate {
388 Initial {
389 positions: Vec<PositionWithMetrics>,
390 timestamp: i64,
391 },
392 PositionUpdate {
393 position: PositionWithMetrics,
394 timestamp: i64,
395 },
396 BalanceUpdate {
397 total_margin_used: Decimal,
398 timestamp: i64,
399 },
400 MarginUpdate {
401 span_margin: SpanMarginSummary,
402 total_margin_used: Decimal,
403 available_balance: Decimal,
404 timestamp: i64,
405 },
406 GreeksUpdate {
407 per_leg: Vec<PositionGreeksLeg>,
408 aggregate: Option<PortfolioGreeksAggregate>,
409 timestamp: i64,
410 },
411}
412
413#[derive(Debug, Clone, Serialize, Deserialize)]
414#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
415pub struct WsPositionExpired {
416 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
417 pub wallet_address: WalletAddress,
418 pub symbol: String,
419 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
420 pub position_size: Decimal,
421 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
422 pub settlement_price: Decimal,
423 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
424 pub settlement_value: Decimal,
425 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
426 pub settlement_entry_price: Option<Decimal>,
427 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
428 pub cost_basis: Option<Decimal>,
429 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
430 pub net_pnl: Option<Decimal>,
431 pub timestamp: i64,
432}
433
434#[derive(Debug, Clone, Serialize, Deserialize)]
435#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
436pub struct WsLiquidationStateChange {
437 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
438 pub wallet_address: WalletAddress,
439 pub previous_state: String,
440 pub new_state: String,
441 pub liquidation_mode: Option<String>,
442 pub margin_mode: String,
443 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
444 pub equity: Decimal,
445 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
446 pub mm_required: Decimal,
447 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
448 pub maintenance_margin: Decimal,
449 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
450 pub shortfall: Decimal,
451 pub partial_liquidation: Option<WsPartialLiquidationState>,
452 pub full_liquidation: Option<WsFullLiquidationState>,
453 pub timestamp: i64,
454}
455
456#[derive(Debug, Clone, Serialize, Deserialize)]
457#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
458pub struct WsPartialLiquidationState {
459 pub entered_at: i64,
460 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
461 pub target_equity: Decimal,
462 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
463 pub mm_shortfall: Decimal,
464 pub escalation_deadline: i64,
465 pub last_reprice_at: Option<i64>,
466 pub active_order_request_ids: Vec<String>,
467 pub active_order_client_ids: Vec<String>,
468 pub bonus_bps: i32,
469 pub pending_full_auction_id: Option<String>,
470 pub pending_full_request_id: Option<String>,
471 pub pending_full_tx_hash: Option<String>,
472 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
473 pub pending_full_margin_needed: Option<Decimal>,
474}
475
476#[derive(Debug, Clone, Serialize, Deserialize)]
477#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
478pub struct WsFullLiquidationState {
479 pub auction_id: Option<String>,
480 pub request_id: Option<String>,
481 pub tx_hash: Option<String>,
482 pub started_at: Option<i64>,
483 pub chain_start_time: Option<i64>,
484 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
485 pub margin_needed: Option<Decimal>,
486 pub stop_request_id: Option<String>,
487 pub stop_tx_hash: Option<String>,
488 pub liquidated_at: Option<i64>,
489 pub winner: Option<String>,
490 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
491 pub bonus: Option<Decimal>,
492 pub resolution_tx_hash: Option<String>,
493}
494
495#[derive(Debug, Clone, Serialize, Deserialize)]
496#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
497pub struct WsCompetitionUpdate {
498 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
499 pub wallet_address: WalletAddress,
500 pub competition_id: i64,
501 pub rank: i64,
502 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
503 pub pnl: Decimal,
504 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
505 pub volume: Decimal,
506 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
507 pub efficiency: Decimal,
508 pub timestamp: i64,
509}
510
511#[derive(Debug, Clone, Serialize, Deserialize)]
512#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
513pub struct WsCompetitionPnlStanding {
514 pub competition_id: i64,
515 pub competition_name: String,
516 pub competition_state: String,
517 pub rank: Option<usize>,
518 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
519 pub pnl: Decimal,
520 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
521 pub volume: Decimal,
522 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
523 pub efficiency: Decimal,
524 pub medal: Option<u8>,
525}
526
527#[derive(Debug, Clone, Serialize, Deserialize)]
528#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
529pub struct WsCompetitionPnlSummary {
530 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
531 pub wallet_address: WalletAddress,
532 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
533 pub lifetime_realized_pnl: Decimal,
534 pub active_competition: Option<WsCompetitionPnlStanding>,
535 pub timestamp: i64,
536}
537
538#[derive(Debug, Clone, Serialize, Deserialize)]
539#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
540pub struct WsCompetitionFinalStats {
541 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
542 pub wallet_address: WalletAddress,
543 pub competition_id: i64,
544 pub rank: i64,
545 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
546 pub pnl: Decimal,
547 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
548 pub volume: Decimal,
549 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
550 pub efficiency: Decimal,
551 pub medal: Option<i64>,
552 pub timestamp: i64,
553}
554
555#[derive(Debug, Clone, Serialize, Deserialize)]
556#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
557pub struct IndexPriceEntry {
558 pub underlying: String,
559 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
560 pub price: Decimal,
561}
562
563#[derive(Debug, Clone, Serialize, Deserialize)]
564#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
565pub struct WsIndexPriceUpdate {
566 pub prices: Vec<IndexPriceEntry>,
567 pub timestamp: i64,
568}
569
570#[derive(Debug, Clone, Serialize, Deserialize)]
571#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
572pub struct WsCompetitionRankChange {
573 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
574 pub wallet_address: WalletAddress,
575 pub competition_id: i64,
576 pub from_rank: i64,
577 pub to_rank: i64,
578 pub delta_places: i64,
579 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
580 pub pnl: Decimal,
581 pub timestamp: i64,
582}
583
584#[derive(Debug, Clone, Serialize, Deserialize)]
585#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
586pub struct WsCompetitionGapUpdate {
587 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
588 pub wallet_address: WalletAddress,
589 pub competition_id: i64,
590 pub rank: i64,
591 pub next_rank: Option<i64>,
592 #[cfg_attr(feature = "schemars", schemars(with = "Option<String>"))]
593 pub gap_metric_value: Option<Decimal>,
594 pub timestamp: i64,
595}
596
597#[derive(Debug, Clone, Serialize, Deserialize)]
598#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
599pub struct WsCompetitionFinalStanding {
600 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
601 pub wallet_address: WalletAddress,
602 pub competition_id: i64,
603 pub rank: i64,
604 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
605 pub pnl: Decimal,
606 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
607 pub volume: Decimal,
608 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
609 pub efficiency: Decimal,
610 pub medal: Option<i64>,
611 pub timestamp: i64,
612}
613
614#[derive(Debug, Clone, Serialize, Deserialize)]
615#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
616#[serde(tag = "action")]
617pub enum WsMarketUpdate {
618 Created {
619 symbol: String,
620 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
621 strike: Decimal,
622 is_call: bool,
623 underlying: String,
624 expiry: u32,
625 timestamp: u64,
626 },
627 Deleted {
628 symbol: String,
629 timestamp: u64,
630 },
631 Expired {
632 symbol: String,
633 #[cfg_attr(feature = "schemars", schemars(with = "String"))]
634 strike: Decimal,
635 is_call: bool,
636 underlying: String,
637 expiry: u32,
638 timestamp: u64,
639 },
640}
641
642#[derive(Debug, Clone, Serialize, Deserialize)]
643#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
644#[serde(tag = "action")]
645#[allow(clippy::large_enum_variant)]
646pub enum WsOptionsChainUpdate {
647 Upsert {
648 currency: String,
649 expiry: u64,
650 row: OptionsChainStrikeRow,
651 timestamp: i64,
652 },
653 Remove {
654 currency: String,
655 expiry: u64,
656 strike: f64,
657 option_type: String,
658 symbol: String,
659 timestamp: i64,
660 },
661}