schwab_cli/options/
validate.rs1use 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 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}