Skip to content

Commit

Permalink
[BugFix] Fix Seeking Alpha (#6461)
Browse files Browse the repository at this point in the history
* fix seeking alpha

* try again sequence

* prevent key error

* move value check up the sequence

* filter test cassette more

---------

Co-authored-by: Igor Radovanovic <74266147+IgorWounds@users.noreply.github.com>
  • Loading branch information
deeleeramone and IgorWounds committed May 25, 2024
1 parent aefd921 commit 5ff4d89
Show file tree
Hide file tree
Showing 15 changed files with 1,490 additions and 438 deletions.

This file was deleted.

42 changes: 23 additions & 19 deletions openbb_platform/extensions/equity/integration/test_equity_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,14 @@ def test_equity_calendar_splits(params, headers):
({"start_date": "2023-11-09", "end_date": "2023-11-10", "provider": "fmp"}),
({"start_date": "2023-11-09", "end_date": "2023-11-10", "provider": "nasdaq"}),
({"start_date": "2023-11-09", "end_date": "2023-11-10", "provider": "tmx"}),
(
{
"start_date": None,
"end_date": None,
"provider": "seeking_alpha",
"country": "us",
}
),
],
)
@pytest.mark.integration
Expand Down Expand Up @@ -397,7 +405,14 @@ def test_equity_estimates_historical(params, headers):
"calendar_period": None,
"provider": "intrinio",
}
)
),
(
{
"symbol": "AAPL,BAM:CA",
"period": "annual",
"provider": "seeking_alpha",
}
),
],
)
@pytest.mark.integration
Expand Down Expand Up @@ -434,6 +449,13 @@ def test_equity_estimates_forward_sales(params, headers):
"provider": "fmp",
}
),
(
{
"symbol": "AAPL,BAM:CA",
"period": "annual",
"provider": "seeking_alpha",
}
),
],
)
@pytest.mark.integration
Expand Down Expand Up @@ -1652,24 +1674,6 @@ def test_equity_discovery_top_retail(params, headers):
assert result.status_code == 200


@parametrize(
"params",
[({"provider": "seeking_alpha"})],
)
@pytest.mark.integration
def test_equity_discovery_upcoming_release_days(params, headers):
"""Test the equity discovery upcoming release days endpoint."""
params = {p: v for p, v in params.items() if v}

query_str = get_querystring(params, [])
url = (
f"http://0.0.0.0:8000/api/v1/equity/discovery/upcoming_release_days?{query_str}"
)
result = requests.get(url, headers=headers, timeout=30)
assert isinstance(result, requests.Response)
assert result.status_code == 200


@parametrize(
"params",
[
Expand Down
39 changes: 23 additions & 16 deletions openbb_platform/extensions/equity/integration/test_equity_python.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,14 @@ def test_equity_calendar_splits(params, obb):
({"start_date": "2023-11-09", "end_date": "2023-11-10", "provider": "fmp"}),
({"start_date": "2023-11-09", "end_date": "2023-11-10", "provider": "nasdaq"}),
({"start_date": "2023-11-09", "end_date": "2023-11-10", "provider": "tmx"}),
(
{
"start_date": None,
"end_date": None,
"provider": "seeking_alpha",
"country": "us",
}
),
],
)
@pytest.mark.integration
Expand Down Expand Up @@ -705,7 +713,14 @@ def test_equity_estimates_consensus(params, obb):
"calendar_period": None,
"provider": "intrinio",
}
)
),
(
{
"symbol": "AAPL,BAM:CA",
"period": "annual",
"provider": "seeking_alpha",
}
),
],
)
@pytest.mark.integration
Expand Down Expand Up @@ -739,6 +754,13 @@ def test_equity_estimates_forward_sales(params, obb):
"provider": "fmp",
}
),
(
{
"symbol": "AAPL,BAM:CA",
"period": "annual",
"provider": "seeking_alpha",
}
),
],
)
@pytest.mark.integration
Expand Down Expand Up @@ -1570,21 +1592,6 @@ def test_equity_discovery_top_retail(params, obb):
assert len(result.results) > 0


@parametrize(
"params",
[({"provider": "seeking_alpha"})],
)
@pytest.mark.integration
def test_equity_discovery_upcoming_release_days(params, obb):
"""Test the equity discovery upcoming release days endpoint."""
params = {p: v for p, v in params.items() if v}

result = obb.equity.discovery.upcoming_release_days(**params)
assert result
assert isinstance(result, OBBject)
assert len(result.results) > 0


