# How to Implement a Custom Strategy Using the Strategable Trait in optionstratlib

> Learn to implement custom option strategies with optionstratlib by utilizing the Strategable trait. Define your strategy and unlock the full analytics engine.

- Repository: [Joaquin Bejar Garcia/optionstratlib](https://github.com/joaquinbejar/optionstratlib)
- Tags: how-to-guide
- Published: 2026-03-04

---

**Implementing a custom strategy in optionstratlib requires defining a struct that holds your option legs, implementing the component traits like `StrategyConstructor`, `BreakEvenable`, and `Profit`, and finally implementing the empty `Strategable` trait marker to unlock the full analytics engine.**

The `optionstratlib` crate provides a powerful custom strategy framework that enables traders to define bespoke options strategies while retaining access to built-in analytics for Greeks, P&L, and risk management. At the heart of this system lies the **`Strategable`** trait, which aggregates all capabilities a strategy can expose. This guide walks you through implementing a custom strategy using the `Strategable` trait based on the reference implementation in the library source code.

## 1. Define the Strategy Data Structure

First, create a struct that stores the option legs and any auxiliary parameters. In [`src/strategies/custom.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/strategies/custom.rs), the `CustomStrategy` struct serves as the canonical example:

```rust
/// The `CustomStrategy` struct allows traders to create and analyse bespoke options strategies
pub struct CustomStrategy {
    /// Vector of option legs that make up the strategy
    pub legs: Vec<OptionLeg>,
    /// Optional name for the strategy (useful for logging / reporting)
    pub name: Option<String>,
    // …any extra fields you need (e.g., target delta, risk limits, etc.)
}

```

*Source:* [[`src/strategies/custom.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/strategies/custom.rs) – struct definition (line 51)](https://github.com/joaquinbejar/optionstratlib/blob/main/src/strategies/custom.rs#L51)

## 2. Implement the StrategyConstructor Trait

The **`StrategyConstructor`** trait defines how the strategy is instantiated and initialized. This is where you compute break-even points, run validation, and set up any derived data:

```rust
impl StrategyConstructor for CustomStrategy {
    fn new(name: &str, vec_options: Vec<OptionLeg>) -> Result<Self, StrategyError> {
        // Build the struct
        let mut strategy = CustomStrategy {
            legs: vec_options,
            name: Some(name.to_string()),
        };

        // Compute break‑even, implied vol, etc.
        strategy.calculate_break_even()?;
        strategy.validate()?;

        Ok(strategy)
    }

    fn strategy_name(&self) -> String {
        self.name.clone().unwrap_or_else(|| "CustomStrategy".to_string())
    }

    fn description(&self) -> String {
        format!("CustomStrategy: {:?}", self.legs)
    }
}

```

*Source:* [[`src/strategies/custom.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/strategies/custom.rs) – constructor impl (line 343‑352)](https://github.com/joaquinbejar/optionstratlib/blob/main/src/strategies/custom.rs#L343-L352)

## 3. Implement Core Analytics Traits

To make your strategy fully functional, you must implement the component traits that `Strategable` aggregates. Most implementations delegate to the `legs` vector using generic utilities provided by the library.

### BreakEvenable

The **`BreakEvenable`** trait calculates the break-even points for the strategy:

```rust
impl BreakEvenable for CustomStrategy {
    fn calculate_break_even(&mut self) -> Result<(), StrategyError> {
        // Use the generic utility that works on any collection of legs
        self.break_even = self
            .legs
            .iter()
            .map(|leg| leg.premium())
            .sum::<f64>();
        Ok(())
    }
}

```

*Source:* [[`src/strategies/custom.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/strategies/custom.rs) – `BreakEvenable` (line 358‑363)](https://github.com/joaquinbejar/optionstratlib/blob/main/src/strategies/custom.rs#L358-L363)

### Positionable

The **`Positionable`** trait exposes position-level metrics like net delta and gamma:

```rust
impl Positionable for CustomStrategy {
    fn net_delta(&self) -> f64 {
        self.legs.iter().map(|leg| leg.delta()).sum()
    }

    fn net_gamma(&self) -> f64 {
        self.legs.iter().map(|leg| leg.gamma()).sum()
    }

    // …other position metrics (vega, theta, rho)
}

```

*Source:* [[`src/strategies/custom.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/strategies/custom.rs) – `Positionable` (line 387‑393)](https://github.com/joaquinbejar/optionstratlib/blob/main/src/strategies/custom.rs#L387-L393)

### Profit

The **`Profit`** trait calculates P&L at expiry for a given underlying price:

```rust
impl Profit for CustomStrategy {
    fn profit_at_expiry(&self, underlying: f64) -> f64 {
        self.legs.iter().map(|leg| leg.payoff(underlying)).sum()
    }
}

```

*Source:* [[`src/strategies/custom.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/strategies/custom.rs) – `Profit` (line 829‑834)](https://github.com/joaquinbejar/optionstratlib/blob/main/src/strategies/custom.rs#L829-L834)

### Greeks and Validation

All other traits—**`Greeks`**, **`DeltaNeutrality`**, **`Validable`**, **`Optimizable`**, etc.—are implemented in the same style by delegating to the `legs` collection or applying custom formulas. The library provides default helper functions for most calculations; you only need to override methods when your strategy requires special logic.

*Sources (excerpt):*  
- `Greeks` impl (line 921‑928)  
- `Validable` impl (line 742‑749)  
- `Optimizable` impl (line 767‑771)  

## 4. Implement the Strategable Trait Marker

**`Strategable`** is the master trait that aggregates every capability. The implementation is essentially a "glue" marker that tells the compiler your type fulfills all sub‑traits:

```rust
impl Strategable for CustomStrategy {
    // The trait does not require any additional methods; the presence of the
    // component‑trait impls is enough for the compiler.
}

```

*Source:* [[`src/strategies/custom.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/strategies/custom.rs) – `Strategable` (line 512‑514)](https://github.com/joaquinbejar/optionstratlib/blob/main/src/strategies/custom.rs#L512-L514)

Because `Strategable` inherits from `BasicAble`, `Positionable`, `BreakEvenable`, `Profit`, `Greeks`, and others, once you implement those components, your strategy automatically becomes a full‑featured object compatible with any library routine expecting a `Box<dyn Strategable>`.

## 5. Using Your Custom Strategy

Here is a complete example showing how to instantiate and use your custom strategy within the `optionstratlib` ecosystem:

```rust
use optionstratlib::strategies::{CustomStrategy, StrategyConstructor};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Define your legs (calls, puts, strikes, expiries, etc.)
    let legs = vec![
        OptionLeg::new_call("AAPL", 150.0, 30.0, 0.25),
        OptionLeg::new_put ("AAPL", 140.0, 20.0, 0.25),
    ];

    // Build the custom strategy
    let my_strat = CustomStrategy::new("MyAAPLSpread", legs)?;

    // All high‑level analytics are now available:
    println!("Net delta: {}", my_strat.net_delta());
    println!("Break‑even: {}", my_strat.break_even());
    println!("Profit if underlying = 155: {}", my_strat.profit_at_expiry(155.0));

    // It can be passed to any generic routine that expects a `Strategable`
    run_backtest(Box::new(my_strat));

    Ok(())
}

```

**Key implementation details demonstrated:**

- **Leg definition** uses the library’s `OptionLeg` helper types to specify underlying, strike, premium, and expiration.
- **Constructor** calls `CustomStrategy::new`, which automatically runs break-even calculation and validation.
- **Analytics** methods (`net_delta`, `break_even`, `profit_at_expiry`) come from the sub-traits implemented earlier.
- **Trait object compatibility** allows passing `Box::new(my_strat)` to any function expecting `Box<dyn Strategable>`, making your custom strategy interchangeable with built-in strategies like `ShortStrangle`.

## Summary

To implement a custom strategy using the `Strategable` trait framework in `optionstratlib`:

- **Define a struct** (e.g., `CustomStrategy`) containing a `Vec<OptionLeg>` and any configuration fields.
- **Implement `StrategyConstructor`** to handle initialization, validation, and break-even calculation.
- **Implement component traits** (`BreakEvenable`, `Positionable`, `Profit`, `Greeks`, `Validable`, `Optimizable`) by delegating to the legs collection or providing custom logic.
- **Add an empty `Strategable` impl** to mark the type as fully capable, enabling use as `Box<dyn Strategable>`.
- **Use the strategy** with any library function expecting a strategable object, gaining access to backtesting, visualization, and risk analytics.

## Frequently Asked Questions

### What is the difference between `Strategable` and `StrategyConstructor`?

`StrategyConstructor` is a component trait that defines how a strategy is created and named, requiring methods like `new()` and `strategy_name()`. `Strategable` is the master trait that aggregates all capabilities—including `StrategyConstructor`, `BreakEvenable`, `Profit`, and `Greeks`—into a single interface. You implement the component traits to provide functionality, then implement `Strategable` (usually as an empty impl) to signal that your type is a complete strategy.

### Do I need to implement every trait method manually, or are there default implementations?

Many traits in `optionstratlib` provide default implementations that operate on collections of `OptionLeg`. For example, `net_delta()` and `net_gamma()` in `Positionable` can often be implemented by simply summing the corresponding values across `self.legs`. Similarly, `profit_at_expiry()` sums the payoff of each leg. You only need to provide custom implementations when your strategy has unique logic that deviates from the standard leg aggregation.

### Can I mix custom strategies with built-in strategies like `ShortStrangle`?

Yes. Once you implement `Strategable` for your custom type, it becomes interchangeable with any built-in strategy. Both your custom strategy and library strategies like `ShortStrangle` can be boxed as `Box<dyn Strategable>` and passed to generic functions for backtesting, optimization, or risk analysis. This polymorphism is the primary benefit of the trait-based architecture.

### Where should I place my custom strategy code?

While you can place custom strategy implementations anywhere in your own crate, the reference implementation in [`src/strategies/custom.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/strategies/custom.rs) demonstrates the recommended structure. If you are contributing to the library or maintaining a fork, place your strategy in `src/strategies/` and ensure it is exported in [`src/strategies/mod.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/strategies/mod.rs). For end-users consuming the library as a dependency, implementing the traits on a local struct in your application code is sufficient.