etrade 0.6.0

Wraps the etrade API and implements the oauth flows
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
use crate::{accounts::QuoteStatus, empty_body, qs_params, session::CallbackProvider, Messages};
use crate::{Product, Session, Store};
use anyhow::Result;
use http::Method;
use std::sync::Arc;
use strum::EnumString;

pub struct Api<T: Store> {
  session: Arc<Session<T>>,
}

impl<T> Api<T>
where
  T: Store,
{
  pub fn new(session: Arc<Session<T>>) -> Self {
    Self { session }
  }

  pub async fn quotes(
    &self,
    symbols: &str,
    params: GetQuotesRequest,
    callbacks: impl CallbackProvider,
  ) -> Result<QuoteResponse> {
    let quotes: serde_json::Value = self
      .session
      .send(
        Method::GET,
        format!("/v1/market/quote/{}", symbols),
        qs_params(&params)?,
        callbacks,
      )
      .await?;
    debug!("quotes json: {}", serde_json::to_string_pretty(&quotes)?);
    Ok(serde_json::from_value(quotes.get("QuoteResponse").unwrap().clone())?)
  }

  pub async fn product(&self, search: &str, callbacks: impl CallbackProvider) -> Result<LookupResponse> {
    let product: serde_json::Value = self
      .session
      .send(
        Method::GET,
        format!("/v1/market/quote/{}", search),
        empty_body(),
        callbacks,
      )
      .await?;
    debug!("product json: {}", serde_json::to_string_pretty(&product)?);
    Ok(serde_json::from_value(product.get("LookupResponse").unwrap().clone())?)
  }

  pub async fn chains<'a>(
    &self,
    params: &'a GetOptionChainsRequest<'a>,
    callbacks: impl CallbackProvider,
  ) -> Result<OptionChainResponse> {
    let chains: serde_json::Value = self
      .session
      .send(
        Method::GET,
        "/v1/market/quote/optionchains",
        qs_params(params)?,
        callbacks,
      )
      .await?;
    debug!("chains json: {}", serde_json::to_string_pretty(&chains)?);
    Ok(serde_json::from_value(
      chains.get("OptionChainResponse").unwrap().clone(),
    )?)
  }

  pub async fn expire_dates<'a>(
    &self,
    params: &'a GetOptionExpireDatesRequest<'a>,
    callbacks: impl CallbackProvider,
  ) -> Result<OptionExpireDateResponse> {
    let dates: serde_json::Value = self
      .session
      .send(
        Method::GET,
        "/v1/market/quote/optionexpiredate",
        qs_params(params)?,
        callbacks,
      )
      .await?;
    debug!("dates json: {}", serde_json::to_string_pretty(&dates)?);
    Ok(serde_json::from_value(
      dates.get("OptionExpireDateResponse").unwrap().clone(),
    )?)
  }
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct GetOptionExpireDatesRequest<'a> {
  pub expiry_type: Option<ExpiryType>,
  pub symbol: &'a str,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct OptionExpireDateResponse {
  #[serde(rename = "ExpirationDate", skip_serializing_if = "Vec::is_empty")]
  pub expiration_dates: Vec<ExpirationDate>,
}

#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct ExpirationDate {
  pub year: i32,
  pub month: i32,
  pub day: i32,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub expiry_type: Option<ExpiryType>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase", default)]
pub struct GetOptionChainsRequest<'a> {
  pub symbol: &'a str,
  pub expiry_year: Option<usize>,
  pub expiry_month: Option<usize>,
  pub expiry_day: Option<usize>,
  pub strike_price_near: Option<f64>,
  pub no_of_strikes: Option<f64>,
  pub include_weekly: bool,
  pub skip_adjusted: bool,
}

impl<'a> Default for GetOptionChainsRequest<'a> {
  fn default() -> Self {
    Self {
      symbol: "",
      expiry_year: None,
      expiry_month: None,
      expiry_day: None,
      strike_price_near: None,
      no_of_strikes: None,
      include_weekly: false,
      skip_adjusted: true,
    }
  }
}

#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct OptionChainResponse {
  #[serde(rename = "OptionPair", skip_serializing_if = "Vec::is_empty")]
  pub option_pairs: Vec<OptionChainPair>,
  pub time_stamp: i64,
  pub quote_type: String,
  pub near_price: f64,
  #[serde(rename = "SelectedED", skip_serializing_if = "Option::is_none")]
  pub selected: Option<SelectedED>,
}

