use ibapi::client::blocking::Client;
use ibapi::{
contracts::{Contract, Currency, Exchange, SecurityType, Symbol},
orders::ExerciseAction,
};
fn main() {
env_logger::init();
let client = Client::connect("127.0.0.1:4002", 100).expect("connection failed");
println!("Attempting to get SPY option chain...");
let option_chain_result = client.option_chain("SPY", "", SecurityType::Stock, 0);
let mut option_contract = if let Ok(subscription) = option_chain_result {
let mut chains = Vec::new();
for chain in subscription {
println!(
"Found option chain for exchange: {}, trading class: {}",
chain.exchange, chain.trading_class
);
chains.push(chain);
}
if !chains.is_empty() && !chains[0].expirations.is_empty() && !chains[0].strikes.is_empty() {
let chain = &chains[0];
let expiration = &chain.expirations[0];
let strike = chain.strikes[chain.strikes.len() / 2];
println!("Using option from chain: SPY {} Call, Strike: {}", expiration, strike);
Contract {
symbol: Symbol::from("SPY"),
security_type: SecurityType::Option,
exchange: Exchange::from(chain.exchange.clone()),
currency: Currency::from("USD"),
last_trade_date_or_contract_month: expiration.clone(),
strike,
right: "C".to_owned(),
multiplier: chain.multiplier.clone(),
trading_class: chain.trading_class.clone(),
..Default::default()
}
} else {
println!("No option chain data available, using hardcoded contract");
Contract {
symbol: Symbol::from("SPY"),
security_type: SecurityType::Option,
exchange: Exchange::from("SMART"),
currency: Currency::from("USD"),
last_trade_date_or_contract_month: "20250117".to_owned(),
strike: 500.0, right: "C".to_owned(),
multiplier: "100".to_owned(),
..Default::default()
}
}
} else {
println!("Could not get option chain, using hardcoded contract");
Contract {
symbol: Symbol::from("SPY"),
security_type: SecurityType::Option,
exchange: Exchange::from("SMART"),
currency: Currency::from("USD"),
last_trade_date_or_contract_month: "20250117".to_owned(),
strike: 550.0,
right: "C".to_owned(),
multiplier: "100".to_owned(),
..Default::default()
}
};
println!("\nGetting contract details for option:");
println!(
"Symbol: {}, Strike: {}, Right: {}, Expiry: {}",
option_contract.symbol, option_contract.strike, option_contract.right, option_contract.last_trade_date_or_contract_month
);
match client.contract_details(&option_contract) {
Ok(details) if !details.is_empty() => {
option_contract = details[0].contract.clone();
println!("\nFound valid contract!");
println!("Local Symbol: {}", option_contract.local_symbol);
println!("Contract ID: {}", option_contract.contract_id);
println!("Exchange: {}", option_contract.exchange);
println!("Trading Class: {}", option_contract.trading_class);
}
_ => {
println!("\nWarning: Could not validate contract details.");
println!("Will attempt to exercise with the provided contract specification.");
println!("Note: This may fail if the contract doesn't exist.");
}
}
let accounts = client.managed_accounts().expect("could not get managed accounts");
let account = &accounts[0];
let manual_order_time = None;
println!("\n=== Exercising Option Contract ===");
println!("Account: {}", account);
println!("Action: Exercise");
println!("Quantity: 1 contract");
println!("Override: true (exercise even if out-of-the-money)");
println!();
let subscription = client
.exercise_options(&option_contract, ExerciseAction::Exercise, 1, account, true, manual_order_time)
.expect("exercise options request failed!");
println!("Exercise request sent. Waiting for responses...\n");
for status in &subscription {
println!("Response: {:?}", status);
}
println!("\nExercise options example completed.");
}