Skip to content

Commit

Permalink
Merge pull request #25 from AndrewRPorter/refactor_and_remove_python_…
Browse files Browse the repository at this point in the history
…2_support

Refactor and remove python 2 support
  • Loading branch information
AndrewRPorter authored Aug 3, 2022
2 parents 41609ad + 33ee82b commit 6cd9fee
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 144 deletions.
52 changes: 20 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ pip install --user yahoo-historical
- get_historical()
- get_dividends()
- get_splits()
- get_date_price()
- get_date_volume()

## Example Usage

Expand All @@ -23,17 +21,23 @@ Below details the available method params for creating a Fetcher object.
### Arguments

- ticker: The ticker symbol to download historical data for
- start: Start date in form [Year,Month,Day]
- start: Start date as Unix timestamp

### Optional Arguments

- end: End date in form [Year,Month,Day]
- end: End date as Unix timestamp (defaults to `time.time()`)
- interval: Interval to fetch historical data (can be 1d, 1wk, 1mo, defaults to 1d)

```python
from yahoo_historical import Fetcher
data = Fetcher("AAPL", [2007,1,1], [2017,1,1])
print(data.get_historical())
import datetime
import time

# create unix timestamp representing January 1st, 2007
timestamp = time.mktime(datetime.datetime(2007, 1, 1).timetuple())

data = Fetcher("AAPL", timestamp)
print(data.get_historical())
```

```
Expand All @@ -42,35 +46,19 @@ from yahoo_historical import Fetcher
1 2007-01-04 12.007143 12.278571 11.974286 11.052453 12.237143 211815100
2 2007-01-05 12.252857 12.314285 12.057143 10.973743 12.150000 208685400
3 2007-01-08 12.280000 12.361428 12.182858 11.027935 12.210000 199276700
4 2007-01-09 12.350000 13.282857 12.164286 11.944029 13.224286 837324600
5 2007-01-10 13.535714 13.971429 13.350000 12.515617 13.857142 738220000
6 2007-01-11 13.705714 13.825714 13.585714 12.360788 13.685715 360063200
7 2007-01-12 13.512857 13.580000 13.318571 12.208535 13.517143 328172600
8 2007-01-16 13.668571 13.892858 13.635715 12.528520 13.871428 311019100
9 2007-01-17 13.937143 13.942857 13.545714 12.251113 13.564285 411565000
10 2007-01-18 13.157143 13.158571 12.721429 11.492435 12.724286 591151400
```

## License

MIT License
Note that you can return a dictionary instead of a DataFrame by setting the `as_dataframe` flag to `False`.

Copyright (c) 2017 Andrew Porter
```python
from yahoo_historical import Fetcher

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
import datetime
import time

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
# create unix timestamp representing January 1st, 2007
timestamp = time.mktime(datetime.datetime(2007, 1, 1).timetuple())

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
data = Fetcher("AAPL", timestamp)
print(data.get_historical(as_dataframe=False))
```
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]",
Expand Down
File renamed without changes.
32 changes: 32 additions & 0 deletions tests/test_fetch.py
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
2 changes: 1 addition & 1 deletion yahoo_historical/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from yahoo_historical.fetch import Fetcher
from .fetch import Fetcher # noqa
6 changes: 6 additions & 0 deletions yahoo_historical/constants.py
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]
140 changes: 56 additions & 84 deletions yahoo_historical/fetch.py
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)
26 changes: 0 additions & 26 deletions yahoo_historical/tests/test_fetch.py

This file was deleted.

0 comments on commit 6cd9fee

Please sign in to comment.