# How the Leg Enum Supports Multi-Asset Strategies in optionstratlib

> Discover how the Leg enum in optionstratlib unifies options, spot, futures & perpetuals for streamlined multi-asset strategy construction and P&L calculations.

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

---

**The `Leg` enum unifies options, spot assets, futures, and perpetual swaps under a single `LegAble` interface, enabling seamless construction of multi-asset strategies through uniform P&L calculations and risk metrics.**

The `Leg` enum serves as the architectural foundation for complex portfolio modeling in the **optionstratlib** crate. By abstracting four distinct instrument types into a unified type system, it eliminates the need for separate handling logic when building multi-asset strategies that combine traditional derivatives with spot and crypto instruments.

## The Four Leg Variants

Defined in [`src/model/leg/leg_enum.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/model/leg/leg_enum.rs), the `Leg` enum encapsulates each instrument type within a dedicated variant. This design allows a single vector of legs to represent heterogeneous positions while maintaining type safety through Rust's enum dispatch.

### Option Positions

The `Option(Box<Position>)` variant wraps traditional option contracts (calls and puts). According to the source in [`src/model/leg/leg_enum.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/model/leg/leg_enum.rs) [lines 61-64], this variant stores the option contract details, premium, and fees within a boxed `Position` struct to enable efficient heap allocation for complex option strategies.

### Spot Positions

The `Spot(SpotPosition)` variant represents direct ownership of the underlying asset. As implemented in [`src/model/leg/spot.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/model/leg/spot.rs) [lines 63-84], `SpotPosition` tracks the asset symbol, quantity, cost basis, side (long/short), and associated fees. This enables strategies like protective puts or cash-and-carry arbitrage that require physical holdings.

### Futures Positions

The `Future(FuturePosition)` variant handles standard exchange-traded futures contracts. The implementation in [`src/model/leg/future.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/model/leg/future.rs) [lines 71-79] includes fields for symbol, quantity, entry price, expiration date, contract size, and margin requirements. This supports calendar spreads and basis trading strategies within the same framework.

### Perpetual Swaps

The `Perpetual(PerpetualPosition)` variant accommodates crypto perpetual swaps. Defined in [`src/model/leg/perpetual.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/model/leg/perpetual.rs) [lines 71-79], this struct tracks the symbol, quantity, entry price, funding rate, margin, and expiration handling specific to perpetual instruments. This enables crypto-native strategies that combine perpetuals with options or spot holdings.

## The LegAble Trait Interface

All four variants implement the `LegAble` trait, which serves as the common contract for strategy calculations. This trait abstraction, defined alongside the `Leg` enum in [`src/model/leg/leg_enum.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/model/leg/leg_enum.rs), exposes uniform methods regardless of the underlying instrument type:

- `get_symbol()` – Returns the ticker symbol of the underlying asset.
- `get_quantity()` – Retrieves the number of units or contracts held.
- `get_side()` – Indicates long or short orientation.
- `pnl_at_price()` – Calculates profit and loss at a given underlying price.
- `total_cost()` – Aggregates entry costs including fees.
- `fees()` – Returns transaction costs.
- Greeks calculation methods (`delta`, `gamma`, `theta`, `vega`, `rho`) for risk metrics.

Because every leg implements these methods, strategies can iterate over a `Vec<Leg>` (retrieved via `get_legs()`) without pattern matching on specific instrument types. The enum's internal dispatch handles the differentiation, while strategies work with the uniform `LegAble` interface.

## Building Multi-Asset Strategies

The `Leg` enum enables complex multi-asset strategies through convenience constructors and `From` implementations. Strategies like `CoveredCall`, `ProtectivePut`, and custom crypto-covered-calls collect heterogeneous positions into a unified `Vec<Leg>` for uniform processing.

### Cash-and-Carry Arbitrage

This strategy combines a spot position with a short futures contract to capture the basis differential. The following example demonstrates constructing both legs using the `Leg` enum:

```rust
use optionstratlib::model::leg::{Leg, SpotPosition, FuturePosition};
use optionstratlib::model::types::Side;
use positive::Positive;
use chrono::Utc;

// Spot leg – long 100 shares of AAPL
let spot = SpotPosition::long(
    "AAPL".to_string(),
    Positive::HUNDRED,
    Positive::from(150),
);
let spot_leg = Leg::spot(spot);

// Futures leg – short 2 ES contracts, expiring in 30 days
let future = FuturePosition::short(
    "ES".to_string(),
    Positive::TWO,
    Positive::from(4500),
    optionstratlib::model::ExpirationDate::Days(Positive::from(30)),
    Positive::from(50),          // contract size
    Positive::from(15000),      // margin per contract
);
let future_leg = Leg::future(future);

// Combine into a strategy-like container
let legs = vec![spot_leg, future_leg];

// Uniformly access data
for leg in &legs {
    println!("{} {} @ {}",
        leg.leg_type_name(),
        leg.get_quantity(),
        leg.get_symbol(),
    );
}

```

This creates a two-leg, multi-asset strategy where the spot position offsets the futures exposure, all accessed through the same `Leg` API.

