Skip to main content

schwab_cli/options/
validate.rs

1use anyhow::{bail, Result};
2use schwab_api::TraderApi;
3use serde_json::Value;
4
5use crate::options::strategies::{iron_condor_max_loss, vertical_max_loss};
6use crate::options::types::{IronCondorParams, StrategyKind, VerticalParams};
7use crate::portfolio::{account_buying_power, ensure_sufficient_buying_power, BuyingPower};
8use crate::rules::AccountType;
9
10pub fn validate_account_for_strategy(account_type: AccountType, kind: StrategyKind) -> Result<()> {
11    match kind {
12        StrategyKind::Vertical | StrategyKind::IronCondor => {
13            // Defined-risk strategies allowed on all account types in v1.
14            let _ = account_type;
15            Ok(())
16        }
17    }
18}
19
20pub async fn ensure_option_buying_power(
21    api: &TraderApi,
22    account_hash: &str,
23    required_margin: f64,
24) -> Result<BuyingPower> {
25    let bp = account_buying_power(api, account_hash).await?;
26    ensure_sufficient_buying_power(&bp, required_margin)?;
27    Ok(bp)
28}
29
30pub fn estimate_vertical_margin(params: &VerticalParams) -> Result<f64> {
31    vertical_max_loss(params)
32}
33
34pub fn estimate_iron_condor_margin(params: &IronCondorParams) -> f64 {
35    iron_condor_max_loss(params)
36}
37
38pub fn estimate_order_margin(_order: &Value, kind: StrategyKind, params: &Value) -> Result<f64> {
39    match kind {
40        StrategyKind::Vertical => {
41            let p: VerticalParams = serde_json::from_value(params.clone())?;
42            estimate_vertical_margin(&p)
43        }
44        StrategyKind::IronCondor => {
45            let p: IronCondorParams = serde_json::from_value(params.clone())?;
46            Ok(estimate_iron_condor_margin(&p))
47        }
48    }
49}
50
51pub fn build_order_for_strategy(kind: StrategyKind, params: &Value) -> Result<Value> {
52    match kind {
53        StrategyKind::Vertical => {
54            let p: VerticalParams = serde_json::from_value(params.clone())?;
55            crate::options::strategies::build_vertical_order(&p)
56        }
57        StrategyKind::IronCondor => {
58            let p: IronCondorParams = serde_json::from_value(params.clone())?;
59            crate::options::strategies::build_iron_condor_order(&p)
60        }
61    }
62}
63
64pub fn params_from_value(kind: StrategyKind, params: &Value) -> Result<Value> {
65    match kind {
66        StrategyKind::Vertical => {
67            let p: VerticalParams = serde_json::from_value(params.clone())?;
68            if p.limit_credit.is_none() && p.limit_debit.is_none() {
69                bail!("vertical params require limit_credit or limit_debit");
70            }
71            Ok(serde_json::to_value(p)?)
72        }
73        StrategyKind::IronCondor => {
74            let p: IronCondorParams = serde_json::from_value(params.clone())?;
75            Ok(serde_json::to_value(p)?)
76        }
77    }
78}