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 in src/strategies/base.rs): Supplies title retrieval and fundamental strategy metadata through methods like get_title().
  • Validable (defined in src/strategies/base.rs): Enforces validation logic via validate(), ensuring strategy configurations meet structural requirements before calculation.

Position and Break-Even Management

  • Positionable (defined in src/strategies/base.rs): Grants access to the collection of Position structs and handles quantity calculations.
  • BreakEvenable (defined in src/strategies/base.rs): Manages break-even price points through get_break_even_points() and update_break_even_points().
  • Strategies (defined in src/strategies/base.rs): Aggregates profit/loss, cost, price-range, and volume calculations, building upon Validable, Positionable, BreakEvenable, and BasicAble.

Analytics and Visualization

Strategy Construction

  • StrategyConstructor (defined in src/strategies/build/traits.rs): Enables generic conversion from a slice of Position structs into concrete strategy types via the get_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

  • Strategable serves as the master trait in src/strategies/base.rs, aggregating nine specialized capability traits into a unified contract.
  • Sub-traits like Greeks, Profit, and ProbabilityAnalysis isolate specific domains, enabling modular testing and extension.
  • Concrete strategies such as ShortStrangle implement Strategable by 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →