Overview
Getting started
Add the engine, build a ChainSnapshot, construct candidates with a SpreadBuilder, and rank them — in a few lines.
Add the dependency
FerroSpread is a path dependency on the engine crates within the MorphIQ Labs workspace:
# Cargo.toml
[dependencies]
ferro-spread = { path = "../ferro-spread" }Pricing is supplied by FerroRisk; FerroSpread constructs and ranks over the FerroRisk parametric IV surface rather than re-deriving option prices.
Construct your first spread
Construction takes a typed ChainSnapshot and a SpreadBuilder policy, and returns a vector of priced SpreadCandidates:
use ferro_spread::{ChainSnapshot, SpreadBuilder, SpreadStrategy};
let chain = ChainSnapshot::from_enriched(quote_snapshot)?;
let policy = SpreadBuilder::default()
.strategy(SpreadStrategy::BullCallDebit)
.dte_range(21..=45)
.target_delta(0.30)
.min_wing_pts(5.0)
.max_wing_pts(20.0);
let candidates: Vec<SpreadCandidate> = policy.construct(&chain)?;
// Each candidate carries legs, debit, max profit, max loss,
// breakeven, and a PricingTrace back to the FerroRisk fit.…then rank
Rankerimposes the trader's priorities — rank by a metric, under hard constraints — and returns a sorted Vec<RankedCandidate>:
use ferro_spread::{Ranker, RankingMetric};
let ranker = Ranker::default()
.by(RankingMetric::ExpectedValue)
.constrain(RankingMetric::ProbabilityOfProfit, 0.60..)
.constrain(RankingMetric::MaxLoss, ..=500.0);
let ranked = ranker.rank(&candidates);Every ranked candidate can be expanded into a typed Explanation — score breakdown, dominant Greeks, comparables, and the assumptions trail. See explain a candidate.
Where to go next
- Conventions — units, probabilities, and the capital/risk definitions behind the scores.
- Strategies — the full construction taxonomy.
- Universe screen — run the construct/rank pipeline across a whole watchlist.