From a742cb36113f3b2e470a4f20438fa78a9c607658 Mon Sep 17 00:00:00 2001 From: Ray Garcia Date: Wed, 28 Jun 2023 09:33:37 -0500 Subject: [PATCH 1/2] added method to get earnings calendar --- alphavantage_api_client/__init__.py | 2 +- alphavantage_api_client/client.py | 25 ++++++++++++++++++- alphavantage_api_client/models.py | 12 +++++++++ tests/test_single_client_cache_integration.py | 20 ++++++++++++++- 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/alphavantage_api_client/__init__.py b/alphavantage_api_client/__init__.py index 4f5bfd7..1df935c 100644 --- a/alphavantage_api_client/__init__.py +++ b/alphavantage_api_client/__init__.py @@ -1,4 +1,4 @@ from alphavantage_api_client.client import AlphavantageClient from alphavantage_api_client.models import GlobalQuote, Quote, AccountingReport, CompanyOverview, RealGDP, \ - CsvNotSupported, TickerSearch, MarketStatus, MarketMovers, NewsAndSentiment + CsvNotSupported, TickerSearch, MarketStatus, MarketMovers, NewsAndSentiment, EarningsCalendar, EarningsCalendarItem from alphavantage_api_client.ticker import Ticker diff --git a/alphavantage_api_client/client.py b/alphavantage_api_client/client.py index 5411152..7dd8690 100644 --- a/alphavantage_api_client/client.py +++ b/alphavantage_api_client/client.py @@ -6,11 +6,12 @@ from .response_validation_rules import ValidationRuleChecks import json from alphavantage_api_client.models import GlobalQuote, Quote, AccountingReport, CompanyOverview, RealGDP, \ - CsvNotSupported, TickerSearch, MarketStatus, NewsAndSentiment, MarketMovers + CsvNotSupported, TickerSearch, MarketStatus, NewsAndSentiment, MarketMovers, EarningsCalendar import copy import logging import hashlib from typing import Optional, Union +import csv class ApiKeyNotFound(Exception): @@ -681,6 +682,28 @@ def get_top_gainers_and_losers(self) -> MarketMovers: return MarketMovers.parse_obj(json_response) + def get_earnings_calendar(self, event: dict) -> EarningsCalendar: + """ + This API returns a list of company earnings expected in the next 3, 6, or 12 months. + Returns: + + """ + defaults = { + "function": "EARNINGS_CALENDAR", + "horizon": "3month", + "datatype": "csv" + } + json_request = self.__create_api_request_from__(defaults, event) + json_response = self.get_data_from_alpha_vantage(json_request, self.__retry__) + records = json_response['csv'].split("\n") + header = records.pop(0) + headers = header.split(",") + reader = csv.DictReader(records, delimiter=',') + reader.fieldnames = headers + items = list(reader) + json_response['data'] = items + + return EarningsCalendar.parse_obj(json_response) def get_news_and_sentiment(self, event: dict) -> NewsAndSentiment: """ diff --git a/alphavantage_api_client/models.py b/alphavantage_api_client/models.py index 272cc98..6d68ae4 100644 --- a/alphavantage_api_client/models.py +++ b/alphavantage_api_client/models.py @@ -43,6 +43,18 @@ class MarketMovers(BaseResponse): meta_data: Optional[str] = Field(str, alias='metadata') most_actively_traded: list[dict] +class EarningsCalendarItem(BaseModel): + symbol: str + name: str + report_date: str = Field(str,alias='reportDate') + fiscal_date_ending: str = Field(str,alias='fiscalDateEnding') + estimate: Optional[float] + currency: Optional[str] + +class EarningsCalendar(BaseResponse): + symbol: str + data: Optional[list[EarningsCalendarItem]] = Field([]) + class Quote(BaseQuote): """ data is this clients abstraction of the response from alpha vantage. Time Series, Technical Indicator diff --git a/tests/test_single_client_cache_integration.py b/tests/test_single_client_cache_integration.py index 7e2e0a3..7623dd0 100644 --- a/tests/test_single_client_cache_integration.py +++ b/tests/test_single_client_cache_integration.py @@ -4,7 +4,7 @@ , NewsAndSentiment import logging import json - +import csv client = AlphavantageClient().should_retry_once().use_simple_cache() @@ -529,3 +529,21 @@ def test_get_market_movers(): assert "change_amount" in item, "change_amount not found within result" assert "change_percentage" in item, "change_percentage not found within result" assert "volume" in item, "volume not found within result" + +@pytest.mark.integration +def test_get_earnings_calendar(): + symbols = ["IBM", "AAPL", "AMZN", "MSFT", "TSLA"] + + for symbol in symbols: + event = { + "symbol": symbol + } + earnings_calendar = client.get_earnings_calendar(event) + assert earnings_calendar.success, f"success was found to be True which is unexpected: {earnings_calendar.error_message}" + assert not earnings_calendar.limit_reached, f"limit_reached is true {earnings_calendar.error_message}" + assert len(earnings_calendar.csv), "csv is not defined within response" + assert len(earnings_calendar.data), "data is not defined within response" + + for item in earnings_calendar.data: + print(item.json()) + From d36c31a1ee8943fc8282d02e157246be5b972af4 Mon Sep 17 00:00:00 2001 From: Ray Garcia Date: Wed, 28 Jun 2023 09:59:58 -0500 Subject: [PATCH 2/2] added method to get ipo calendar --- alphavantage_api_client/__init__.py | 3 +- alphavantage_api_client/client.py | 25 +++++++++++++- alphavantage_api_client/models.py | 12 +++++++ tests/test_single_client_cache_integration.py | 33 ++++++++++++++++++- 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/alphavantage_api_client/__init__.py b/alphavantage_api_client/__init__.py index 1df935c..7f0faa2 100644 --- a/alphavantage_api_client/__init__.py +++ b/alphavantage_api_client/__init__.py @@ -1,4 +1,5 @@ from alphavantage_api_client.client import AlphavantageClient from alphavantage_api_client.models import GlobalQuote, Quote, AccountingReport, CompanyOverview, RealGDP, \ - CsvNotSupported, TickerSearch, MarketStatus, MarketMovers, NewsAndSentiment, EarningsCalendar, EarningsCalendarItem + CsvNotSupported, TickerSearch, MarketStatus, MarketMovers, NewsAndSentiment, EarningsCalendar\ + , EarningsCalendarItem,IpoCalendarItem, IpoCalendar from alphavantage_api_client.ticker import Ticker diff --git a/alphavantage_api_client/client.py b/alphavantage_api_client/client.py index 7dd8690..8190687 100644 --- a/alphavantage_api_client/client.py +++ b/alphavantage_api_client/client.py @@ -6,7 +6,8 @@ from .response_validation_rules import ValidationRuleChecks import json from alphavantage_api_client.models import GlobalQuote, Quote, AccountingReport, CompanyOverview, RealGDP, \ - CsvNotSupported, TickerSearch, MarketStatus, NewsAndSentiment, MarketMovers, EarningsCalendar + CsvNotSupported, TickerSearch, MarketStatus, NewsAndSentiment, MarketMovers, EarningsCalendar\ + , IpoCalendarItem, IpoCalendar import copy import logging import hashlib @@ -705,6 +706,28 @@ def get_earnings_calendar(self, event: dict) -> EarningsCalendar: return EarningsCalendar.parse_obj(json_response) + def get_ipo_calendar(self) -> IpoCalendar: + """ + This API returns a list of company earnings expected in the next 3, 6, or 12 months. + Returns: + + """ + json_request = { + "function": "IPO_CALENDAR", + "datatype": "csv" + } + + json_response = self.get_data_from_alpha_vantage(json_request, self.__retry__) + records = json_response['csv'].split("\n") + header = records.pop(0) + headers = header.split(",") + reader = csv.DictReader(records, delimiter=',') + reader.fieldnames = headers + items = list(reader) + json_response['data'] = items + + return IpoCalendar.parse_obj(json_response) + def get_news_and_sentiment(self, event: dict) -> NewsAndSentiment: """ Looking for market news signals to augment your trading strategy, or a global news diff --git a/alphavantage_api_client/models.py b/alphavantage_api_client/models.py index 6d68ae4..e4c2ad1 100644 --- a/alphavantage_api_client/models.py +++ b/alphavantage_api_client/models.py @@ -51,6 +51,18 @@ class EarningsCalendarItem(BaseModel): estimate: Optional[float] currency: Optional[str] +class IpoCalendarItem(BaseModel): + symbol: str + name: str + ipo_date: str = Field(str,alias="ipoDate") + price_range_low: Optional[float] = Field(float, alias="priceRangeLow") + price_range_high: Optional[float] = Field(float, alias="priceRangeHigh") + currency: Optional[str] + exchange: Optional[str] + +class IpoCalendar(BaseResponse): + data: Optional[list[IpoCalendarItem]] = Field([]) + class EarningsCalendar(BaseResponse): symbol: str data: Optional[list[EarningsCalendarItem]] = Field([]) diff --git a/tests/test_single_client_cache_integration.py b/tests/test_single_client_cache_integration.py index 7623dd0..4572264 100644 --- a/tests/test_single_client_cache_integration.py +++ b/tests/test_single_client_cache_integration.py @@ -532,7 +532,7 @@ def test_get_market_movers(): @pytest.mark.integration def test_get_earnings_calendar(): - symbols = ["IBM", "AAPL", "AMZN", "MSFT", "TSLA"] + symbols = ["IBM", "AAPL", "AMZN", "MSFT", "TSLA", "SYM"] for symbol in symbols: event = { @@ -547,3 +547,34 @@ def test_get_earnings_calendar(): for item in earnings_calendar.data: print(item.json()) +@pytest.mark.integration +def test_get_earnings_calendar(): + symbols = ["IBM", "AAPL", "AMZN", "MSFT", "TSLA", "SYM"] + + for symbol in symbols: + event = { + "symbol": symbol + } + earnings_calendar = client.get_earnings_calendar(event) + assert earnings_calendar.success, f"success was found to be True which is unexpected: {earnings_calendar.error_message}" + assert not earnings_calendar.limit_reached, f"limit_reached is true {earnings_calendar.error_message}" + assert len(earnings_calendar.csv), "csv is not defined within response" + assert len(earnings_calendar.data), "data is not defined within response" + + for item in earnings_calendar.data: + print(item.json()) + +def test_get_ipo_calendar(): + + ipo_calendar = client.get_ipo_calendar() + assert ipo_calendar.success, f"success was found to be True which is unexpected: {ipo_calendar.error_message}" + assert not ipo_calendar.limit_reached, f"limit_reached is true {ipo_calendar.error_message}" + assert len(ipo_calendar.csv), "csv is not defined within response" + assert len(ipo_calendar.data), "data is not defined within response" + + for item in ipo_calendar.data: + assert len(item.symbol), "csv is not defined within response" + assert len(item.ipo_date), "ipo_date is not defined within response" + assert len(item.name), "name is not defined within response" + +