How the Strategable Trait Hierarchy Organizes Strategy Capabilities in OptionStratLib
The Strategable trait hierarchy unifies all option strategies under a single master trait that aggregates specialized sub-traits for Greeks, P&L, probability analysis, and visualization, enabling polymorphic handling while enforcing compile-time capability contracts.
OptionStratLib models every option strategy as a concrete Rust type implementing the Strategable trait hierarchy. This architecture decouples capability definitions from business logic, allowing diverse strategies—from covered calls to iron condors—to expose a uniform API while maintaining specialized implementations.
The Master Strategable Trait in src/strategies/base.rs
Located at lines 50-58 in src/strategies/base.rs, the Strategable trait serves as the central abstraction that enforces a comprehensive contract for all option strategies:
pub trait Strategable:
Strategies
+ StrategyConstructor
+ Profit
+ Graph
+ ProbabilityAnalysis
+ Greeks
+ DeltaNeutrality
+ PnLCalculator
{
// default helpers: `info`, `type_name`, `name`
}
This trait contains no business logic itself; it requires implementors to satisfy all listed sub-traits. It provides convenience methods—info(), type_name(), and name()—that forward to the StrategyBasics structure, ensuring consistent metadata access across all strategy types.
Core Capability Traits in the Hierarchy
The Strategable trait composes nine specialized capability traits, each defined in dedicated modules to enforce separation of concerns.
Basic Metadata and Validation
BasicAble(defined insrc/strategies/base.rs): Supplies title retrieval and fundamental strategy metadata through methods likeget_title().Validable(defined insrc/strategies/base.rs): Enforces validation logic viavalidate(), ensuring strategy configurations meet structural requirements before calculation.
Position and Break-Even Management
Positionable(defined insrc/strategies/base.rs): Grants access to the collection ofPositionstructs and handles quantity calculations.BreakEvenable(defined insrc/strategies/base.rs): Manages break-even price points throughget_break_even_points()andupdate_break_even_points().Strategies(defined insrc/strategies/base.rs): Aggregates profit/loss, cost, price-range, and volume calculations, building uponValidable,Positionable,BreakEvenable, andBasicAble.
Analytics and Visualization
Profit(located insrc/pricing/payoff.rs): Calculates profit at any underlying price viacalculate_profit_at().Graph(located insrc/visualization/default.rs): Providesgraph_data()and optionalgraph_config()for plot-ready output.ProbabilityAnalysis(located insrc/strategies/probabilities/core.rs): Generates structured outcome-probability reports for risk assessment.Greeks(located insrc/greeks/equations.rs): Aggregates delta, gamma, vega, theta, and rho calculations across all strategy legs.DeltaNeutrality(located insrc/strategies/delta_neutral/model.rs): Checks and enforces delta-neutral positioning utilities.PnLCalculator(located insrc/pnl/traits.rs): Tracks realized and unrealized profit/loss with transaction handling.
Strategy Construction
StrategyConstructor(defined insrc/strategies/build/traits.rs): Enables generic conversion from a slice ofPositionstructs into concrete strategy types via theget_strategy()method.
Concrete Implementation Example: ShortStrangle
The ShortStrangle strategy in src/strategies/short_strangle.rs demonstrates how concrete types integrate into the hierarchy. It implements Strategable by providing the required info() method:
impl Strategable for ShortStrangle {
fn info(&self) -> Result<StrategyBasics, StrategyError> {
Ok(StrategyBasics {
name: self.name.clone(),
kind: self.kind.clone(),
description: self.description.clone(),
})
}
}
Because ShortStrangle also implements BasicAble (providing get_title()), Positionable (via the internal legs vector), BreakEvenable (with custom break-even logic), StrategyConstructor (through the generic builder), and the remaining analytics traits, the compiler recognizes it as a fully-featured strategy satisfying the complete Strategable contract.
Benefits of the Trait Composition Pattern
This hierarchical design delivers three critical architectural advantages:
Extensibility without breakage — Adding new capabilities requires only defining a new trait and appending it to the Strategable requirements. Existing strategies automatically gain the new method signature at compile time without breaking changes.
Separation of concerns — Each trait isolates a single domain (Greek mathematics, visualization, P&L accounting). Unit tests can target individual trait implementations rather than monolithic strategy objects.
Runtime polymorphism — The library stores heterogeneous strategies behind boxed trait objects (Box<dyn Strategable>) while retaining access to all aggregated methods. The generic builder in strategies/build/model.rs (line 72) leverages this to return concrete strategy instances through a uniform interface.
Implementing a Custom Strategy
Developers can create new strategies by implementing the required traits. The following example shows a minimal "Zero-Cost" strategy implementing the full hierarchy:
use optionstratlib::strategies::{
BasicAble, Strategies, Positionable, BreakEvenable, Validable,
StrategyConstructor, Greeks, Profit, Graph, ProbabiltyAnalysis,
DeltaNeutrality, PnLCalculator, StrategyBasics, StrategyError,
};
use optionstratlib::model::Position;
/// Minimal “Zero‑Cost” strategy that is only profit‑aware.
pub struct ZeroCost {
pub name: String,
pub kind: StrategyType,
pub description: String,
pub legs: Vec<Position>,
}
// ----- BasicAble -------------------------------------------------
impl BasicAble for ZeroCost {
fn get_title(&self) -> String {
format!("Zero‑Cost: {}", self.kind)
}
}
// ----- Positionable -----------------------------------------------
impl Positionable for ZeroCost {
fn get_positions(&self) -> &Vec<Position> {
&self.legs
}
}
// ----- BreakEvenable (use default error) --------------------------
impl BreakEvenable for ZeroCost {}
// ----- Validable --------------------------------------------------
impl Validable for ZeroCost {
fn validate(&self) -> bool {
// a zero‑cost strategy must have net premium = 0
self.get_total_premium() == Decimal::ZERO
}
}
// ----- Strategies -------------------------------------------------
impl Strategies for ZeroCost {}
// ----- StrategyConstructor (use default NotImplemented) ----------
impl StrategyConstructor for ZeroCost {}
// ----- Profit (custom implementation) -----------------------------
impl Profit for ZeroCost {
fn calculate_profit_at(&self, price: &Positive) -> Result<Decimal, PricingError> {
// simple sum of payoff of each leg at `price`
self.legs
.iter()
.map(|leg| leg.calculate_payoff(price))
.sum()
}
}
// ----- Graph (use default from `visualization::default`) ---------
impl Graph for ZeroCost {}
// ----- ProbabilityAnalysis (use default NotImplemented) ----------
impl ProbabiltyAnalysis for ZeroCost {}
// ----- DeltaNeutrality (use default NotImplemented) -------------
impl DeltaNeutrality for ZeroCost {}
// ----- PnLCalculator (use default NotImplemented) ---------------
impl PnLCalculator for ZeroCost {}
// ----- Strategable (only need to supply `info`) ---------------
impl Strategable for ZeroCost {
fn info(&self) -> Result<StrategyBasics, StrategyError> {
Ok(StrategyBasics {
name: self.name.clone(),
kind: self.kind.clone(),
description: self.description.clone(),
})
}
}
All required traits are satisfied, allowing ZeroCost to function as dyn Strategable within the library ecosystem.
Runtime Polymorphism with Boxed Strategies
User code can handle multiple strategy types uniformly through trait objects. The following pattern demonstrates building strategies from raw positions:
use optionstratlib::strategies::{Strategable, StrategyConstructor};
use optionstratlib::model::Position;
/// Build a strategy from raw positions (the builder decides the concrete type)
fn build_from_legs(positions: &[Position]) -> Box<dyn Strategable> {
// The generic builder tries each concrete strategy in order.
// `ShortStrangle` is one of many.
ShortStrangle::get_strategy(positions)
.or_else(|_| ShortPut::get_strategy(positions))
.unwrap()
}
// ---- runtime usage -------------------------------------------------
let legs: Vec<Position> = vec![/* ... */]; // user‑provided data
let strat = build_from_legs(&legs);
println!("Strategy: {}", strat.name());
let profit = strat.calculate_profit_at(&Positive::new(150.0).unwrap()).unwrap();
println!("Profit @ 150 = {}", profit);
The caller interacts solely with the Strategable interface, while the concrete implementation (whether ShortStrangle, ShortPut, or any other variant) remains encapsulated.
Summary
Strategableserves as the master trait insrc/strategies/base.rs, aggregating nine specialized capability traits into a unified contract.- Sub-traits like
Greeks,Profit, andProbabilityAnalysisisolate specific domains, enabling modular testing and extension. - Concrete strategies such as
ShortStrangleimplementStrategableby satisfying all sub-trait requirements, typically providing custom logic only where differentiated. - The hierarchy supports runtime polymorphism via
Box<dyn Strategable>, allowing generic strategy builders to return heterogeneous types through a single interface. - New capabilities integrate seamlessly by adding traits to the hierarchy, with compile-time enforcement ensuring all strategies expose consistent APIs.
Frequently Asked Questions
What is the Strategable trait in OptionStratLib?
The Strategable trait is the central abstraction defined in src/strategies/base.rs that defines the complete contract for option strategies. It aggregates nine specialized sub-traits—including Greeks, Profit, and PnLCalculator—into a single interface that guarantees uniform behavior across all strategy types while permitting specialized implementations.
Which sub-traits does Strategable require?
Strategable requires Strategies, StrategyConstructor, Profit, Graph, ProbabilityAnalysis, Greeks, DeltaNeutrality, and PnLCalculator. These traits cover validation, position management, break-even calculation, profit surfaces, visualization, Greek analytics, delta-neutral checks, and P&L accounting respectively.
How does OptionStratLib handle different strategy types at runtime?
The library leverages trait objects (Box<dyn Strategable>) to store heterogeneous strategies behind a unified pointer. As implemented in strategies/build/model.rs, generic builders can attempt construction against multiple concrete types and return the successful match as a boxed trait object, enabling polymorphic profit calculations and Greek analysis without knowing the concrete type at compile time.
Where can I find the source files for the trait hierarchy?
The master trait resides in src/strategies/base.rs (lines 50-58). Specialized traits are distributed across src/greeks/equations.rs (Greeks), src/pnl/traits.rs (PnL), src/pricing/payoff.rs (Profit), src/visualization/default.rs (Graph), src/strategies/probabilities/core.rs (ProbabilityAnalysis), src/strategies/delta_neutral/model.rs (DeltaNeutrality), and src/strategies/build/traits.rs (StrategyConstructor).
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →