Skip to content

Commit dbce8e8

Browse files
committed
First commit
1 parent 53560ce commit dbce8e8

11 files changed

Lines changed: 747 additions & 0 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,7 @@ ENV/
9999

100100
# mypy
101101
.mypy_cache/
102+
103+
*.sqlite
104+
.DS_Store
105+

.travis.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
sudo: false
2+
3+
language: python
4+
5+
matrix:
6+
fast_finish: true
7+
include:
8+
- os: linux
9+
env:
10+
- PYTHON=3.5 PANDAS=0.20.1
11+
- os: linux
12+
env:
13+
- PYTHON=3.6 PANDAS=0.20.1
14+
# In allow failures
15+
- os: linux
16+
env:
17+
- PYTHON=3.6 PANDAS="MASTER"
18+
allow_failures:
19+
- os: linux
20+
env:
21+
- PYTHON=3.6 PANDAS="MASTER"
22+
23+
install:
24+
- pip install -qq flake8
25+
# You may want to periodically update this, although the conda update
26+
# conda line below will keep everything up-to-date. We do this
27+
# conditionally because it saves us some downloading if the version is
28+
# the same.
29+
- if [[ "$PYTHON" == "2.7" ]]; then
30+
wget http://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh;
31+
else
32+
wget http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
33+
fi
34+
- bash miniconda.sh -b -p $HOME/miniconda
35+
- export PATH="$HOME/miniconda/bin:$PATH"
36+
- hash -r
37+
- conda config --set always_yes yes --set changeps1 no
38+
- conda config --add channels pandas
39+
- conda update -q conda
40+
# Useful for debugging any issues with conda
41+
- conda info -a
42+
- conda create -q -n test-environment python=$PYTHON coverage setuptools pytest pytest-cov
43+
- source activate test-environment
44+
- if [[ "$PANDAS" == "MASTER" ]]; then
45+
conda install numpy pytz python-dateutil;
46+
PRE_WHEELS="https://7933911d6844c6c53a7d-47bd50c35cd79bd838daf386af554a83.ssl.cf2.rackcdn.com";
47+
pip install --pre --upgrade --timeout=60 -f $PRE_WHEELS pandas;
48+
else
49+
conda install pandas=$PANDAS;
50+
fi
51+
- pip install coveralls --quiet
52+
- conda list
53+
- python setup.py install
54+
55+
script:
56+
- export EOD_HISTORICAL_API_KEY=$EOD_HISTORICAL_API_KEY
57+
- pytest -s --cov=eod_historical_data --cov-report xml:/tmp/cov-eod_historical_data.xml --junitxml=/tmp/eod_historical_data.xml
58+
- flake8 --version
59+
- flake8 eod_historical_data tests
60+
61+
after_success:
62+
- coveralls