#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct OptionChainPair {
  #[serde(rename = "Call", skip_serializing_if = "Option::is_none")]
  pub call: Option<OptionDetails>,
  #[serde(rename = "Put", skip_serializing_if = "Option::is_none")]
  pub put: Option<OptionDetails>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub pair_type: Option<PairType>,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct OptionDetails {
  #[serde(skip_serializing_if = "Option::is_none")]
  pub option_category: Option<OptionCategory>,
  pub option_root_symbol: String,
  pub time_stamp: i64,
  pub adjusted_flag: bool,
  pub display_symbol: String,
  pub option_type: String,
  pub strike_price: f64,
  pub symbol: String,
  pub bid: f64,
  pub ask: f64,
  pub bid_size: i64,
  pub ask_size: i64,
  pub in_the_money: String,
  pub volume: i64,
  pub open_interest: i64,
  pub net_change: f64,
  pub last_price: f64,
  pub quote_detail: String,
  pub osi_key: String,
  #[serde(rename = "OptionGreeks", skip_serializing_if = "Option::is_none")]
  pub option_greeks: Option<OptionGreeks>,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct SelectedED {
  pub month: i32,
  pub year: i32,
  pub day: i32,
}

#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct LookupResponse {
  #[serde(rename = "Data", skip_serializing_if = "Vec::is_empty")]
  pub data: Vec<Data>,
}

#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct Data {
  pub symbol: String,
  pub description: String,
  #[serde(rename = "type")]
  pub symbol_type: String,
}

#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct GetQuotesRequest {
  pub detail_flag: Option<DetailFlag>,
  pub require_earnings_date: Option<bool>,
  pub override_symbol_count: Option<bool>,
  pub skip_mini_options_check: Option<bool>,
}

#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct QuoteResponse {
  #[serde(skip_serializing_if = "Vec::is_empty")]
  pub quote_data: Vec<QuoteData>,
  #[serde(skip_serializing_if = "Messages::is_empty")]
  pub message_list: Messages,
}

