Skip to content

Commit

Permalink
feature/standardize-quote: Proposal to Standardize EquityQuote (#5922)
Browse files Browse the repository at this point in the history
* standardize EquityQuote

* intrinio reference

* rogue comma

* pylint

---------

Co-authored-by: Igor Radovanovic <74266147+IgorWounds@users.noreply.github.com>
  • Loading branch information
deeleeramone and IgorWounds authored Jan 9, 2024
1 parent af8dbe4 commit 873e9a5
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class EquityQuoteQueryParams(QueryParams):

symbol: str = Field(
description=QUERY_DESCRIPTIONS.get("symbol", "")
+ " In this case, the comma separated list of symbols."
+ " This endpoint will accept multiple symbols separated by commas."
)

@field_validator("symbol", mode="before", check_fields=False)
Expand All @@ -33,14 +33,125 @@ def upper_symbol(cls, v: Union[str, List[str], Set[str]]):
class EquityQuoteData(Data):
"""Equity Quote Data."""

day_low: Optional[float] = Field(
symbol: str = Field(description=DATA_DESCRIPTIONS.get("symbol", ""))
asset_type: Optional[str] = Field(
default=None, description="Type of asset - i.e, stock, ETF, etc."
)
name: Optional[str] = Field(
default=None, description="Name of the company or asset."
)
exchange: Optional[str] = Field(
default=None,
description="The name or symbol of the venue where the data is from.",
)
bid: Optional[float] = Field(
default=None, description="Price of the top bid order."
)
bid_size: Optional[int] = Field(
default=None,
description="This represents the number of round lot orders at the given price."
+ " The normal round lot size is 100 shares."
+ " A size of 2 means there are 200 shares available at the given price.",
)
bid_exchange: Optional[str] = Field(
default=None,
description="The specific trading venue where the purchase order was placed.",
)
ask: Optional[float] = Field(
default=None, description="Price of the top ask order."
)
ask_size: Optional[int] = Field(
default=None,
description="This represents the number of round lot orders at the given price."
+ " The normal round lot size is 100 shares."
+ " A size of 2 means there are 200 shares available at the given price.",
)
ask_exchange: Optional[str] = Field(
default=None,
description="The specific trading venue where the sale order was placed.",
)
quote_conditions: Optional[Union[str, int, List[str], List[int]]] = Field(
default=None,
description="Conditions or condition codes applicable to the quote.",
)
quote_indicators: Optional[Union[str, int, List[str], List[int]]] = Field(
default=None,
description="Indicators or indicator codes applicable to the participant"
+ " quote related to the price bands for the issue, or the affect the quote has"
+ " on the NBBO.",
)
sales_conditions: Optional[Union[str, int, List[str], List[int]]] = Field(
default=None,
description="Conditions or condition codes applicable to the sale.",
)
sequence_number: Optional[int] = Field(
default=None,
description="The sequence number represents the sequence in which message events happened."
+ " These are increasing and unique per ticker symbol,"
+ " but will not always be sequential (e.g., 1, 2, 6, 9, 10, 11).",
)
market_center: Optional[str] = Field(
default=None,
description="The ID of the UTP participant that originated the message.",
)
participant_timestamp: Optional[datetime] = Field(
default=None,
description="Lowest price of the stock in the current trading day.",
description="Timestamp for when the quote was generated by the exchange.",
)
day_high: Optional[float] = Field(
trf_timestamp: Optional[datetime] = Field(
default=None,
description="Highest price of the stock in the current trading day.",
description="Timestamp for when the TRF (Trade Reporting Facility) received the message.",
)
sip_timestamp: Optional[datetime] = Field(
default=None,
description="Timestamp for when the SIP (Security Information Processor)"
+ " received the message from the exchange.",
)
last_price: Optional[float] = Field(
default=None, description="Price of the last trade."
)
last_tick: Optional[str] = Field(
default=None, description="Whether the last sale was an up or down tick."
)
last_size: Optional[int] = Field(
default=None, description="Size of the last trade."
)
last_timestamp: Optional[datetime] = Field(
default=None, description="Date and Time when the last price was recorded."
)
open: Optional[float] = Field(
default=None, description=DATA_DESCRIPTIONS.get("open", "")
)
high: Optional[float] = Field(
default=None, description=DATA_DESCRIPTIONS.get("high", "")
)
low: Optional[float] = Field(
default=None, description=DATA_DESCRIPTIONS.get("low", "")
)
close: Optional[float] = Field(
default=None, description=DATA_DESCRIPTIONS.get("close", "")
)
volume: Optional[Union[int, float]] = Field(
default=None, description=DATA_DESCRIPTIONS.get("volume", "")
)
exchange_volume: Optional[Union[int, float]] = Field(
default=None,
description="Volume of shares exchanged during the trading day on the specific exchange.",
)
prev_close: Optional[float] = Field(
default=None, description=DATA_DESCRIPTIONS.get("prev_close", "")
)
change: Optional[float] = Field(
default=None, description="Change in price from previous close."
)
change_percent: Optional[float] = Field(
default=None,
description="Change in price as a normalized percentage.",
json_schema_extra={"x-frontendmultiply": 100},
)
year_high: Optional[float] = Field(
default=None, description="The one year high (52W High)."
)
date: Optional[datetime] = Field(
description=DATA_DESCRIPTIONS.get("date", ""), default=None
year_low: Optional[float] = Field(
default=None, description="The one year low (52W Low)."
)
93 changes: 40 additions & 53 deletions openbb_platform/providers/fmp/openbb_fmp/models/equity_quote.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""FMP Equity Quote Model."""

from datetime import datetime
from typing import Any, Dict, List, Optional
from datetime import datetime, timezone
from typing import Any, Dict, List, Optional, Union

from openbb_core.provider.abstract.data import ForceInt
from openbb_core.provider.abstract.fetcher import Fetcher
Expand All @@ -27,71 +27,58 @@ class FMPEquityQuoteData(EquityQuoteData):
__alias_dict__ = {
"price_avg50": "priceAvg50",
"price_avg200": "priceAvg200",
"date": "timestamp",
"last_timestamp": "timestamp",
"high": "dayHigh",
"low": "dayLow",
"last_price": "price",
"change_percent": "changesPercentage",
"prev_close": "previousClose",
}

symbol: Optional[str] = Field(default=None, description="Symbol of the company.")
name: Optional[str] = Field(default=None, description="Name of the company.")
price: Optional[float] = Field(
default=None, description="Current trading price of the equity."
)
changes_percentage: Optional[float] = Field(
default=None, description="Change percentage of the equity price."
)
change: Optional[float] = Field(
default=None, description="Change in the equity price."
)
year_high: Optional[float] = Field(
default=None, description="Highest price of the equity in the last 52 weeks."
)
year_low: Optional[float] = Field(
default=None, description="Lowest price of the equity in the last 52 weeks."
)
market_cap: Optional[float] = Field(
default=None, description="Market cap of the company."
)
price_avg50: Optional[float] = Field(
default=None, description="50 days average price of the equity."
default=None, description="50 day moving average price."
)
price_avg200: Optional[float] = Field(
default=None, description="200 days average price of the equity."
)
volume: Optional[ForceInt] = Field(
default=None,
description="Volume of the equity in the current trading day.",
default=None, description="200 day moving average price."
)
avg_volume: Optional[ForceInt] = Field(
default=None,
description="Average volume of the equity in the last 10 trading days.",
)
exchange: Optional[str] = Field(
default=None, description="Exchange the equity is traded on."
description="Average volume over the last 10 trading days.",
)
open: Optional[float] = Field(
default=None,
description="Opening price of the equity in the current trading day.",
)
previous_close: Optional[float] = Field(
default=None, description="Previous closing price of the equity."
)
eps: Optional[float] = Field(
default=None, description="Earnings per share of the equity."
)
pe: Optional[float] = Field(
default=None, description="Price earnings ratio of the equity."
)
earnings_announcement: Optional[str] = Field(
default=None, description="Earnings announcement date of the equity."
market_cap: Optional[float] = Field(
default=None, description="Market cap of the company."
)
shares_outstanding: Optional[ForceInt] = Field(
default=None, description="Number of shares outstanding of the equity."
default=None, description="Number of shares outstanding."
)
eps: Optional[float] = Field(default=None, description="Earnings per share.")
pe: Optional[float] = Field(default=None, description="Price earnings ratio.")
earnings_announcement: Optional[Union[datetime, str]] = Field(
default=None, description="Upcoming earnings announcement date."
)

@field_validator("timestamp", mode="before", check_fields=False)
@field_validator("last_timestamp", mode="before", check_fields=False)
@classmethod
def date_validate(cls, v): # pylint: disable=E0213
def validate_last_timestamp(cls, v): # pylint: disable=E0213
"""Return the date as a datetime object."""
return datetime.strptime(v, "%Y-%m-%d")
v = int(v) if isinstance(v, str) else v
return datetime.utcfromtimestamp(int(v)).replace(tzinfo=timezone.utc)

@field_validator("earnings_announcement", mode="before", check_fields=False)
@classmethod
def timestamp_validate(cls, v): # pylint: disable=E0213
"""Return the datetime string as a datetime object."""
if v:
dt = datetime.strptime(v, "%Y-%m-%dT%H:%M:%S.%f%z")
dt = dt.replace(microsecond=0)
timestamp = dt.timestamp()
return datetime.fromtimestamp(timestamp, tz=timezone.utc)
return None

@field_validator("change_percent", mode="after", check_fields=False)
@classmethod
def normalize_percent(cls, v): # pylint: disable=E0213
"""Return the percent value as a normalized value."""
return float(v) / 100 if v else None


class FMPEquityQuoteFetcher(
Expand Down
Loading

0 comments on commit 873e9a5

Please sign in to comment.