Skip to content

Commit 7f4baa6

Browse files
author
Scott Sanderson
committed
TEST: Add test coverage for loading fx rates of None.
We should always return NaN on a request to load None as an FX rate.
1 parent 73a2c07 commit 7f4baa6

File tree

3 files changed

+27
-17
lines changed

3 files changed

+27
-17
lines changed

tests/data/test_fx.py

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,17 @@ def test_scalar_lookup(self):
6565
reader = self.reader
6666

6767
rates = self.FX_RATES_RATE_NAMES
68-
currencies = self.FX_RATES_CURRENCIES
68+
quotes = self.FX_RATES_CURRENCIES
69+
bases = self.FX_RATES_CURRENCIES + [None]
6970
dates = pd.date_range(
7071
self.FX_RATES_START_DATE - pd.Timedelta('1 day'),
7172
self.FX_RATES_END_DATE,
7273
)
73-
74-
cases = itertools.product(rates, currencies, currencies, dates)
74+
cases = itertools.product(rates, quotes, bases, dates)
7575

7676
for rate, quote, base, dt in cases:
7777
dts = pd.DatetimeIndex([dt], tz='UTC')
78-
bases = np.array([base])
78+
bases = np.array([base], dtype=object)
7979

8080
result = reader.get_rates(rate, quote, bases, dts)
8181
assert_equal(result.shape, (1, 1))
@@ -101,10 +101,11 @@ def test_2d_lookup(self):
101101
self.FX_RATES_END_DATE
102102
)
103103
rates = self.FX_RATES_RATE_NAMES + [DEFAULT_FX_RATE]
104-
currencies = self.FX_RATES_CURRENCIES
104+
possible_quotes = self.FX_RATES_CURRENCIES
105+
possible_bases = self.FX_RATES_CURRENCIES + [None]
105106

106107
# For every combination of rate name and quote currency...
107-
for rate, quote in itertools.product(rates, currencies):
108+
for rate, quote in itertools.product(rates, possible_quotes):
108109

109110
# Choose N random distinct days...
110111
for ndays in 1, 2, 7, 20:
@@ -113,7 +114,10 @@ def test_2d_lookup(self):
113114

114115
# Choose M random possibly-non-distinct currencies...
115116
for nbases in 1, 2, 10, 200:
116-
bases = rand.choice(currencies, nbases, replace=True)
117+
bases = (
118+
rand.choice(possible_bases, nbases, replace=True)
119+
.astype(object)
120+
)
117121

118122
# ...And check that we get the expected result when querying
119123
# for those dates/currencies.
@@ -130,16 +134,20 @@ def test_columnar_lookup(self):
130134
self.FX_RATES_END_DATE,
131135
)
132136
rates = self.FX_RATES_RATE_NAMES + [DEFAULT_FX_RATE]
133-
currencies = self.FX_RATES_CURRENCIES
137+
possible_quotes = self.FX_RATES_CURRENCIES
138+
possible_bases = self.FX_RATES_CURRENCIES + [None]
134139
reader = self.reader
135140

136141
# For every combination of rate name and quote currency...
137-
for rate, quote in itertools.product(rates, currencies):
142+
for rate, quote in itertools.product(rates, possible_quotes):
138143
for N in 1, 2, 10, 200:
139144
# Choose N (date, base) pairs randomly with replacement.
140145
dts_raw = rand.choice(dates, N, replace=True)
141-
dts = pd.DatetimeIndex(dts_raw, tz='utc').sort_values()
142-
bases = rand.choice(currencies, N, replace=True)
146+
dts = pd.DatetimeIndex(dts_raw, tz='utc')
147+
bases = (
148+
rand.choice(possible_bases, N, replace=True)
149+
.astype(object)
150+
)
143151

144152
# ... And check that we get the expected result when querying
145153
# for those dates/currencies.
@@ -222,10 +230,11 @@ def test_read_after_end_date(self):
222230
def test_read_unknown_base(self):
223231
for rate in self.FX_RATES_RATE_NAMES:
224232
quote = 'USD'
225-
bases = np.array(['XXX'], dtype=object)
226-
dts = pd.DatetimeIndex([self.FX_RATES_START_DATE])
227-
result = self.reader.get_rates(rate, quote, bases, dts)[0, 0]
228-
assert_equal(result, np.nan)
233+
for unknown_base in 'XXX', None:
234+
bases = np.array(['XXX'], dtype=object)
235+
dts = pd.DatetimeIndex([self.FX_RATES_START_DATE])
236+
result = self.reader.get_rates(rate, quote, bases, dts)[0, 0]
237+
assert_equal(result, np.nan)
229238

230239

231240
class InMemoryFXReaderTestCase(_FXReaderTestCase):

zipline/data/fx/base.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,6 @@ def get_rates_columnar(self, rate, quote, bases, dts):
136136
"len(bases) ({}) != len(dts) ({})".format(len(bases), len(dts))
137137
)
138138

139-
# TODO: Casting `bases` to str here is a temporary fix for the bug
140-
# where having any `None` in `bases` causes `np.unique` to error.
141139
bases_ix, unique_bases, _ = factorize_strings(
142140
bases,
143141
missing_value=None,

zipline/testing/fixtures.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2197,6 +2197,9 @@ def write_h5_fx_rates(cls, path):
21972197
def get_expected_fx_rate_scalar(cls, rate, quote, base, dt):
21982198
"""Get the expected FX rate for the given scalar coordinates.
21992199
"""
2200+
if base is None:
2201+
return np.nan
2202+
22002203
if rate == DEFAULT_FX_RATE:
22012204
rate = cls.FX_RATES_DEFAULT_RATE
22022205

0 commit comments

Comments
 (0)