#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct QuoteData {
  #[serde(rename = "All", skip_serializing_if = "Option::is_none")]
  pub all: Option<AllQuoteDetails>,
  pub date_time: String,
  #[serde(rename = "dateTimeUTC")]
  pub date_time_utc: i64,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub quote_status: Option<QuoteStatus>,
  pub ah_flags: String,
  pub error_message: String,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub fundamental: Option<FundamentalQuoteDetails>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub intraday: Option<IntraQuoteDetails>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub option: Option<OptionQuoteDetails>,
  #[serde(rename = "Product", skip_serializing_if = "Option::is_none")]
  pub product: Option<Product>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub week52: Option<Week52QuoteDetails>,
  #[serde(rename = "MutualFund", skip_serializing_if = "Option::is_none")]
  pub mutual_fund: Option<MutualFund>,
  pub time_zone: String,
  pub dst_flag: bool,
  pub has_mini_options: bool,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct MutualFund {
  pub symbol_description: String,
  pub cusip: String,
  pub change_close: f64,
  pub previous_close: f64,
  pub transaction_fee: f64,
  pub early_redemption_fee: String,
  pub availability: String,
  pub initial_investment: f64,
  pub subsequent_investment: f64,
  pub fund_family: String,
  pub fund_name: String,
  pub change_close_percentage: f64,
  pub time_of_last_trade: i64,
  pub net_asset_value: f64,
  pub public_offer_price: f64,
  pub net_expense_ratio: f64,
  pub gross_expense_ratio: f64,
  pub order_cutoff_time: i64,
  pub sales_charge: String,
  pub initial_ira_investment: f64,
  pub subsequent_ira_investment: f64,
  pub net_assets: NetAsset,
  pub fund_inception_date: i64,
  pub average_annual_returns: f64,
  pub seven_day_current_yield: f64,
  pub annual_total_return: f64,
  pub weighted_average_maturity: f64,
  pub average_annual_returns_1_yr: f64,
  pub average_annual_returns_3_yr: f64,
  pub average_annual_returns_5_yr: f64,
  pub average_annual_returns_10_yr: f64,
  pub high52: f64,
  pub low52: f64,
  pub week_52_low_date: i64,
  pub week_52_hi_date: i64,
  pub exchange_name: String,
  pub since_inception: f64,
  pub quarterly_since_inception: f64,
  pub last_trade: f64,
  #[serde(rename = "actual12B1Fee")]
  pub actual_12b1_fee: f64,
  pub performance_as_of_date: String,
  pub qtrly_performance_as_of_date: String,
  pub redemption: Redemption,
  pub morning_star_category: String,
  #[serde(rename = "monthlyTrailingReturn1Y")]
  pub monthly_trailing_return_1y: f64,
  #[serde(rename = "monthlyTrailingReturn3Y")]
  pub monthly_trailing_return_3y: f64,
  #[serde(rename = "monthlyTrailingReturn5Y")]
  pub monthly_trailing_return_5y: f64,
  #[serde(rename = "monthlyTrailingReturn10Y")]
  pub monthly_trailing_return_10y: f64,
  pub etrade_early_redemption_fee: String,
  pub max_sales_load: f64,
  #[serde(rename = "monthlyTrailingReturnYTD")]
  pub monthly_trailing_return_ytd: f64,
  #[serde(rename = "monthlyTrailingReturn1M")]
  pub monthly_trailing_return_1m: f64,
  #[serde(rename = "monthlyTrailingReturn3M")]
  pub monthly_trailing_return_3m: f64,
  #[serde(rename = "monthlyTrailingReturn6M")]
  pub monthly_trailing_return_6m: f64,
  #[serde(rename = "qtrlyTrailingReturnYTD")]
  pub qtrly_trailing_return_ytd: f64,
  #[serde(rename = "qtrlyTrailingReturn1M")]
  pub qtrly_trailing_return_1m: f64,
  #[serde(rename = "qtrlyTrailingReturn3M")]
  pub qtrly_trailing_return_3m: f64,
  #[serde(rename = "qtrlyTrailingReturn6M")]
  pub qtrly_trailing_return_6m: f64,
  #[serde(skip_serializing_if = "Vec::is_empty")]
  pub deferred_sales_changes: Vec<SaleChargeValues>,
  #[serde(skip_serializing_if = "Vec::is_empty")]
  pub frontend_sales_changes: Vec<SaleChargeValues>,
  pub exchange_code: String,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct Redemption {
  pub min_month: String,
  pub fee_percent: String,
  pub is_front_end: String,
  #[serde(skip_serializing_if = "Vec::is_empty")]
  pub front_end_values: Vec<Values>,
  pub redemption_duration_type: String,
  pub is_sales: String,
  pub sales_duration_type: String,
  #[serde(skip_serializing_if = "Vec::is_empty")]
  pub sales_values: Vec<Values>,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct Values {
  pub low: String,
  pub high: String,
  pub percent: String,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct SaleChargeValues {
  pub lowhigh: String,
  pub percent: String,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct NetAsset {
  pub value: f64,
  pub as_of_date: i64,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct Week52QuoteDetails {
  pub annual_dividend: f64,
  pub company_name: String,
  pub high52: f64,
  pub last_trade: f64,
  pub low52: f64,
  pub perf_12_months: f64,
  pub previous_close: f64,
  pub symbol_description: String,
  pub total_volume: i64,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct OptionQuoteDetails {
  pub ask: f64,
  pub ask_size: i64,
  pub bid: f64,
  pub bid_size: i64,
  pub company_name: String,
  pub days_to_expiration: i64,
  pub last_trade: f64,
  pub open_interest: i64,
  pub option_previous_bid_price: f64,
  pub option_previous_ask_price: f64,
  pub osi_key: String,
  pub intrinsic_value: f64,
  pub time_premium: f64,
  pub option_multiplier: f64,
  pub contract_size: f64,
  pub symbol_description: String,
  #[serde(rename = "OptionGreeks", skip_serializing_if = "Option::is_none")]
  pub option_greeks: Option<OptionGreeks>,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct OptionGreeks {
  pub rho: f64,
  pub vega: f64,
  pub theta: f64,
  pub delta: f64,
  pub gamma: f64,
  pub iv: f64,
  pub current_value: bool,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct IntraQuoteDetails {
  pub ask: f64,
  pub bid: f64,
  pub change_close: f64,
  pub change_close_percentage: f64,
  pub company_name: String,
  pub high: f64,
  pub last_trade: f64,
  pub low: f64,
  pub total_volume: i64,
}

#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct FundamentalQuoteDetails {
  pub company_name: String,
  pub eps: f64,
  pub est_earnings: f64,
  pub high52: f64,
  pub last_trade: f64,
  pub low52: f64,
  pub symbol_description: String,
  pub volume_10_day: i64,
}

#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct AllQuoteDetails {
  pub adjusted_flag: bool,
  pub annual_dividend: f64,
  pub ask: f64,
  pub ask_exchange: String,
  pub ask_size: i64,
  pub ask_time: String,
  pub bid: f64,
  pub bid_exchange: String,
  pub bid_size: i64,
  pub bid_time: String,
  pub change_close: f64,
  pub change_close_percentage: f64,
  pub company_name: String,
  pub days_to_expiration: i64,
  pub dir_last: String,
  pub dividend: f64,
  pub eps: f64,
  pub est_earnings: f64,
  pub ex_dividend_date: i64,
  pub exchg_last_trade: String,
  pub fsi: String,
  pub high: f64,
  pub high52: f64,
  pub high_ask: f64,
  pub high_bid: f64,
  pub last_trade: f64,
  pub low: f64,
  pub low52: f64,
  pub low_ask: f64,
  pub low_bid: f64,
  pub number_of_trades: i64,
  pub open: f64,
  pub open_interest: i64,
  pub option_style: String,
  pub option_underlier: String,
  pub option_underlier_exchange: String,
  pub previous_close: f64,
  pub previous_day_volume: i64,
  pub primary_exchange: String,
  pub symbol_description: String,
  pub today_close: f64,
  pub total_volume: i64,
  pub upc: i64,
  pub volume_10_day: i64,
  #[serde(rename = "OptionDeliverable", skip_serializing_if = "Vec::is_empty")]
  pub option_deliverable_list: Vec<OptionDeliverable>,
  pub cash_deliverable: f64,
  pub market_cap: f64,
  pub shares_outstanding: f64,
  pub next_earning_date: String,
  pub beta: f64,
  #[serde(rename = "yield")]
  pub dividend_yield: f64,
  pub declared_dividend: f64,
  pub dividend_payable_date: i64,
  pub pe: f64,
  pub market_close_bid_size: i64,
  pub market_close_ask_size: i64,
  pub market_close_volume: i64,
  pub week_52_low_date: i64,
  pub week_52_hi_date: i64,
  pub intrinsic_value: f64,
  pub time_premium: f64,
  pub option_multiplier: f64,
  pub contract_size: f64,
  pub expiration_date: i64,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub eh_quote: Option<ExtendedHourQuoteDetail>,
  pub option_previous_bid_price: f64,
  pub option_previous_ask_price: f64,
  pub osi_key: String,
  pub time_of_last_trade: i64,
  pub average_volume: i64,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct OptionDeliverable {
  pub root_symbol: String,
  pub deliverable_symbol: String,
  pub deliverable_type_code: String,
  pub deliverable_exchange_code: String,
  pub deliverable_strike_percent: f64,
  pub deliverable_c_i_l_shares: f64,
  pub deliverable_whole_shares: f64,
}

#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct ExtendedHourQuoteDetail {
  pub last_price: f64,
  pub change: f64,
  pub percent_change: f64,
  pub bid: f64,
  pub bid_size: i64,
  pub ask: f64,
  pub ask_size: i64,
  pub volume: i64,
  pub time_of_last_trade: i64,
  pub time_zone: String,
  pub quote_status: String,
}
#[derive(Debug, Clone, Copy, Deserialize, Serialize, EnumString)]
#[strum(serialize_all = "lowercase")]
pub enum DetailFlag {
  #[serde(rename = "ALL")]
  All,
  #[serde(rename = "FUNDAMENTAL")]
  Fundamental,
  #[serde(rename = "INTRADAY")]
  Intraday,
  #[serde(rename = "OPTIONS")]
  Options,
  #[serde(rename = "WEEK_52")]
  Week52,
  #[serde(rename = "MF_DETAIL")]
  MfDetail,
}
#[derive(Debug, Clone, Copy, Deserialize, Serialize, EnumString)]
#[strum(serialize_all = "lowercase")]
pub enum OptionCategory {
  #[serde(rename = "STANDARD")]
  Standard,
  #[serde(rename = "ALL")]
  All,
  #[serde(rename = "MINI")]
  Mini,
}

#[derive(Debug, Clone, Copy, Deserialize, Serialize, EnumString)]
#[strum(serialize_all = "lowercase")]
pub enum ChainType {
  #[serde(rename = "CALL")]
  Call,
  #[serde(rename = "PUT")]
  Put,
  #[serde(rename = "CALLPUT")]
  CallPut,
}

#[derive(Debug, Clone, Copy, Deserialize, Serialize, EnumString)]
#[strum(serialize_all = "lowercase")]
pub enum PairType {
  #[serde(rename = "CALLONLY")]
  CallOnly,
  #[serde(rename = "PUTONLY")]
  PutOnly,
  #[serde(rename = "CALLPUT")]
  CallPut,
}

#[derive(Debug, Clone, Copy, Deserialize, Serialize, EnumString)]
#[strum(serialize_all = "lowercase")]
pub enum PriceType {
  #[serde(rename = "ATNM")]
  Atnm,
  #[serde(rename = "ALL")]
  All,
}

#[derive(Debug, Clone, Copy, Deserialize, Serialize, EnumString)]
#[strum(serialize_all = "lowercase")]
pub enum ExpiryType {
  #[serde(rename = "UNSPECIFIED")]
  Unspecified,
  #[serde(rename = "DAILY")]
  Daily,
  #[serde(rename = "WEEKLY")]
  Weekly,
  #[serde(rename = "MONTHLY")]
  Monthly,
  #[serde(rename = "QUARTERLY")]
  Quarterly,
  #[serde(rename = "VIX")]
  Vix,
  #[serde(rename = "ALL")]
  All,
  #[serde(rename = "MONTHEND")]
  Monthend,
}

impl Default for ExpiryType {
  fn default() -> Self {
    ExpiryType::Unspecified
  }
}