### Crypto Covered Call with Perpetual

For crypto-native portfolios, strategies often combine perpetual swaps with options. The `Leg` enum accommodates this by mixing the `Perpetual` variant with traditional `Option` and `Spot` variants:

```rust
use optionstratlib::model::leg::{Leg, SpotPosition, PerpetualPosition};
use optionstratlib::model::types::Side;
use positive::Positive;
use chrono::Utc;

// Existing covered-call legs (spot + option) – omitted for brevity
let spot_leg = Leg::spot(/* SpotPosition::long(...) */);
let option_leg = Leg::option(/* Position::new(...) */);

// Perpetual leg – long BTC-USDT perpetual swap
let perp = PerpetualPosition::long(
    "BTC-USDT-PERP".to_string(),
    Positive::ONE,
    Positive::from(50000),
    optionstratlib::model::ExpirationDate::Perpetual, // perpetual never expires
    Positive::from(1),          // contract multiplier
    Positive::from(1000),       // initial margin
);
let perp_leg = Leg::perpetual(perp);

// Full strategy now holds three different asset types
let all_legs = vec![spot_leg, option_leg, perp_leg];

for leg in all_legs {
    println!("Leg: {} – Symbol: {}", leg.leg_type_name(), leg.get_symbol());
}

```

The `Leg` enum cleanly accommodates a perpetual swap alongside traditional option-spot components, enabling complex crypto derivatives strategies.

### Generic P&L Aggregation

The unified `LegAble` interface enables generic calculations across heterogeneous positions. Because every variant implements `pnl_at_price()`, strategies can aggregate P&L without type-specific logic:

```rust
use optionstratlib::model::leg::Leg;
use positive::Positive;
use rust_decimal::Decimal;

fn aggregate_pnl(legs: &[Leg], price: Positive) -> Decimal {
    legs.iter()
        .map(|leg| leg.pnl_at_price(price))
        .sum()
}

// Example usage
let pnl = aggregate_pnl(&all_legs, Positive::from(52000));
println!("Total P&L at price 52,000 = {}", pnl);

```

Because every `Leg` implements `pnl_at_price`, the function works for any mix of instrument types, from spot holdings to perpetual swaps.

## Summary

The `Leg` enum provides the type system foundation for complex portfolio construction in **optionstratlib**:

- **Four unified variants** (`Option`, `Spot`, `Future`, `Perpetual`) encapsulate distinct instrument types while exposing a common interface.
- **The `LegAble` trait** enables uniform access to symbols, quantities, sides, P&L calculations, and Greeks across all asset classes.
- **Heterogeneous vectors** of `Leg` items allow strategies to combine options with spot, futures, and perpetual positions without type-specific dispatch logic.
- **Source locations** including [`src/model/leg/leg_enum.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/model/leg/leg_enum.rs), [`src/model/leg/spot.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/model/leg/spot.rs), [`src/model/leg/future.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/model/leg/future.rs), and [`src/model/leg/perpetual.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/model/leg/perpetual.rs) implement this unified abstraction.

## Frequently Asked Questions

### How does the Leg enum handle different margin requirements across asset types?

The `Leg` enum delegates margin tracking to the underlying position structs. For futures, `FuturePosition` stores margin requirements in [`src/model/leg/future.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/model/leg/future.rs) [lines 71-79], while `PerpetualPosition` handles crypto-specific margin and funding rates in [`src/model/leg/perpetual.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/model/leg/perpetual.rs) [lines 71-79]. When accessed through the `LegAble` interface, margin calculations remain uniform while preserving instrument-specific requirements.

### Can I mix long and short positions in the same multi-asset strategy?

Yes. Each `Leg` variant carries its own `Side` orientation (long or short) within the underlying position struct. The `get_side()` method from the `LegAble` trait allows strategies to query directionality uniformly, enabling complex multi-asset strategies like cash-and-carry arbitrage (long spot, short futures) or reverse conversions without type-specific logic.

### What performance benefits does the LegAble trait provide for strategy calculations?

The `LegAble` trait enables vectorized iteration over heterogeneous positions without dynamic dispatch overhead. Because `Leg` is an enum with inline storage, calling `delta()`, `gamma()`, or `theta()` on each leg in a `Vec<Leg>` uses static dispatch through the trait implementation. This allows strategies defined in files like [`src/strategies/covered_call.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/strategies/covered_call.rs) to aggregate risk metrics across options, spot, and futures positions with a single iteration loop.

### How do I construct a Leg instance from a custom position struct?

The `Leg` enum provides convenience constructors (`Leg::spot()`, `Leg::future()`, `Leg::perpetual()`, `Leg::option()`) that wrap concrete position types. Additionally, `From` implementations allow implicit conversion. For example, passing a `SpotPosition` to a function expecting a `Leg` automatically invokes the conversion, or you can explicitly call `Leg::spot(spot_position)` as implemented in [`src/model/leg/leg_enum.rs`](https://github.com/joaquinbejar/optionstratlib/blob/main/src/model/leg/leg_enum.rs).