OpenBB-finance/OpenBB · error · OpenBBError

Error: No premium data found for the selected strikes. Call:

Error message

Error: No premium data found for the selected strikes. Call: {call_strike_estimate}, Put: {put_strike_estimate}

What it means

Thrown by OptionsChainsData.straddle() when, after estimating the nearest call and put strikes for the target expiration, filtering the chains DataFrame by those strikes and option types yields an empty premium series. It means the strike rows returned by _get_nearest_strike() do not exist in the sliced expiration frame for the selected price column (bid/ask/last). The offending strikes are embedded in the message so you can see which values failed to match.

Source

Thrown at openbb_platform/core/openbb_core/provider/utils/options_chains_properties.py:741

            short = True

        strike_price = abs(strike)  # type: ignore
        bid_ask = "bid" if short else "ask"
        call_price_col = self._identify_price_col(chains, "call", bid_ask)  # type: ignore
        put_price_col = self._identify_price_col(chains, "put", bid_ask)  # type: ignore
        call_strike_estimate = self._get_nearest_strike("call", days, strike_price, call_price_col, force_otm)  # type: ignore
        # If a strike price is supplied, the put strike is the same as the call strike.
        # Otherwise, the put strike is the nearest OTM put strike to the last price.

        put_strike_estimate = self._get_nearest_strike("put", days, strike_price, put_price_col, force_otm)  # type: ignore
        call_premium = chains[chains.strike == call_strike_estimate].query("`option_type` == 'call'")[  # type: ignore
            call_price_col
        ]
        put_premium = chains[chains.strike == put_strike_estimate].query("`option_type` == 'put'")[  # type: ignore
            put_price_col
        ]
        if call_premium.empty or put_premium.empty:
            raise OpenBBError(
                "Error: No premium data found for the selected strikes."
                f" Call: {call_strike_estimate}, Put: {put_strike_estimate}"
            )
        put_premium = put_premium.values[0]
        call_premium = call_premium.values[0]
        dte = chains[chains.expiration.astype(str) == dte_estimate]["dte"].unique()[0]  # type: ignore
        straddle_cost = call_premium + put_premium  # type: ignore
        straddle_dict: dict = {}

        # Includes the as-of date if it is historical EOD data.
        if hasattr(chains, "eod_date"):
            straddle_dict.update({"Date": chains.eod_date.iloc[0]})

        straddle_dict.update(
            {
                "Symbol": chains.underlying_symbol.unique()[0],
                "Underlying Price": underlying_price,
                "Expiration": dte_estimate,

View on GitHub (pinned to 3e071fcc2c)

Solutions

  1. Pass an explicit strike_price that exists in chains.strikes (e.g. chains.strikes nearest value) instead of relying on auto-estimation.
  2. Try a different days value so a different expiration (with denser quotes) is selected: straddle(days=60).
  3. Inspect the slice before calling: chains.dataframe[chains.dataframe.expiration.astype(str) == chains._get_nearest_expiration(days)] and verify both 'call' and 'put' rows exist at the estimated strikes.
  4. If the price column (bid/ask) is all-NaN for those strikes, switch providers (e.g. cboe/yfinance) or patch the missing quotes so _identify_price_col finds usable values.

Example fix

# before
res = chains.straddle(days=30)  # raises: no premium at estimated strikes

# after
import numpy as np
strikes = np.array(chains.strikes)
explicit = strikes[min(range(len(strikes)), key=lambda i: abs(strikes[i] - chains.last_price))]
res = chains.straddle(days=30, strike=explicit)
Defensive patterns

Strategy: validation

Validate before calling

df = chains.dataframe
exp = chains._get_nearest_expiration(days)
slice_ = df[df['expiration'].astype(str) == exp]
col = chains._identify_price_col(slice_, 'call', 'last_price')
strikes = set(slice_[slice_.option_type == 'call'].strike)
assert any(s in strikes for s in [target_strike]), 'call premium rows missing at strike'

Type guard

def has_premium_at(df, strike: float, option_type: str, col: str) -> bool:
    rows = df[(df.strike == strike) & (df.option_type == option_type)]
    return not rows.empty and rows[col].notna().any() and (rows[col] > 0).any()

Try / catch

from openbb_core.app.model.abstract.error import OpenBBError
try:
    chains.straddle(days=30)
except OpenBBError as e:
    if 'No premium data found' in str(e):
        # retry with nearest listed strike
        ...

Prevention

When it happens

Trigger: Calling obb.derivatives.options.chains(...).straddle() (or chains.dataframe-based straddle) where the nearest-expiration slice has no call row at call_strike_estimate or no put row at put_strike_estimate for the price column chosen by _identify_price_col (e.g. 'bid'/'ask' columns present but NaN/absent for those strikes, or strike-price rounding mismatch between providers).

Common situations: Using a provider whose chain is sparse at the estimated ATM strikes; passing an explicit strike_price that does not exist in the chain (e.g. 152.5 when strikes are in 5-point increments); Illiquid symbols with one-sided quotes; filtering the chains DataFrame before calling straddle so the matched rows were removed.

Related errors


AI-assisted analysis of OpenBB-finance/OpenBB@3e071fcc2c (2026-08-14). Data as JSON: /api/errors/4d6ddbe86b1a033c. Report an issue: GitHub.