@parametrize(
"params",
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,20 +152,6 @@ async def top_retail(
return await OBBject.from_query(Query(**locals()))


@router.command(
model="UpcomingReleaseDays",
examples=[APIEx(parameters={"provider": "seeking_alpha"})],
)
async def upcoming_release_days(
cc: CommandContext,
provider_choices: ProviderChoices,
standard_params: StandardParams,
extra_params: ExtraParams,
) -> OBBject:
"""Get upcoming earnings release dates."""
return await OBBject.from_query(Query(**locals()))


@router.command(
model="DiscoveryFilings",
examples=[
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
"""Seeking Alpha Provider module."""

from openbb_core.provider.abstract.provider import Provider
from openbb_seeking_alpha.models.upcoming_release_days import (
SAUpcomingReleaseDaysFetcher,
from openbb_seeking_alpha.models.calendar_earnings import SACalendarEarningsFetcher
from openbb_seeking_alpha.models.forward_eps_estimates import (
SAForwardEpsEstimatesFetcher,
)
from openbb_seeking_alpha.models.forward_sales_estimates import (
SAForwardSalesEstimatesFetcher,
)

seeking_alpha_provider = Provider(
Expand All @@ -11,7 +15,9 @@
description="""Seeking Alpha is a data provider with access to news, analysis, and
real-time alerts on stocks.""",
fetcher_dict={
"UpcomingReleaseDays": SAUpcomingReleaseDaysFetcher,
"CalendarEarnings": SACalendarEarningsFetcher,
"ForwardEpsEstimates": SAForwardEpsEstimatesFetcher,
"ForwardSalesEstimates": SAForwardSalesEstimatesFetcher,
},
repr_name="Seeking Alpha",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
"""Seeking Alpha Calendar Earnings Model."""

# pylint: disable=unused-argument

import asyncio
import json
from datetime import datetime, timedelta
from typing import Any, Dict, List, Literal, Optional
from warnings import warn

from openbb_core.provider.abstract.fetcher import Fetcher
from openbb_core.provider.standard_models.calendar_earnings import (
CalendarEarningsData,
CalendarEarningsQueryParams,
)
from openbb_core.provider.utils.helpers import amake_request
from openbb_seeking_alpha.utils.helpers import HEADERS, date_range
from pydantic import Field, field_validator


class SACalendarEarningsQueryParams(CalendarEarningsQueryParams):
"""Seeking Alpha Calendar Earnings Query.
Source: https://seekingalpha.com/earnings/earnings-calendar
"""

country: Literal["us", "ca"] = Field(
default="us",
description="The country to get calendar data for.",
json_schema_extra={"choices": ["us", "ca"]},
)


class SACalendarEarningsData(CalendarEarningsData):
"""Seeking Alpha Calendar Earnings Data."""

market_cap: Optional[float] = Field(
default=None,
description="Market cap of the entity.",
)
reporting_time: Optional[str] = Field(
default=None,
description="The reporting time - e.g. after market close.",
)
exchange: Optional[str] = Field(
default=None,
description="The primary trading exchange.",
)
sector_id: Optional[int] = Field(
default=None,
description="The Seeking Alpha Sector ID.",
)

@field_validator("report_date", mode="before", check_fields=False)
@classmethod
def validate_release_date(cls, v):
"""Validate the release date."""
v = v.split("T")[0]
return datetime.strptime(v, "%Y-%m-%d").date()


class SACalendarEarningsFetcher(
Fetcher[
SACalendarEarningsQueryParams,
List[SACalendarEarningsData],
]
):
"""Seeking Alpha Calendar Earnings Fetcher."""

@staticmethod
def transform_query(params: Dict[str, Any]) -> SACalendarEarningsQueryParams:
"""Transform the query."""
now = datetime.today().date()
transformed_params = params
if not params.get("start_date"):
transformed_params["start_date"] = now
if not params.get("end_date"):
transformed_params["end_date"] = now + timedelta(days=3)
return SACalendarEarningsQueryParams(**transformed_params)

@staticmethod
async def aextract_data(
query: SACalendarEarningsQueryParams,
credentials: Optional[Dict[str, str]],
**kwargs: Any,
) -> List[Dict]:
"""Return the raw data from the Seeking Alpha endpoint."""
results: List[Dict] = []
dates = [
date.strftime("%Y-%m-%d")
for date in date_range(query.start_date, query.end_date)
]
currency = "USD" if query.country == "us" else "CAD"
messages: List = []

async def get_date(date, currency):
"""Get date for one date."""
url = (
f"https://seekingalpha.com/api/v3/earnings_calendar/tickers?"
f"filter%5Bselected_date%5D={date}"
f"&filter%5Bwith_rating%5D=false&filter%5Bcurrency%5D={currency}"
)
response = await amake_request(url=url, headers=HEADERS)
# Try again if the response is blocked.
if "blockScript" in response:
response = await amake_request(url=url, headers=HEADERS)
if "blockScript" in response:
message = json.dumps(response)
messages.append(message)
warn(message)
if "data" in response:
results.extend(response.get("data"))

await asyncio.gather(*[get_date(date, currency) for date in dates])

if not results:
raise RuntimeError(f"Error with the Seeking Alpha request -> {messages}")

return results

@staticmethod
def transform_data(
query: SACalendarEarningsQueryParams,
data: List[Dict],
**kwargs: Any,
) -> List[SACalendarEarningsData]:
"""Transform the data to the standard format."""
transformed_data: List[SACalendarEarningsData] = []
for row in sorted(data, key=lambda x: x["attributes"]["release_date"]):
attributes = row.get("attributes", {})
transformed_data.append(
SACalendarEarningsData.model_validate(
{
"report_date": attributes.get("release_date"),
"reporting_time": attributes.get("release_time"),
"symbol": attributes.get("slug"),
"name": attributes.get("name"),
"market_cap": attributes.get("marketcap"),
"exchange": attributes.get("exchange"),
"sector_id": attributes.get("sector_id"),
}
)
)
return transformed_data
Loading

0 comments on commit 5ff4d89

Please sign in to comment.