Skip to content

Commit 3700771

Browse files
authored
Merge pull request #440 from bashtage/dwrpayne-bankofcanada
REBASE: Dwrpayne/bankofcanada
2 parents f50e5cc + 9a9971d commit 3700771

File tree

4 files changed

+122
-15
lines changed

4 files changed

+122
-15
lines changed

pandas_datareader/bankofcanada.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from __future__ import unicode_literals
2+
3+
import pandas.compat as compat
4+
5+
from pandas_datareader.base import _BaseReader
6+
7+
8+
class BankOfCanadaReader(_BaseReader):
9+
"""Get data for the given name from Bank of Canada."""
10+
11+
_URL = 'http://www.bankofcanada.ca/valet/observations'
12+
13+
@property
14+
def url(self):
15+
if not isinstance(self.symbols, compat.string_types):
16+
raise ValueError('data name must be string')
17+
18+
return '{0}/{1}/csv'.format(self._URL, self.symbols)
19+
20+
@property
21+
def params(self):
22+
return {'start_date': self.start.strftime('%Y-%m-%d'),
23+
'end_date': self.end.strftime('%Y-%m-%d')}
24+
25+
@staticmethod
26+
def _sanitize_response(response):
27+
"""
28+
Clean up the response string
29+
"""
30+
data = response.text.split('OBSERVATIONS')[1]
31+
return data.split('ERRORS')[0].strip()

pandas_datareader/base.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
class _BaseReader(object):
1818

1919
"""
20-
2120
Parameters
2221
----------
2322
sym : string with a single Single stock symbol (ticker).

pandas_datareader/data.py

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,30 @@
44

55
import warnings
66

7+
from pandas_datareader.bankofcanada import BankOfCanadaReader
8+
from pandas_datareader.edgar import EdgarIndexReader
9+
from pandas_datareader.enigma import EnigmaReader
10+
from pandas_datareader.eurostat import EurostatReader
11+
from pandas_datareader.famafrench import FamaFrenchReader
12+
from pandas_datareader.fred import FredReader
713
from pandas_datareader.google.daily import GoogleDailyReader
8-
from pandas_datareader.google.quotes import GoogleQuotesReader
914
from pandas_datareader.google.options import Options as GoogleOptions
10-
11-
from pandas_datareader.yahoo.daily import YahooDailyReader
12-
from pandas_datareader.yahoo.quotes import YahooQuotesReader
15+
from pandas_datareader.google.quotes import GoogleQuotesReader
16+
from pandas_datareader.moex import MoexReader
17+
from pandas_datareader.nasdaq_trader import get_nasdaq_symbols
18+
from pandas_datareader.oecd import OECDReader
19+
from pandas_datareader.quandl import QuandlReader
1320
from pandas_datareader.yahoo.actions import (YahooActionReader, YahooDivReader)
14-
from pandas_datareader.yahoo.components import _get_data as get_components_yahoo # noqa
21+
from pandas_datareader.yahoo.components import _get_data as \
22+
get_components_yahoo
23+
from pandas_datareader.yahoo.daily import YahooDailyReader
1524
from pandas_datareader.yahoo.options import Options as YahooOptions
25+
from pandas_datareader.yahoo.quotes import YahooQuotesReader
1626

17-
from pandas_datareader.eurostat import EurostatReader
18-
from pandas_datareader.fred import FredReader
19-
from pandas_datareader.famafrench import FamaFrenchReader
20-
from pandas_datareader.oecd import OECDReader
21-
from pandas_datareader.edgar import EdgarIndexReader
22-
from pandas_datareader.enigma import EnigmaReader
23-
from pandas_datareader.nasdaq_trader import get_nasdaq_symbols
24-
from pandas_datareader.quandl import QuandlReader
25-
from pandas_datareader.moex import MoexReader
27+
__all__ = ['get_components_yahoo', 'get_data_enigma', 'get_data_famafrench',
28+
'get_data_fred', 'get_data_google', 'get_data_moex',
29+
'get_data_quandl', 'get_data_yahoo', 'get_data_yahoo_actions',
30+
'get_nasdaq_symbols', 'get_quote_google', 'get_quote_yahoo']
2631

2732

2833
def get_data_fred(*args, **kwargs):
@@ -141,6 +146,11 @@ def DataReader(name, data_source=None, start=None, end=None,
141146
retry_count=retry_count, pause=pause,
142147
session=session).read()
143148

149+
elif data_source == "bankofcanada":
150+
return BankOfCanadaReader(symbols=name, start=start, end=end,
151+
retry_count=retry_count, pause=pause,
152+
session=session).read()
153+
144154
elif data_source == "enigma":
145155
return EnigmaReader(dataset_id=name, api_key=access_key).read()
146156

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
from datetime import date, timedelta
2+
3+
import pytest
4+
5+
import pandas_datareader.data as web
6+
from pandas_datareader._utils import RemoteDataError
7+
8+
9+
class TestBankOfCanada(object):
10+
11+
@staticmethod
12+
def get_symbol(currency_code, inverted=False):
13+
if inverted:
14+
return 'FXCAD{}'.format(currency_code)
15+
else:
16+
return 'FX{}CAD'.format(currency_code)
17+
18+
def check_bankofcanada_count(self, code):
19+
df = web.DataReader(self.get_symbol(code), 'bankofcanada',
20+
date.today() - timedelta(days=30), date.today())
21+
assert df.size > 15
22+
23+
def check_bankofcanada_valid(self, code):
24+
symbol = self.get_symbol(code)
25+
df = web.DataReader(symbol, 'bankofcanada',
26+
date.today() - timedelta(days=30), date.today())
27+
assert symbol in df.columns
28+
29+
def check_bankofcanada_inverted(self, code):
30+
symbol = self.get_symbol(code)
31+
symbol_inverted = self.get_symbol(code, inverted=True)
32+
33+
df = web.DataReader(symbol, 'bankofcanada',
34+
date.today() - timedelta(days=30), date.today())
35+
df_i = web.DataReader(symbol_inverted, 'bankofcanada',
36+
date.today() - timedelta(days=30), date.today())
37+
38+
pairs = zip((1 / df)[symbol].tolist(), df_i[symbol_inverted].tolist())
39+
assert all(a - b < 0.01 for a, b in pairs)
40+
41+
def test_bankofcanada_usd_count(self):
42+
self.check_bankofcanada_count('USD')
43+
44+
def test_bankofcanada_eur_count(self):
45+
self.check_bankofcanada_count('EUR')
46+
47+
def test_bankofcanada_usd_valid(self):
48+
self.check_bankofcanada_valid('USD')
49+
50+
def test_bankofcanada_eur_valid(self):
51+
self.check_bankofcanada_valid('EUR')
52+
53+
def test_bankofcanada_usd_inverted(self):
54+
self.check_bankofcanada_inverted('USD')
55+
56+
def test_bankofcanada_eur_inverted(self):
57+
self.check_bankofcanada_inverted('EUR')
58+
59+
def test_bankofcanada_bad_range(self):
60+
with pytest.raises(RemoteDataError):
61+
web.DataReader('FXCADUSD', 'bankofcanada',
62+
date.today(), date.today() - timedelta(days=30))
63+
64+
def test_bankofcanada_bad_url(self):
65+
with pytest.raises(RemoteDataError):
66+
web.DataReader('abcdefgh', 'bankofcanada',
67+
date.today() - timedelta(days=30), date.today())

0 commit comments

Comments
 (0)