Skip to content

Commit

Permalink
Merge pull request #276 from RomelTorres/develop
Browse files Browse the repository at this point in the history
Prep for 2.3.0
  • Loading branch information
PatrickAlphaC committed Dec 21, 2020
2 parents ac0fb7e + 65c7670 commit b904374
Show file tree
Hide file tree
Showing 12 changed files with 1,072 additions and 23 deletions.
11 changes: 11 additions & 0 deletions .deepsource.toml
@@ -0,0 +1,11 @@
version = 1

test_patterns = ["test_alpha_vantage/**"]

[[analyzers]]
name = "python"
enabled = true

[analyzers.meta]
runtime_version = "3.x.x"

1 change: 1 addition & 0 deletions README.md
Expand Up @@ -14,6 +14,7 @@ For code-less access to the APIs, you may also consider the official [Google She

## News

* From version 2.3.0 onwards, fundamentals data and extended intraday is supported.
* From version 2.2.0 onwards, asyncio support now provided. See below for more information.
* From version 2.1.3 onwards, [rapidAPI](https://rapidapi.com/alphavantage/api/alpha-vantage-alpha-vantage-default) key integration is now available.
* From version 2.1.0 onwards, error logging of bad API calls has been made more apparent.
Expand Down
36 changes: 29 additions & 7 deletions alpha_vantage/alphavantage.py
Expand Up @@ -219,7 +219,11 @@ def _format_wrapper(self, *args, **kwargs):
self, *args, **kwargs)
if 'json' in self.output_format.lower() or 'pandas' \
in self.output_format.lower():
data = call_response[data_key]
if data_key is not None:
data = call_response[data_key]
else:
data = call_response


if meta_data_key is not None:
meta_data = call_response[meta_data_key]
Expand All @@ -232,18 +236,36 @@ def _format_wrapper(self, *args, **kwargs):
output_format = override.lower()
# Choose output format
if output_format == 'json':
return data, meta_data
if isinstance(data, list):
# If the call returns a list, then we will append them
# in the resulting data frame. If in the future
# alphavantage decides to do more with returning arrays
# this might become buggy. For now will do the trick.
if not data:
data_pandas = pandas.DataFrame()
else:
data_array = []
for val in data:
data_array.append([v for _, v in val.items()])
data_pandas = pandas.DataFrame(data_array, columns=[
k for k, _ in data[0].items()])
return data_pandas, meta_data
else:
return data, meta_data
elif output_format == 'pandas':
if isinstance(data, list):
# If the call returns a list, then we will append them
# in the resulting data frame. If in the future
# alphavantage decides to do more with returning arrays
# this might become buggy. For now will do the trick.
data_array = []
for val in data:
data_array.append([v for _, v in val.items()])
data_pandas = pandas.DataFrame(data_array, columns=[
k for k, _ in data[0].items()])
if not data:
data_pandas = pandas.DataFrame()
else:
data_array = []
for val in data:
data_array.append([v for _, v in val.items()])
data_pandas = pandas.DataFrame(data_array, columns=[
k for k, _ in data[0].items()])
else:
try:
data_pandas = pandas.DataFrame.from_dict(data,
Expand Down
29 changes: 21 additions & 8 deletions alpha_vantage/cryptocurrencies.py
Expand Up @@ -60,17 +60,30 @@ def get_digital_currency_monthly(self, symbol, market):

@av._output_format
@av._call_api_on_func
def get_digital_currency_exchange_rate(self, symbol, market):
""" Returns the current exchange rate for a digital currency
(e.g., BTC) traded on a specific market (e.g., CNY/Chinese Yuan),
and when it was last updated.
def get_digital_currency_exchange_rate(self, from_currency, to_currency):
""" Returns the realtime exchange rate for any pair of digital
currency (e.g., BTC) or physical currency (e.g., USD).
Keyword Arguments:
from_currency: The currency you would like to get the exchange rate
for. It can either be a physical currency or digital/crypto currency.
For example: from_currency=USD or from_currency=BTC.
to_currency: The destination currency for the exchange rate.
It can either be a physical currency or digital/crypto currency.
For example: to_currency=USD or to_currency=BTC.
"""
_FUNCTION_KEY = 'CURRENCY_EXCHANGE_RATE'
return _FUNCTION_KEY, 'Realtime Currency Exchange Rate', None

@av._output_format
@av._call_api_on_func
def get_digital_crypto_rating(self, symbol):
""" Returns the Fundamental Crypto Asset Score for a digital currency
(e.g., BTC), and when it was last updated.
Keyword Arguments:
symbol: The digital/crypto currency of your choice. It can be any
of the currencies in the digital currency list. For example:
symbol=BTC.
market: The exchange market of your choice. It can be any of the
market in the market list. For example: market=CNY.
"""
_FUNCTION_KEY = 'CURRENCY_EXCHANGE_RATE'
return _FUNCTION_KEY, 'Dictonary (Digital Currency Exchange Rate)', 'Meta Data'
_FUNCTION_KEY = 'CRYPTO_RATING'
return _FUNCTION_KEY, 'Crypto Rating (FCAS)', None
117 changes: 117 additions & 0 deletions alpha_vantage/fundamentaldata.py
@@ -0,0 +1,117 @@
from .alphavantage import AlphaVantage as av

from datetime import datetime
search_date = datetime.now().date().strftime('%Y-%m-%d')

class FundamentalData(av):

"""This class implements all the api calls to fundamental data
"""
def __init__(self, *args, **kwargs):
"""
Inherit AlphaVantage base class with its default arguments.
"""
super(FundamentalData, self).__init__(*args, **kwargs)
self._append_type = False
if self.output_format.lower() == 'csv':
raise ValueError("Output format {} is not compatible with the FundamentalData class".format(
self.output_format.lower()))

@av._output_format
@av._call_api_on_func
def get_company_overview(self, symbol):
"""
Returns the company information, financial ratios,
and other key metrics for the equity specified.
Data is generally refreshed on the same day a company reports its latest
earnings and financials.
Keyword Arguments:
symbol: the symbol for the equity we want to get its data
"""
_FUNCTION_KEY = 'OVERVIEW'
return _FUNCTION_KEY, None, None

@av._output_format
@av._call_api_on_func
def get_income_statement_annual(self, symbol):
"""
Returns the annual and quarterly income statements for the company of interest.
Data is generally refreshed on the same day a company reports its latest
earnings and financials.
Keyword Arguments:
symbol: the symbol for the equity we want to get its data
"""
_FUNCTION_KEY = 'INCOME_STATEMENT'
return _FUNCTION_KEY, 'annualReports', 'symbol'

@av._output_format
@av._call_api_on_func
def get_income_statement_quarterly(self, symbol):
"""
Returns the annual and quarterly income statements for the company of interest.
Data is generally refreshed on the same day a company reports its latest
earnings and financials.
Keyword Arguments:
symbol: the symbol for the equity we want to get its data
"""
_FUNCTION_KEY = 'INCOME_STATEMENT'
return _FUNCTION_KEY, 'quarterlyReports', 'symbol'

@av._output_format
@av._call_api_on_func
def get_balance_sheet_annual(self, symbol):
"""
Returns the annual and quarterly balance sheets for the company of interest.
Data is generally refreshed on the same day a company reports its latest
earnings and financials.
Keyword Arguments:
symbol: the symbol for the equity we want to get its data
"""
_FUNCTION_KEY = 'BALANCE_SHEET'
return _FUNCTION_KEY, 'annualReports', 'symbol'

@av._output_format
@av._call_api_on_func
def get_balance_sheet_quarterly(self, symbol):
"""
Returns the annual and quarterly balance sheets for the company of interest.
Data is generally refreshed on the same day a company reports its latest
earnings and financials.
Keyword Arguments:
symbol: the symbol for the equity we want to get its data
"""
_FUNCTION_KEY = 'BALANCE_SHEET'
return _FUNCTION_KEY, 'quarterlyReports', 'symbol'

@av._output_format
@av._call_api_on_func
def get_cash_flow_annual(self, symbol):
"""
Returns the annual and quarterly cash flows for the company of interest.
Data is generally refreshed on the same day a company reports its latest
earnings and financials.
Keyword Arguments:
symbol: the symbol for the equity we want to get its data
"""
_FUNCTION_KEY = 'CASH_FLOW'
return _FUNCTION_KEY, 'annualReports', 'symbol'

@av._output_format
@av._call_api_on_func
def get_cash_flow_quarterly(self, symbol):
"""
Returns the annual and quarterly cash flows for the company of interest.
Data is generally refreshed on the same day a company reports its latest
earnings and financials.
Keyword Arguments:
symbol: the symbol for the equity we want to get its data
"""
_FUNCTION_KEY = 'CASH_FLOW'
return _FUNCTION_KEY, 'quarterlyReports', 'symbol'
19 changes: 18 additions & 1 deletion alpha_vantage/timeseries.py
Expand Up @@ -24,6 +24,23 @@ def get_intraday(self, symbol, interval='15min', outputsize='compact'):
_FUNCTION_KEY = "TIME_SERIES_INTRADAY"
return _FUNCTION_KEY, "Time Series ({})".format(interval), 'Meta Data'

@av._output_format
@av._call_api_on_func
def get_intraday_extended(self, symbol, interval='15min', slice='year1month1'):
""" Return extended intraday time series in one csv_reader object.
It raises ValueError when problems arise
Keyword Arguments:
symbol: the symbol for the equity we want to get its data
interval: time interval between two conscutive values,
supported values are '1min', '5min', '15min', '30min', '60min'
(default '15min')
slice: the trailing 2 years of intraday data is evenly divided into
24 "slices" - year1month1, year1month2, ..., year2month12
"""
_FUNCTION_KEY = "TIME_SERIES_INTRADAY_EXTENDED"
return _FUNCTION_KEY, "Time Series ({})".format(interval), 'Meta Data'

@av._output_format
@av._call_api_on_func
def get_daily(self, symbol, outputsize='compact'):
Expand Down Expand Up @@ -115,7 +132,7 @@ def get_monthly_adjusted(self, symbol):
@av._call_api_on_func
def get_quote_endpoint(self, symbol):
""" Return the latest price and volume information for a
security of your choice
security of your choice
Keyword Arguments:
symbol: the symbol for the equity we want to get its data
Expand Down
4 changes: 2 additions & 2 deletions docs/conf.py
Expand Up @@ -55,9 +55,9 @@
# built documents.
#
# The short X.Y version.
version = u'2.2.0'
version = u'2.3.0'
# The full version, including alpha/beta/rc tags.
release = u'2.2.0'
release = u'2.3.0'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
6 changes: 3 additions & 3 deletions setup.py
Expand Up @@ -4,14 +4,14 @@

here = path.abspath(path.dirname(__file__))
try:
with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
long_description = f.read()
with open("README.md", "r") as fh:
long_description = fh.read()
except IOError:
long_description = 'Python module to get stock data from the Alpha Vantage Api'

setup(
name='alpha_vantage',
version='2.2.0',
version='2.3.0',
author='Romel J. Torres',
author_email='romel.torres@gmail.com',
license='MIT',
Expand Down
25 changes: 25 additions & 0 deletions test_alpha_vantage/test_alphavantage.py
Expand Up @@ -4,6 +4,7 @@
from ..alpha_vantage.techindicators import TechIndicators
from ..alpha_vantage.sectorperformance import SectorPerformances
from ..alpha_vantage.foreignexchange import ForeignExchange
from ..alpha_vantage.fundamentaldata import FundamentalData

from pandas import DataFrame as df, Timestamp

Expand Down Expand Up @@ -200,3 +201,27 @@ def test_foreign_exchange(self, mock_request):
from_currency='BTC', to_currency='CNY')
self.assertIsInstance(
data, dict, 'Result Data must be a dictionary')

@requests_mock.Mocker()
def test_fundamental_data(self, mock_request):
"""Test that api call returns a json file as requested
"""
fd = FundamentalData(key=TestAlphaVantage._API_KEY_TEST)
url = 'https://www.alphavantage.co/query?function=INCOME_STATEMENT&symbol=IBM&apikey=test'
path_file = self.get_file_from_url("mock_fundamental_data")
with open(path_file) as f:
mock_request.get(url, text=f.read())
data, _ = fd.get_income_statement_annual(symbol='IBM')
self.assertIsInstance(data, df, 'Result Data must be a pandas data frame')

@requests_mock.Mocker()
def test_company_overview(self, mock_request):
"""Test that api call returns a json file as requested
"""
fd = FundamentalData(key=TestAlphaVantage._API_KEY_TEST)
url = "https://www.alphavantage.co/query?function=OVERVIEW&symbol=IBM&apikey=test"
path_file = self.get_file_from_url("mock_company_overview")
with open(path_file) as f:
mock_request.get(url, text=f.read())
data, _ = fd.get_company_overview(symbol='IBM')
self.assertIsInstance(data, dict, 'Result Data must be a dictionary')
61 changes: 61 additions & 0 deletions test_alpha_vantage/test_data/mock_company_overview
@@ -0,0 +1,61 @@
{
"Symbol": "IBM",
"AssetType": "Common Stock",
"Name": "International Business Machines Corporation",
"Description": "International Business Machines Corporation operates as an integrated solutions and services company worldwide. Its Cloud & Cognitive Software segment offers software for vertical and domain-specific solutions in health, financial services, and Internet of Things (IoT), weather, and security software and services application areas; and customer information control system and storage, and analytics and integration software solutions to support client mission critical on-premise workloads in banking, airline, and retail industries. It also offers middleware and data platform software, including Red Hat, which enables the operation of clients' hybrid multi-cloud environments; and Cloud Paks, WebSphere distributed, and analytics platform software, such as DB2 distributed, information integration, and enterprise content management, as well as IoT, Blockchain and AI/Watson platforms. The company's Global Business Services segment offers business consulting services; system integration, application management, maintenance, and support services for packaged software; finance, procurement, talent and engagement, and industry-specific business process outsourcing services; and IT infrastructure and platform services. Its Global Technology Services segment provides project, managed, outsourcing, and cloud-delivered services for enterprise IT infrastructure environments; and IT infrastructure support services. The company's Systems segment offers servers for businesses, cloud service providers, and scientific computing organizations; data storage products and solutions; and z/OS, an enterprise operating system, as well as Linux. Its Global Financing segment provides lease, installment payment, loan financing, short-term working capital financing, and remanufacturing and remarketing services. The company was formerly known as Computing-Tabulating-Recording Co. and changed its name to International Business Machines Corporation in 1924. The company was founded in 1911 and is headquartered in Armonk, New York.",
"Exchange": "NYSE",
"Currency": "USD",
"Country": "USA",
"Sector": "Technology",
"Industry": "Information Technology Services",
"Address": "One New Orchard Road, Armonk, NY, United States, 10504",
"FullTimeEmployees": "352600",
"FiscalYearEnd": "December",
"LatestQuarter": "2020-06-30",
"MarketCapitalization": "114234572800",
"EBITDA": "15576999936",
"PERatio": "14.1327",
"PEGRatio": "8.7525",
"BookValue": "23.076",
"DividendPerShare": "6.52",
"DividendYield": "0.0529",
"EPS": "8.811",
"RevenuePerShareTTM": "85.058",
"ProfitMargin": "0.1043",
"OperatingMarginTTM": "0.1185",
"ReturnOnAssetsTTM": "0.0362",
"ReturnOnEquityTTM": "0.4097",
"RevenueTTM": "75499003904",
"GrossProfitTTM": "36489000000",
"DilutedEPSTTM": "8.811",
"QuarterlyEarningsGrowthYOY": "-0.458",
"QuarterlyRevenueGrowthYOY": "-0.054",
"AnalystTargetPrice": "135.19",
"TrailingPE": "14.1327",
"ForwardPE": "11.2867",
"PriceToSalesRatioTTM": "1.4762",
"PriceToBookRatio": "5.4017",
"EVToRevenue": "2.2076",
"EVToEBITDA": "11.0349",
"Beta": "1.2071",
"52WeekHigh": "158.75",
"52WeekLow": "90.56",
"50DayMovingAverage": "124.9097",
"200DayMovingAverage": "122.2713",
"SharesOutstanding": "890579008",
"SharesFloat": "889189445",
"SharesShort": "21600483",
"SharesShortPriorMonth": "23242369",
"ShortRatio": "4.51",
"ShortPercentOutstanding": "0.02",
"ShortPercentFloat": "0.0243",
"PercentInsiders": "0.108",
"PercentInstitutions": "58.555",
"ForwardAnnualDividendRate": "6.52",
"ForwardAnnualDividendYield": "0.0529",
"PayoutRatio": "0.7358",
"DividendDate": "2020-09-10",
"ExDividendDate": "2020-08-07",
"LastSplitFactor": "2:1",
"LastSplitDate": "1999-05-27"
}

0 comments on commit b904374

Please sign in to comment.