{"record":{"id":"aebfa8f1c5d49636","repo":"OpenBB-finance/OpenBB","slug":"error-moneyness-must-be-expressed-as-a-percentage","errorCode":null,"errorMessage":"Error: Moneyness must be expressed as a percentage between 0 and 100","messagePattern":"Error: Moneyness must be expressed as a percentage between 0 and 100","errorType":"exception","errorClass":"OpenBBError","httpStatus":null,"severity":"error","filePath":"openbb_platform/core/openbb_core/provider/utils/options_chains_properties.py","lineNumber":545,"sourceCode":"        underlying_price: Optional[float]\n            Only supply this is if the underlying price is not a returned field.\n\n        Returns\n        -------\n        Dict[str, float]\n            Dictionary of the upper (call) and lower (put) strike prices.\n        \"\"\"\n        # pylint: disable=import-outside-toplevel\n        from pandas import Series\n\n        if moneyness is None:\n            moneyness = 0.25\n\n        if 0 < moneyness < 100:\n            moneyness = moneyness / 100\n\n        if moneyness > 100 or moneyness < 0:\n            raise OpenBBError(\n                \"Error: Moneyness must be expressed as a percentage between 0 and 100\"\n            )\n\n        df = self.dataframe\n\n        if underlying_price is None and not hasattr(df, \"underlying_price\"):\n            raise OpenBBError(\n                \"Error: underlying_price must be provided if underlying_price is not available\"\n            )\n\n        if date is not None:\n            date = self._get_nearest_expiration(date)\n            df = df[df.expiration.astype(str) == date]\n            strikes = Series(df.strike.unique().tolist())\n\n        last_price = (\n            underlying_price\n            if underlying_price is not None","sourceCodeStart":527,"sourceCodeEnd":563,"githubUrl":"https://github.com/OpenBB-finance/OpenBB/blob/3e071fcc2cd9f891cac6040ae60296dba76dab46/openbb_platform/core/openbb_core/provider/utils/options_chains_properties.py#L527-L563","documentation":"Raised in OptionsChainsData._get_nearest_otm_strikes (used for ITM/OTM strike boundaries). moneyness is a percentage: values in (0, 100) exclusive are divided by 100 to a fraction; a value > 100 or < 0 after that normalization raises this error. Note the edge: exactly 0 or exactly 100 are accepted as-is (0 stays 0), and passing 0.25 means 0.25% because 0<0.25<100 triggers /100.","triggerScenarios":"Calling methods that take moneyness= (e.g. filter_data(moneyness=...)) with 250 (meaning 2.5x), -5, or a fraction intended as already-normalized like 0.25 (which gets re-interpreted as 0.25%). Values above 100 after no division, like moneyness=150, raise.","commonSituations":"Confusion between percent (25) and fraction (0.25) conventions; passing monetary strike offsets or multipliers instead of percentages.","solutions":["Pass the value as a percent in (0, 100): moneyness=25 for 25%","Do not pass fractions — 0.25 is treated as 0.25%, not 25%","Clamp/validate user input on your side to 0 < moneyness < 100 before the call"],"exampleFix":"# before\nstrikes = res.filter_data(moneyness=0.25)  # treated as 0.25%, not 25%; 250 would raise\n\n# after\nstrikes = res.filter_data(moneyness=25)  # 25 percent","handlingStrategy":"validation","validationCode":"def normalize_moneyness(m) -> float:\n    if m is None:\n        return 25.0\n    if not 0 < m < 100 and m not in (0, 100):\n        raise ValueError(\"moneyness must be a percent in [0, 100]\")\n    return m\n\nmoneyness = normalize_moneyness(user_moneyness)","typeGuard":"def is_valid_moneyness(m) -> bool:\n    return isinstance(m, (int, float)) and 0 <= m <= 100","tryCatchPattern":"from openbb_core.app.model.abstract.error import OpenBBError\n\ntry:\n    strikes = res.filter_data(moneyness=moneyness)\nexcept OpenBBError as e:\n    if \"Moneyness must be expressed\" in str(e):\n        strikes = res.filter_data(moneyness=25)  # default 25 percent\n    else:\n        raise","preventionTips":["Always express moneyness in percent units (25 = 25%), never as a 0-1 fraction","Validate/clamp user input to 0-100 at the form boundary","Remember the default is 0.25 (i.e. 0.25%) when omitted — pass 25 explicitly for a quarter-window"],"tags":["options","moneyness","validation","derivatives"],"backgroundTag":null,"analyzedSha":"3e071fcc2cd9f891cac6040ae60296dba76dab46","analyzedAt":"2026-08-14T23:40:48.960Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}