mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-28 04:52:07 +00:00
Merge branch 'develop' into feature/james-didier-feedback
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import argparse
|
||||
import inspect
|
||||
import re
|
||||
from copy import deepcopy
|
||||
from enum import Enum
|
||||
from typing import (
|
||||
@@ -21,6 +22,8 @@ from openbb_core.app.model.field import OpenBBField
|
||||
from pydantic import BaseModel, model_validator
|
||||
from typing_extensions import Annotated
|
||||
|
||||
# pylint: disable=protected-access
|
||||
|
||||
SEP = "__"
|
||||
|
||||
|
||||
@@ -200,7 +203,7 @@ class ArgparseTranslator:
|
||||
self.func = func
|
||||
self.signature = inspect.signature(func)
|
||||
self.type_hints = get_type_hints(func)
|
||||
self.provider_parameters = []
|
||||
self.provider_parameters: List[str] = []
|
||||
|
||||
self._parser = argparse.ArgumentParser(
|
||||
prog=func.__name__,
|
||||
@@ -217,23 +220,95 @@ class ArgparseTranslator:
|
||||
for group in custom_argument_groups:
|
||||
argparse_group = self._parser.add_argument_group(group.name)
|
||||
for argument in group.arguments:
|
||||
kwargs = argument.model_dump(exclude={"name"}, exclude_none=True)
|
||||
self._handle_argument_in_groups(argument, argparse_group)
|
||||
|
||||
# If the argument is already in use, we can't repeat it
|
||||
if f"--{argument.name}" not in self._parser_arguments():
|
||||
argparse_group.add_argument(f"--{argument.name}", **kwargs)
|
||||
self.provider_parameters.append(argument.name)
|
||||
def _handle_argument_in_groups(self, argument, group):
|
||||
"""Handle the argument and add it to the parser."""
|
||||
|
||||
def _parser_arguments(self) -> List[str]:
|
||||
"""Get all the arguments from all groups currently defined on the parser."""
|
||||
arguments_in_use: List[str] = []
|
||||
def _in_optional_arguments(arg):
|
||||
for action_group in self._parser._action_groups:
|
||||
if action_group.title == "optional arguments":
|
||||
for action in action_group._group_actions:
|
||||
opts = action.option_strings
|
||||
if (opts and opts[0] == arg) or action.dest == arg:
|
||||
return True
|
||||
return False
|
||||
|
||||
# pylint: disable=protected-access
|
||||
for action_group in self._parser._action_groups:
|
||||
for action in action_group._group_actions:
|
||||
arguments_in_use.extend(action.option_strings)
|
||||
def _remove_argument(arg) -> List[Optional[str]]:
|
||||
groups_w_arg = []
|
||||
|
||||
return arguments_in_use
|
||||
# remove the argument from the parser
|
||||
for action in self._parser._actions:
|
||||
opts = action.option_strings
|
||||
if (opts and opts[0] == arg) or action.dest == arg:
|
||||
self._parser._remove_action(action)
|
||||
break
|
||||
|
||||
# remove from all groups
|
||||
for action_group in self._parser._action_groups:
|
||||
for action in action_group._group_actions:
|
||||
opts = action.option_strings
|
||||
if (opts and opts[0] == arg) or action.dest == arg:
|
||||
action_group._group_actions.remove(action)
|
||||
groups_w_arg.append(action_group.title)
|
||||
|
||||
# remove from _action_groups dict
|
||||
self._parser._option_string_actions.pop(f"--{arg}", None)
|
||||
|
||||
return groups_w_arg
|
||||
|
||||
def _get_arg_choices(arg) -> Tuple:
|
||||
for action in self._parser._actions:
|
||||
opts = action.option_strings
|
||||
if (opts and opts[0] == arg) or action.dest == arg:
|
||||
return tuple(action.choices or ())
|
||||
return ()
|
||||
|
||||
def _update_providers(
|
||||
input_string: str, new_provider: List[Optional[str]]
|
||||
) -> str:
|
||||
pattern = r"\(provider:\s*(.*?)\)"
|
||||
providers = re.findall(pattern, input_string)
|
||||
providers.extend(new_provider)
|
||||
# remove pattern from help and add with new providers
|
||||
input_string = re.sub(pattern, "", input_string).strip()
|
||||
return f"{input_string} (provider: {', '.join(providers)})"
|
||||
|
||||
# check if the argument is already in use, if not, add it
|
||||
if f"--{argument.name}" not in self._parser._option_string_actions:
|
||||
kwargs = argument.model_dump(exclude={"name"}, exclude_none=True)
|
||||
group.add_argument(f"--{argument.name}", **kwargs)
|
||||
self.provider_parameters.append(argument.name)
|
||||
|
||||
else:
|
||||
kwargs = argument.model_dump(exclude={"name"}, exclude_none=True)
|
||||
model_choices = kwargs.get("choices", ()) or ()
|
||||
# extend choices
|
||||
choices = tuple(set(_get_arg_choices(argument.name) + model_choices))
|
||||
|
||||
# check if the argument is in the optional arguments
|
||||
if _in_optional_arguments(argument.name):
|
||||
for action in self._parser._actions:
|
||||
if action.dest == argument.name:
|
||||
# update choices
|
||||
action.choices = choices
|
||||
# update help
|
||||
action.help = _update_providers(
|
||||
action.help or "", [group.title]
|
||||
)
|
||||
return
|
||||
|
||||
# if the argument is in use, remove it from all groups
|
||||
# and return the groups that had the argument
|
||||
groups_w_arg = _remove_argument(argument.name)
|
||||
groups_w_arg.append(group.title) # add current group
|
||||
|
||||
# add it to the optional arguments group instead
|
||||
if choices:
|
||||
kwargs["choices"] = choices # update choices
|
||||
# add provider info to the help
|
||||
kwargs["help"] = _update_providers(argument.help or "", groups_w_arg)
|
||||
self._parser.add_argument(f"--{argument.name}", **kwargs)
|
||||
|
||||
@property
|
||||
def parser(self) -> argparse.ArgumentParser:
|
||||
|
||||
@@ -908,11 +908,6 @@ class BaseController(metaclass=ABCMeta):
|
||||
|
||||
if "--help" in other_args or "-h" in other_args:
|
||||
txt_help = parser.format_help() + "\n"
|
||||
if parser.prog != "about":
|
||||
txt_help += (
|
||||
f"For more information and examples, use 'about {parser.prog}' "
|
||||
f"to access the related guide.\n"
|
||||
)
|
||||
session.console.print(f"[help]{txt_help}[/help]")
|
||||
return None
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ class OptionsChainsQueryParams(QueryParams):
|
||||
|
||||
symbol: str = Field(description=QUERY_DESCRIPTIONS.get("symbol", ""))
|
||||
|
||||
@classmethod
|
||||
@field_validator("symbol", mode="before", check_fields=False)
|
||||
@classmethod
|
||||
def to_upper(cls, v: str) -> str:
|
||||
"""Return the symbol in uppercase."""
|
||||
return v.upper()
|
||||
|
||||
@@ -10,6 +10,7 @@ from openbb_cboe.utils.helpers import (
|
||||
get_company_directory,
|
||||
get_index_directory,
|
||||
)
|
||||
from openbb_core.provider.abstract.annotated_result import AnnotatedResult
|
||||
from openbb_core.provider.abstract.fetcher import Fetcher
|
||||
from openbb_core.provider.standard_models.options_chains import (
|
||||
OptionsChainsData,
|
||||
@@ -62,10 +63,9 @@ class CboeOptionsChainsFetcher(
|
||||
query: CboeOptionsChainsQueryParams,
|
||||
credentials: Optional[Dict[str, str]],
|
||||
**kwargs: Any,
|
||||
) -> List[Dict]:
|
||||
"""Return the raw data from the Cboe endpoint"""
|
||||
|
||||
symbol = query.symbol.replace("^", "").split(",")[0]
|
||||
) -> Dict:
|
||||
"""Return the raw data from the Cboe endpoint."""
|
||||
symbol = query.symbol.replace("^", "").split(",")[0].upper()
|
||||
INDEXES = await get_index_directory(use_cache=query.use_cache)
|
||||
SYMBOLS = await get_company_directory(use_cache=query.use_cache)
|
||||
INDEXES = INDEXES.set_index("index_symbol")
|
||||
@@ -78,21 +78,57 @@ class CboeOptionsChainsFetcher(
|
||||
if symbol in TICKER_EXCEPTIONS or symbol in INDEXES.index
|
||||
else f"https://cdn.cboe.com/api/global/delayed_quotes/options/{symbol}.json"
|
||||
)
|
||||
|
||||
return await amake_request(quotes_url)
|
||||
results = await amake_request(quotes_url)
|
||||
return results # type: ignore
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
query: CboeOptionsChainsQueryParams,
|
||||
data: List[Dict],
|
||||
data: Dict,
|
||||
**kwargs: Any,
|
||||
) -> List[CboeOptionsChainsData]:
|
||||
"""Transform the data to the standard format"""
|
||||
|
||||
) -> AnnotatedResult[List[CboeOptionsChainsData]]:
|
||||
"""Transform the data to the standard format."""
|
||||
if not data:
|
||||
raise EmptyDataError()
|
||||
results_metadata = {}
|
||||
options = data.get("data", {}).pop("options", [])
|
||||
change_percent = data["data"].get("percent_change", None)
|
||||
iv30_percent = data["data"].get("iv30_change_percent", None)
|
||||
if change_percent:
|
||||
change_percent = change_percent / 100
|
||||
if iv30_percent:
|
||||
iv30_percent = iv30_percent / 100
|
||||
last_timestamp = data["data"].get("last_trade_time", None)
|
||||
if last_timestamp:
|
||||
last_timestamp = to_datetime(
|
||||
last_timestamp, format="%Y-%m-%dT%H:%M:%S"
|
||||
).strftime("%Y-%m-%d %H:%M:%S")
|
||||
results_metadata.update(
|
||||
{
|
||||
"symbol": data["data"].get("symbol"),
|
||||
"security_type": data["data"].get("security_type", None),
|
||||
"bid": data["data"].get("bid", None),
|
||||
"bid_size": data["data"].get("bid_size", None),
|
||||
"ask": data["data"].get("ask", None),
|
||||
"ask_size": data["data"].get("ask_size", None),
|
||||
"open": data["data"].get("open", None),
|
||||
"high": data["data"].get("high", None),
|
||||
"low": data["data"].get("low", None),
|
||||
"close": data["data"].get("close", None),
|
||||
"volume": data["data"].get("volume", None),
|
||||
"current_price": data["data"].get("current_price", None),
|
||||
"prev_close": data["data"].get("prev_day_close", None),
|
||||
"change": data["data"].get("price_change", None),
|
||||
"change_percent": change_percent,
|
||||
"iv30": data["data"].get("iv30", None),
|
||||
"iv30_change": data["data"].get("iv30_change", None),
|
||||
"iv30_change_percent": iv30_percent,
|
||||
"last_tick": data["data"].get("tick", None),
|
||||
"last_trade_timestamp": last_timestamp,
|
||||
}
|
||||
)
|
||||
|
||||
options_df = DataFrame.from_records(data["data"]["options"])
|
||||
options_df = DataFrame.from_records(options)
|
||||
|
||||
options_df = options_df.rename(
|
||||
columns={
|
||||
@@ -152,7 +188,10 @@ class CboeOptionsChainsFetcher(
|
||||
quotes["prev_close"] = round(quotes["prev_close"], 2)
|
||||
quotes["change_percent"] = round(quotes["change_percent"] / 100, 4)
|
||||
|
||||
return [
|
||||
CboeOptionsChainsData.model_validate(d)
|
||||
for d in quotes.reset_index().to_dict("records")
|
||||
]
|
||||
return AnnotatedResult(
|
||||
result=[
|
||||
CboeOptionsChainsData.model_validate(d)
|
||||
for d in quotes.reset_index().to_dict("records")
|
||||
],
|
||||
metadata=results_metadata,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user