README.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
[![Build Status](https://travis-ci.org/femtotrader/python-eodhistoricaldata.svg?branch=master)](https://travis-ci.org/femtotrader/python-eodhistoricaldata)
2+
3+
# Python EOD Historical Data
4+
5+
A library to download data from EOD historical data https://eodhistoricaldata.com/ using:
6+
- [Python](https://www.python.org/)
7+
- [Requests](http://docs.python-requests.org/) / [Requests-cache](http://requests-cache.readthedocs.io/)
8+
- [Pandas](http://pandas.pydata.org/)
9+
10+
## Installation
11+
12+
### Install latest development version
13+
14+
```bash
15+
$ pip install git+https://github.com/femtotrader/python-eodhistoricaldata.git
16+
```
17+
18+
or
19+
20+
```bash
21+
$ git clone https://github.com/femtotrader/python-eodhistoricaldata.git
22+
$ python setup.py install
23+
```
24+
25+
## Usage
26+
27+
Environment variable `EOD_HISTORICAL_API_KEY` should be defined using:
28+
29+
```bash
30+
export EOD_HISTORICAL_API_KEY="YOUR_API"
31+
```
32+
33+
You can download data simply using
34+
35+
```python
36+
In [1]: import pandas as pd
37+
In [2]: pd.set_option("max_rows", 10)
38+
In [3]: from eod_historical_data import get_eod_data
39+
In [4]: df = get_eod_data("AAPL", "US")
40+
In [5]: df
41+
Out[1]:
42+
Open High Low Close Adjusted_close \
43+
Date
44+
2000-01-03 3.7455 4.0179 3.6317 3.9978 3.9978
45+
2000-01-04 3.8661 3.9509 3.6138 3.6607 3.6607
46+
2000-01-05 3.7054 3.9487 3.6786 3.7143 3.7143
47+
2000-01-06 3.7902 3.8214 3.3929 3.3929 3.3929
48+
2000-01-07 3.4464 3.6071 3.4107 3.5536 3.5536
49+
... ... ... ... ... ...
50+
2017-05-26 154.0000 154.2400 153.3100 153.6100 153.6100
51+
2017-05-30 153.4200 154.4300 153.3300 153.6700 153.6700
52+
2017-05-31 153.9700 154.1700 152.3800 152.7600 152.7600
53+
2017-06-01 153.1700 153.3300 152.2200 153.1800 153.1800
54+
2017-06-02 153.6000 155.4500 152.8900 155.4500 155.4500
55+
56+
Volume
57+
Date
58+
2000-01-03 133949200.0
59+
2000-01-04 128094400.0
60+
2000-01-05 194580400.0
61+
2000-01-06 191993200.0
62+
2000-01-07 115183600.0
63+
... ...
64+
2017-05-26 21927600.0
65+
2017-05-30 20126900.0
66+
2017-05-31 24451200.0
67+
2017-06-01 16274200.0
68+
2017-06-02 25163841.0
69+
70+
[4382 rows x 6 columns]
71+
```
72+
73+
but if you want to avoid too much data consumption, you can use a cache mechanism.
74+
75+
76+
```python
77+
In [1]: import datetime
78+
In [2]: import requests_cache
79+
In [3]: expire_after = datetime.timedelta(days=1)
80+
In [4]: session = requests_cache.CachedSession(cache_name='cache', backend='sqlite', expire_after=expire_after)
81+
In [5]: df = get_eod_data("AAPL", "US", session=session)
82+
```
83+
84+
See [tests directory](https://github.com/femtotrader/python-eodhistoricaldata/tree/master/tests) for example of other API endpoints.
85+
86+
## Credits
87+
88+
- Idea to create this project [came from this issue](https://github.com/pydata/pandas-datareader/issues/315) (Thanks [@deios0](https://github.com/deios0) )
89+
- Code was inspired by [pandas-datareader](http://pandas-datareader.readthedocs.io/)

eod_historical_data/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .data import (get_api_key, get_eod_data, get_dividends, # noqa
2+
get_exchange_symbols, get_exchanges, # noqa
3+
get_currencies, get_indexes) # noqa

eod_historical_data/_utils.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import requests
2+
import datetime
3+
import pandas as pd
4+
from pandas.io.common import urlencode
5+
from pandas.api.types import is_number
6+
7+
8+
def _init_session(session):
9+
"""
10+
Returns a requests.Session (or CachedSession)
11+
"""
12+
if session is None:
13+
return requests.Session()
14+
return session
15+
16+
17+
def _url(url, params):
18+
"""
19+
Returns long url with parameters
20+
http://mydomain.com?param1=...&param2=...
21+
"""
22+
if params is not None and len(params) > 0:
23+
return url + "?" + urlencode(params)
24+
else:
25+
return url
26+
27+
28+
class RemoteDataError(IOError):
29+
"""
30+
Remote data exception
31+
"""
32+
pass
33+
34+
35+
def _format_date(dt):
36+
"""
37+
Returns formated date
38+
"""
39+
if dt is None:
40+
return dt
41+
return dt.strftime("%Y-%m-%d")
42+
43+
44+
def _sanitize_dates(start, end):
45+
"""
46+
Return (datetime_start, datetime_end) tuple
47+
"""
48+
if is_number(start):
49+
# regard int as year
50+
start = datetime.datetime(start, 1, 1)
51+
start = pd.to_datetime(start)
52+
53+
if is_number(end):
54+
# regard int as year
55+
end = datetime.datetime(end, 1, 1)
56+
end = pd.to_datetime(end)
57+
58+
if start is not None and end is not None:
59+
if start > end:
60+
raise Exception("end must be after start")
61+
62+
return start, end

0 commit comments

Comments
 (0)