Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BugFix] Fix Seeking Alpha #6461

Merged
merged 6 commits into from
May 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

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
Loading