{"record":{"id":"af2ee7c4101e2fa8","repo":"OpenBB-finance/OpenBB","slug":"error-no-premium-data-found-for-the-selected-stri-af2ee7","errorCode":null,"errorMessage":"Error: No premium data found for the selected strikes. Call: {bought}, Put: {sold}","messagePattern":"Error: No premium data found for the selected strikes\\. Call: (.+?), Put: (.+?)","errorType":"exception","errorClass":"OpenBBError","httpStatus":null,"severity":"error","filePath":"openbb_platform/core/openbb_core/provider/utils/options_chains_properties.py","lineNumber":1260,"sourceCode":"            days = -1\n\n        dte_estimate = self._get_nearest_expiration(days)\n        chains = DataFrame(chains[chains[\"expiration\"].astype(str) == dte_estimate])\n        last_price = (\n            underlying_price\n            if underlying_price is not None\n            else chains.underlying_price.iloc[0]\n        )\n        bid = self._identify_price_col(chains, \"put\", \"bid\")\n        ask = self._identify_price_col(chains, \"call\", \"ask\")\n        strike_price = last_price if strike == 0 else strike\n        sold = self._get_nearest_strike(\"put\", days, strike_price, bid, False)\n        bought = self._get_nearest_strike(\"call\", days, strike_price, ask, False)\n        put_premium = chains[chains.strike == sold].query(\"`option_type` == 'put'\")[bid]  # type: ignore\n        call_premium = chains[chains.strike == bought].query(\"`option_type` == 'call'\")[ask]  # type: ignore\n\n        if call_premium.empty or put_premium.empty:\n            raise OpenBBError(\n                f\"Error: No premium data found for the selected strikes. Call: {bought}, Put: {sold}\"\n            )\n\n        put_premium = put_premium.values[0] * (-1)\n        call_premium = call_premium.values[0]\n        dte = chains[chains.expiration.astype(str) == dte_estimate][\"dte\"].unique()[0]  # type: ignore\n        position_cost = call_premium + put_premium\n        breakeven = ((sold + bought) / 2) + position_cost  # type: ignore\n        synthetic_long_dict: dict = {}\n        # Includes the as-of date if it is historical EOD data.\n        if hasattr(chains, \"eod_date\"):\n            synthetic_long_dict.update({\"Date\": chains.eod_date.iloc[0]})\n\n        synthetic_long_dict.update(\n            {\n                \"Symbol\": chains.underlying_symbol.unique()[0],\n                \"Underlying Price\": last_price,\n                \"Expiration\": dte_estimate,","sourceCodeStart":1242,"sourceCodeEnd":1278,"githubUrl":"https://github.com/OpenBB-finance/OpenBB/blob/3e071fcc2cd9f891cac6040ae60296dba76dab46/openbb_platform/core/openbb_core/provider/utils/options_chains_properties.py#L1242-L1278","documentation":"Raised by OptionsChainsData.synthetic_long() when the put premium lookup at the sold put strike (bid column) or the call premium lookup at the bought call strike (ask column) returns an empty series in the expiration slice. Both legs must be quotable to compute position cost and breakeven.","triggerScenarios":"Calling chains.synthetic_long(...) where the expiration chosen by _get_nearest_expiration has no 'put' row at the estimated put strike in the bid column, or no 'call' row at the call strike in the ask column; commonly when bid or ask columns are missing so _identify_price_col falls back to a column that is empty for those rows.","commonSituations":"Providers that report last_price only (no bid/ask) at ATM strikes; sparse single-sided quotes on illiquid symbols; strike rounding mismatch (e.g. estimated 152.55 vs listed 152.5).","solutions":["Pass an explicit strike that exists in chains.strikes.","Switch to another expiration (days=) with denser quotes.","Use a provider that supplies both bid and ask columns (e.g. cboe/deribit).","Inspect the slice and confirm both legs exist before calling."],"exampleFix":"# before\nres = chains.synthetic_long(days=30)  # empty call/put premium at estimated strikes\n\n# after\nres = chains.synthetic_long(days=30, strike=152.5, underlying_price=spot)","handlingStrategy":"validation","validationCode":"df = chains.dataframe\nexp = chains._get_nearest_expiration(days)\ns = df[df['expiration'].astype(str) == exp]\nassert not s.query(\"option_type == 'call'\")[ask_col].dropna().empty, 'no call ask'\nassert not s.query(\"option_type == 'put'\")[bid_col].dropna().empty, 'no put bid'","typeGuard":"def legs_quotable(df, call_k, put_k) -> bool:\n    c = df[(df.strike == call_k) & (df.option_type == 'call')]\n    p = df[(df.strike == put_k) & (df.option_type == 'put')]\n    return not c.empty and not p.empty","tryCatchPattern":"try:\n    chains.synthetic_long(days=days)\nexcept OpenBBError as e:\n    if 'No premium data found' in str(e):\n        chains.synthetic_long(days=days, strike=nearest_listed_strike, underlying_price=spot)","preventionTips":["Verify bid (puts) and ask (calls) coverage at the target strikes before building synthetics.","Snap strikes to listed values."],"tags":["options","pandas","openbb","data-quality"],"backgroundTag":null,"analyzedSha":"3e071fcc2cd9f891cac6040ae60296dba76dab46","analyzedAt":"2026-08-14T23:40:48.960Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}