-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #25 from AndrewRPorter/refactor_and_remove_python_…
…2_support Refactor and remove python 2 support
- Loading branch information
Showing
8 changed files
with
116 additions
and
144 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ | |
setup( | ||
name="yahoo_historical", | ||
packages=["yahoo_historical"], | ||
version="0.4.1", | ||
version="1.0.0", | ||
description="Fetches historical EOD (end of day) prices from yahoo finance", | ||
author="Andrew Porter", | ||
author_email="[email protected]", | ||
|
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
from yahoo_historical import Fetcher | ||
import datetime | ||
import time | ||
|
||
TEST_TICKER = "AAPL" | ||
TIME_START = time.mktime(datetime.datetime(2007, 1, 1).timetuple()) | ||
TIME_END = time.mktime(datetime.datetime(2017, 1, 1).timetuple()) | ||
|
||
|
||
def test_get_no_dataframe(): | ||
data = Fetcher(TEST_TICKER, TIME_START, TIME_END).get_historical(as_dataframe=False) | ||
assert len(data) > 0 | ||
|
||
|
||
def test_get_with_lowercase(): | ||
data = Fetcher(TEST_TICKER.lower(), TIME_START, TIME_END).get_historical() | ||
assert len(data) > 0 | ||
|
||
|
||
def test_get_historical(): | ||
data = Fetcher(TEST_TICKER, TIME_START, TIME_END).get_historical() | ||
assert len(data) > 0 | ||
|
||
|
||
def test_get_dividends(): | ||
data = Fetcher(TEST_TICKER, TIME_START, TIME_END).get_dividends() | ||
assert len(data) > 0 | ||
|
||
|
||
def test_get_splits(): | ||
data = Fetcher(TEST_TICKER, TIME_START, TIME_END).get_splits() | ||
assert len(data) > 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
from yahoo_historical.fetch import Fetcher | ||
from .fetch import Fetcher # noqa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
API_URL = "https://query1.finance.yahoo.com/v7/finance/download/%s?period1=%s&period2=%s&interval=%s&events=%s" | ||
ONE_DAY_INTERVAL = "1d" | ||
ONE_WEEK_INTERVAL = "1wk" | ||
ONE_MONTH_INTERVAL = "1mo" | ||
|
||
DATE_INTERVALS = [ONE_DAY_INTERVAL, ONE_WEEK_INTERVAL, ONE_MONTH_INTERVAL] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,103 +1,75 @@ | ||
import calendar as cal | ||
import datetime as dt | ||
from typing import Union | ||
import time | ||
import warnings | ||
|
||
import pandas as pd | ||
import requests | ||
|
||
try: | ||
from io import StringIO | ||
except ImportError: | ||
from StringIO import StringIO | ||
from io import StringIO | ||
from .constants import API_URL, DATE_INTERVALS, ONE_DAY_INTERVAL | ||
|
||
|
||
class Fetcher: | ||
api_url = "https://query1.finance.yahoo.com/v7/finance/download/%s?period1=%s&period2=%s&interval=%s&events=%s" | ||
|
||
def __init__(self, ticker, start, end=None, interval="1d"): | ||
"""Initializes class variables and formats api_url string""" | ||
def __init__( | ||
self, | ||
ticker: str, | ||
start: Union[int, float], | ||
end: Union[int, float] = time.time(), | ||
interval: str = ONE_DAY_INTERVAL, | ||
): | ||
self.ticker = ticker.upper() | ||
self.interval = interval | ||
self.start = int(cal.timegm(dt.datetime(*start).timetuple())) | ||
|
||
if end is not None: | ||
self.end = int(cal.timegm(dt.datetime(*end).timetuple())) | ||
else: | ||
self.end = int(time.time()) | ||
# we convert the unix timestamps to int here to avoid sending floats to yahoo finance API | ||
# as the API will reject the call for an invalid type | ||
self.start = int(start) | ||
self.end = int(end) | ||
|
||
def create_url(self, event: str) -> str: | ||
"""Generate a URL for a particular event. | ||
Args: | ||
event (str): event type to query for ('history', 'div', 'split') | ||
def _get(self, events): | ||
if self.interval not in ["1d", "1wk", "1mo"]: | ||
raise ValueError("Incorrect interval: valid intervals are 1d, 1wk, 1mo") | ||
Returns: | ||
str: formatted URL for an API call | ||
""" | ||
return API_URL % (self.ticker, self.start, self.end, self.interval, event) | ||
|
||
url = self.api_url % (self.ticker, self.start, self.end, self.interval, events) | ||
def _get(self, event: str, as_dataframe=True) -> Union[pd.DataFrame, dict]: | ||
"""Private helper function to build URL and make API request to grab data | ||
Args: | ||
event (str): kind of data we want to query (history, div, split) | ||
as_dataframe (bool, optional): whether or not to return data as a pandas DataFrame. Defaults to True. | ||
Raises: | ||
ValueError: if invalid interval is supplied | ||
Returns: | ||
Union[pd.DataFrame, dict]: data from yahoo finance API call | ||
""" | ||
if self.interval not in DATE_INTERVALS: | ||
raise ValueError( | ||
f"Incorrect interval: valid intervals are {', '.join(DATE_INTERVALS)}" | ||
) | ||
|
||
url = self.create_url(event) | ||
# yahoo finance rejects our API request without an empty user agent | ||
data = requests.get(url, headers={"User-agent": ""}) | ||
content = StringIO(data.content.decode("utf-8")) | ||
return pd.read_csv(content, sep=",") | ||
|
||
def getData(self, events): | ||
"""Returns a list of historical data from Yahoo Finance""" | ||
warnings.warn( | ||
"getData has been deprecated, use get_data instead", DeprecationWarning | ||
) | ||
return self._get(events) | ||
dataframe = pd.read_csv(content, sep=",") | ||
if as_dataframe: | ||
return dataframe | ||
|
||
def getHistorical(self): | ||
return dataframe.to_json() | ||
|
||
def get_historical(self, as_dataframe=True): | ||
"""Returns a list of historical price data from Yahoo Finance""" | ||
warnings.warn( | ||
"getHistorical has been deprecated, use get_historical instead", | ||
DeprecationWarning, | ||
) | ||
return self._get("history") | ||
return self._get("history", as_dataframe=as_dataframe) | ||
|
||
def getDividends(self): | ||
def get_dividends(self, as_dataframe=True): | ||
"""Returns a list of historical dividends data from Yahoo Finance""" | ||
warnings.warn( | ||
"getDividends has been deprecated, use get_dividends instead", | ||
DeprecationWarning, | ||
) | ||
return self._get("div") | ||
|
||
def getSplits(self): | ||
"""Returns a list of historical splits data from Yahoo Finance""" | ||
warnings.warn( | ||
"getSplits has been deprecated, use get_splits instead", DeprecationWarning | ||
) | ||
return self._get("split") | ||
|
||
def getDatePrice(self): | ||
"""Returns a DataFrame for Date and Price from getHistorical()""" | ||
warnings.warn( | ||
"getDatePrice has been deprecated, use get_date_price instead", | ||
DeprecationWarning, | ||
) | ||
return self.getHistorical().iloc[:, [0, 4]] | ||
|
||
def getDateVolume(self): | ||
"""Returns a DataFrame for Date and Volume from getHistorical()""" | ||
warnings.warn( | ||
"getDateVolume has been deprecated, use get_date_volume instead", | ||
DeprecationWarning, | ||
) | ||
return self.getHistorical().iloc[:, [0, 6]] | ||
|
||
def get_historical(self): | ||
"""PEP8 friendly version of deprecated getHistorical function""" | ||
return self._get("history") | ||
|
||
def get_dividends(self): | ||
"""PEP8 friendly version of deprecated getDividends function""" | ||
return self._get("div") | ||
|
||
def get_splits(self): | ||
"""PEP8 friendly version of deprecated getSplits function""" | ||
return self._get("split") | ||
|
||
def get_date_price(self): | ||
"""PEP8 friendly version of deprecated getDatePrice function""" | ||
return self.get_historical().iloc[:, [0, 4]] | ||
|
||
def get_date_volume(self): | ||
"""PEP8 friendly version of deprecated getDateVolume function""" | ||
return self.get_historical().iloc[:, [0, 6]] | ||
return self._get("div", as_dataframe=as_dataframe) | ||
|
||
def get_splits(self, as_dataframe=True): | ||
"""Returns a list of historical stock splits from Yahoo Finance""" | ||
return self._get("split", as_dataframe=as_dataframe) |
This file was deleted.
Oops, something went wrong.