From b863733953c8a2a268a37ea86a39d8fefc0bb1e1 Mon Sep 17 00:00:00 2001 From: Eddie Hebert Date: Mon, 14 Dec 2015 18:10:26 -0500 Subject: [PATCH 1/4] REF: Move order class to distinct module. --- tests/test_blotter.py | 3 +- zipline/finance/blotter.py | 178 +-------------------------------- zipline/finance/order.py | 194 ++++++++++++++++++++++++++++++++++++ zipline/utils/test_utils.py | 2 +- 4 files changed, 199 insertions(+), 178 deletions(-) create mode 100644 zipline/finance/order.py diff --git a/tests/test_blotter.py b/tests/test_blotter.py index 2b012e38..6f2ffee1 100644 --- a/tests/test_blotter.py +++ b/tests/test_blotter.py @@ -18,7 +18,8 @@ from nose_parameterized import parameterized from unittest import TestCase from zipline.finance import trading -from zipline.finance.blotter import Blotter, ORDER_STATUS +from zipline.finance.blotter import Blotter +from zipline.finance.order import ORDER_STATUS from zipline.finance.execution import ( LimitOrder, MarketOrder, diff --git a/zipline/finance/blotter.py b/zipline/finance/blotter.py index a7a552d1..320fb12a 100644 --- a/zipline/finance/blotter.py +++ b/zipline/finance/blotter.py @@ -1,5 +1,5 @@ # -# Copyright 2014 Quantopian, Inc. +# Copyright 2015 Quantopian, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,13 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. import math -import uuid -from copy import copy from logbook import Logger from collections import defaultdict -from six import text_type, iteritems from six.moves import filter import zipline.errors @@ -28,10 +25,9 @@ import zipline.protocol as zp from zipline.finance.slippage import ( VolumeShareSlippage, transact_partial, - check_order_triggers ) from zipline.finance.commission import PerShare -from zipline.utils.enum import enum +from zipline.finance.order import Order from zipline.utils.serialization_utils import ( VERSION_LABEL @@ -39,14 +35,6 @@ from zipline.utils.serialization_utils import ( log = Logger('Blotter') -ORDER_STATUS = enum( - 'OPEN', - 'FILLED', - 'CANCELLED', - 'REJECTED', - 'HELD', -) - class Blotter(object): @@ -283,165 +271,3 @@ class Blotter(object): self.open_orders = open_orders self.__dict__.update(state) - - -class Order(object): - def __init__(self, dt, sid, amount, stop=None, limit=None, filled=0, - commission=None, id=None): - """ - @dt - datetime.datetime that the order was placed - @sid - stock sid of the order - @amount - the number of shares to buy/sell - a positive sign indicates a buy - a negative sign indicates a sell - @filled - how many shares of the order have been filled so far - """ - # get a string representation of the uuid. - self.id = id or self.make_id() - self.dt = dt - self.reason = None - self.created = dt - self.sid = sid - self.amount = amount - self.filled = filled - self.commission = commission - self._status = ORDER_STATUS.OPEN - self.stop = stop - self.limit = limit - self.stop_reached = False - self.limit_reached = False - self.direction = math.copysign(1, self.amount) - self.type = zp.DATASOURCE_TYPE.ORDER - - def make_id(self): - return uuid.uuid4().hex - - def to_dict(self): - py = copy(self.__dict__) - for field in ['type', 'direction', '_status']: - del py[field] - py['status'] = self.status - return py - - def to_api_obj(self): - pydict = self.to_dict() - obj = zp.Order(initial_values=pydict) - return obj - - def check_triggers(self, event): - """ - Update internal state based on price triggers and the - trade event's price. - """ - stop_reached, limit_reached, sl_stop_reached = \ - check_order_triggers(self, event) - if (stop_reached, limit_reached) \ - != (self.stop_reached, self.limit_reached): - self.dt = event.dt - self.stop_reached = stop_reached - self.limit_reached = limit_reached - if sl_stop_reached: - # Change the STOP LIMIT order into a LIMIT order - self.stop = None - - def handle_split(self, split_event): - ratio = split_event.ratio - - # update the amount, limit_price, and stop_price - # by the split's ratio - - # info here: http://finra.complinet.com/en/display/display_plain.html? - # rbid=2403&element_id=8950&record_id=12208&print=1 - - # new_share_amount = old_share_amount / ratio - # new_price = old_price * ratio - - self.amount = int(self.amount / ratio) - - if self.limit is not None: - self.limit = round(self.limit * ratio, 2) - - if self.stop is not None: - self.stop = round(self.stop * ratio, 2) - - @property - def status(self): - if not self.open_amount: - return ORDER_STATUS.FILLED - elif self._status == ORDER_STATUS.HELD and self.filled: - return ORDER_STATUS.OPEN - else: - return self._status - - @status.setter - def status(self, status): - self._status = status - - def cancel(self): - self.status = ORDER_STATUS.CANCELLED - - def reject(self, reason=''): - self.status = ORDER_STATUS.REJECTED - self.reason = reason - - def hold(self, reason=''): - self.status = ORDER_STATUS.HELD - self.reason = reason - - @property - def open(self): - return self.status in [ORDER_STATUS.OPEN, ORDER_STATUS.HELD] - - @property - def triggered(self): - """ - For a market order, True. - For a stop order, True IFF stop_reached. - For a limit order, True IFF limit_reached. - """ - if self.stop is not None and not self.stop_reached: - return False - - if self.limit is not None and not self.limit_reached: - return False - - return True - - @property - def open_amount(self): - return self.amount - self.filled - - def __repr__(self): - """ - String representation for this object. - """ - return "Order(%s)" % self.to_dict().__repr__() - - def __unicode__(self): - """ - Unicode representation for this object. - """ - return text_type(repr(self)) - - def __getstate__(self): - - state_dict = \ - {k: v for k, v in iteritems(self.__dict__) - if not k.startswith('_')} - - state_dict['_status'] = self._status - - STATE_VERSION = 1 - state_dict[VERSION_LABEL] = STATE_VERSION - - return state_dict - - def __setstate__(self, state): - - OLDEST_SUPPORTED_STATE = 1 - version = state.pop(VERSION_LABEL) - - if version < OLDEST_SUPPORTED_STATE: - raise BaseException("Order saved state is too old.") - - self.__dict__.update(state) diff --git a/zipline/finance/order.py b/zipline/finance/order.py new file mode 100644 index 00000000..aaefc827 --- /dev/null +++ b/zipline/finance/order.py @@ -0,0 +1,194 @@ +# +# Copyright 2015 Quantopian, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from copy import copy +import math +import uuid + +from six import text_type, iteritems + +from zipline.finance.slippage import check_order_triggers +import zipline.protocol as zp +from zipline.utils.serialization_utils import VERSION_LABEL +from zipline.utils.enum import enum + +ORDER_STATUS = enum( + 'OPEN', + 'FILLED', + 'CANCELLED', + 'REJECTED', + 'HELD', +) + + +class Order(object): + def __init__(self, dt, sid, amount, stop=None, limit=None, filled=0, + commission=None, id=None): + """ + @dt - datetime.datetime that the order was placed + @sid - stock sid of the order + @amount - the number of shares to buy/sell + a positive sign indicates a buy + a negative sign indicates a sell + @filled - how many shares of the order have been filled so far + """ + # get a string representation of the uuid. + self.id = id or self.make_id() + self.dt = dt + self.reason = None + self.created = dt + self.sid = sid + self.amount = amount + self.filled = filled + self.commission = commission + self._status = ORDER_STATUS.OPEN + self.stop = stop + self.limit = limit + self.stop_reached = False + self.limit_reached = False + self.direction = math.copysign(1, self.amount) + self.type = zp.DATASOURCE_TYPE.ORDER + + def make_id(self): + return uuid.uuid4().hex + + def to_dict(self): + py = copy(self.__dict__) + for field in ['type', 'direction', '_status']: + del py[field] + py['status'] = self.status + return py + + def to_api_obj(self): + pydict = self.to_dict() + obj = zp.Order(initial_values=pydict) + return obj + + def check_triggers(self, event): + """ + Update internal state based on price triggers and the + trade event's price. + """ + stop_reached, limit_reached, sl_stop_reached = \ + check_order_triggers(self, event) + if (stop_reached, limit_reached) \ + != (self.stop_reached, self.limit_reached): + self.dt = event.dt + self.stop_reached = stop_reached + self.limit_reached = limit_reached + if sl_stop_reached: + # Change the STOP LIMIT order into a LIMIT order + self.stop = None + + def handle_split(self, split_event): + ratio = split_event.ratio + + # update the amount, limit_price, and stop_price + # by the split's ratio + + # info here: http://finra.complinet.com/en/display/display_plain.html? + # rbid=2403&element_id=8950&record_id=12208&print=1 + + # new_share_amount = old_share_amount / ratio + # new_price = old_price * ratio + + self.amount = int(self.amount / ratio) + + if self.limit is not None: + self.limit = round(self.limit * ratio, 2) + + if self.stop is not None: + self.stop = round(self.stop * ratio, 2) + + @property + def status(self): + if not self.open_amount: + return ORDER_STATUS.FILLED + elif self._status == ORDER_STATUS.HELD and self.filled: + return ORDER_STATUS.OPEN + else: + return self._status + + @status.setter + def status(self, status): + self._status = status + + def cancel(self): + self.status = ORDER_STATUS.CANCELLED + + def reject(self, reason=''): + self.status = ORDER_STATUS.REJECTED + self.reason = reason + + def hold(self, reason=''): + self.status = ORDER_STATUS.HELD + self.reason = reason + + @property + def open(self): + return self.status in [ORDER_STATUS.OPEN, ORDER_STATUS.HELD] + + @property + def triggered(self): + """ + For a market order, True. + For a stop order, True IFF stop_reached. + For a limit order, True IFF limit_reached. + """ + if self.stop is not None and not self.stop_reached: + return False + + if self.limit is not None and not self.limit_reached: + return False + + return True + + @property + def open_amount(self): + return self.amount - self.filled + + def __repr__(self): + """ + String representation for this object. + """ + return "Order(%s)" % self.to_dict().__repr__() + + def __unicode__(self): + """ + Unicode representation for this object. + """ + return text_type(repr(self)) + + def __getstate__(self): + + state_dict = \ + {k: v for k, v in iteritems(self.__dict__) + if not k.startswith('_')} + + state_dict['_status'] = self._status + + STATE_VERSION = 1 + state_dict[VERSION_LABEL] = STATE_VERSION + + return state_dict + + def __setstate__(self, state): + + OLDEST_SUPPORTED_STATE = 1 + version = state.pop(VERSION_LABEL) + + if version < OLDEST_SUPPORTED_STATE: + raise BaseException("Order saved state is too old.") + + self.__dict__.update(state) diff --git a/zipline/utils/test_utils.py b/zipline/utils/test_utils.py index a9dd8fe2..31846868 100644 --- a/zipline/utils/test_utils.py +++ b/zipline/utils/test_utils.py @@ -24,7 +24,7 @@ from toolz import concat from zipline.assets import AssetFinder from zipline.assets.asset_writer import AssetDBWriterFromDataFrame from zipline.assets.futures import CME_CODE_TO_MONTH -from zipline.finance.blotter import ORDER_STATUS +from zipline.finance.order import ORDER_STATUS from zipline.utils import security_list From fc9d13ca0cb6af07bffc1ce9698f74dc385defef Mon Sep 17 00:00:00 2001 From: Eddie Hebert Date: Tue, 15 Dec 2015 10:30:11 -0500 Subject: [PATCH 2/4] REF: Move check_order_triggers to method of order. The function takes order as a first parameter, which lends itself to being an instance method. --- zipline/finance/order.py | 67 +++++++++++++++++++++++++++++++++++-- zipline/finance/slippage.py | 60 --------------------------------- 2 files changed, 65 insertions(+), 62 deletions(-) diff --git a/zipline/finance/order.py b/zipline/finance/order.py index aaefc827..d6ff5ab0 100644 --- a/zipline/finance/order.py +++ b/zipline/finance/order.py @@ -18,7 +18,6 @@ import uuid from six import text_type, iteritems -from zipline.finance.slippage import check_order_triggers import zipline.protocol as zp from zipline.utils.serialization_utils import VERSION_LABEL from zipline.utils.enum import enum @@ -31,6 +30,11 @@ ORDER_STATUS = enum( 'HELD', ) +SELL = 1 << 0 +BUY = 1 << 1 +STOP = 1 << 2 +LIMIT = 1 << 3 + class Order(object): def __init__(self, dt, sid, amount, stop=None, limit=None, filled=0, @@ -81,7 +85,7 @@ class Order(object): trade event's price. """ stop_reached, limit_reached, sl_stop_reached = \ - check_order_triggers(self, event) + self.check_order_triggers(event) if (stop_reached, limit_reached) \ != (self.stop_reached, self.limit_reached): self.dt = event.dt @@ -91,6 +95,65 @@ class Order(object): # Change the STOP LIMIT order into a LIMIT order self.stop = None + def check_order_triggers(self, event): + """ + Given an order and a trade event, return a tuple of + (stop_reached, limit_reached). + For market orders, will return (False, False). + For stop orders, limit_reached will always be False. + For limit orders, stop_reached will always be False. + For stop limit orders a Boolean is returned to flag + that the stop has been reached. + + Orders that have been triggered already (price targets reached), + the order's current values are returned. + """ + if self.triggered: + return (self.stop_reached, self.limit_reached, False) + + stop_reached = False + limit_reached = False + sl_stop_reached = False + + order_type = 0 + + if self.amount > 0: + order_type |= BUY + else: + order_type |= SELL + + if self.stop is not None: + order_type |= STOP + + if self.limit is not None: + order_type |= LIMIT + + if order_type == BUY | STOP | LIMIT: + if event.price >= self.stop: + sl_stop_reached = True + if event.price <= self.limit: + limit_reached = True + elif order_type == SELL | STOP | LIMIT: + if event.price <= self.stop: + sl_stop_reached = True + if event.price >= self.limit: + limit_reached = True + elif order_type == BUY | STOP: + if event.price >= self.stop: + stop_reached = True + elif order_type == SELL | STOP: + if event.price <= self.stop: + stop_reached = True + elif order_type == BUY | LIMIT: + if event.price <= self.limit: + limit_reached = True + elif order_type == SELL | LIMIT: + # This is a SELL LIMIT order + if event.price >= self.limit: + limit_reached = True + + return (stop_reached, limit_reached, sl_stop_reached) + def handle_split(self, split_event): ratio = split_event.ratio diff --git a/zipline/finance/slippage.py b/zipline/finance/slippage.py index 772d9e85..6bea1caf 100644 --- a/zipline/finance/slippage.py +++ b/zipline/finance/slippage.py @@ -34,66 +34,6 @@ STOP = 1 << 2 LIMIT = 1 << 3 -def check_order_triggers(order, event): - """ - Given an order and a trade event, return a tuple of - (stop_reached, limit_reached). - For market orders, will return (False, False). - For stop orders, limit_reached will always be False. - For limit orders, stop_reached will always be False. - For stop limit orders a Boolean is returned to flag - that the stop has been reached. - - Orders that have been triggered already (price targets reached), - the order's current values are returned. - """ - if order.triggered: - return (order.stop_reached, order.limit_reached, False) - - stop_reached = False - limit_reached = False - sl_stop_reached = False - - order_type = 0 - - if order.amount > 0: - order_type |= BUY - else: - order_type |= SELL - - if order.stop is not None: - order_type |= STOP - - if order.limit is not None: - order_type |= LIMIT - - if order_type == BUY | STOP | LIMIT: - if event.price >= order.stop: - sl_stop_reached = True - if event.price <= order.limit: - limit_reached = True - elif order_type == SELL | STOP | LIMIT: - if event.price <= order.stop: - sl_stop_reached = True - if event.price >= order.limit: - limit_reached = True - elif order_type == BUY | STOP: - if event.price >= order.stop: - stop_reached = True - elif order_type == SELL | STOP: - if event.price <= order.stop: - stop_reached = True - elif order_type == BUY | LIMIT: - if event.price <= order.limit: - limit_reached = True - elif order_type == SELL | LIMIT: - # This is a SELL LIMIT order - if event.price >= order.limit: - limit_reached = True - - return (stop_reached, limit_reached, sl_stop_reached) - - def transact_stub(slippage, commission, event, open_orders): """ This is intended to be wrapped in a partial, so that the From bbb9cc87a9085b55a09afc547d2f62650678691f Mon Sep 17 00:00:00 2001 From: Eddie Hebert Date: Tue, 15 Dec 2015 10:40:03 -0500 Subject: [PATCH 3/4] REF: Move transaction class to own module. --- tests/serialization_cases.py | 2 +- tests/test_perf_tracking.py | 2 +- .../finance/performance/position_tracker.py | 2 +- zipline/finance/slippage.py | 64 +-------------- zipline/finance/transaction.py | 82 +++++++++++++++++++ 5 files changed, 87 insertions(+), 65 deletions(-) create mode 100644 zipline/finance/transaction.py diff --git a/tests/serialization_cases.py b/tests/serialization_cases.py index 2a6bd094..c1e7645e 100644 --- a/tests/serialization_cases.py +++ b/tests/serialization_cases.py @@ -16,9 +16,9 @@ from zipline.finance.risk.period import RiskMetricsPeriod from zipline.finance.risk.report import RiskReport from zipline.finance.slippage import ( FixedSlippage, - Transaction, VolumeShareSlippage ) +from zipline.finance.transaction import Transaction from zipline.protocol import Account from zipline.protocol import Portfolio from zipline.protocol import Position as ProtocolPosition diff --git a/tests/test_perf_tracking.py b/tests/test_perf_tracking.py index 9ffe4a41..bb3a766f 100644 --- a/tests/test_perf_tracking.py +++ b/tests/test_perf_tracking.py @@ -36,7 +36,7 @@ from six.moves import range, zip import zipline.utils.factory as factory import zipline.finance.performance as perf from zipline.finance.performance import position_tracker -from zipline.finance.slippage import Transaction, create_transaction +from zipline.finance.transaction import Transaction, create_transaction import zipline.utils.math_utils as zp_math from zipline.gens.composites import date_sorted_sources diff --git a/zipline/finance/performance/position_tracker.py b/zipline/finance/performance/position_tracker.py index 114c5570..8c5c3037 100644 --- a/zipline/finance/performance/position_tracker.py +++ b/zipline/finance/performance/position_tracker.py @@ -28,7 +28,7 @@ except ImportError: from six import iteritems, itervalues from zipline.protocol import Event, DATASOURCE_TYPE -from zipline.finance.slippage import Transaction +from zipline.finance.transaction import Transaction from zipline.utils.serialization_utils import ( VERSION_LABEL ) diff --git a/zipline/finance/slippage.py b/zipline/finance/slippage.py index 6bea1caf..52866e90 100644 --- a/zipline/finance/slippage.py +++ b/zipline/finance/slippage.py @@ -1,5 +1,5 @@ # -# Copyright 2014 Quantopian, Inc. +# Copyright 2015 Quantopian, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ from functools import partial from six import with_metaclass -from zipline.protocol import DATASOURCE_TYPE +from zipline.finance.transaction import create_transaction from zipline.utils.serialization_utils import ( VERSION_LABEL ) @@ -52,66 +52,6 @@ def transact_partial(slippage, commission): return partial(transact_stub, slippage, commission) -class Transaction(object): - - def __init__(self, sid, amount, dt, price, order_id, commission=None): - self.sid = sid - self.amount = amount - self.dt = dt - self.price = price - self.order_id = order_id - self.commission = commission - self.type = DATASOURCE_TYPE.TRANSACTION - - def __getitem__(self, name): - return self.__dict__[name] - - def to_dict(self): - py = copy(self.__dict__) - del py['type'] - return py - - def __getstate__(self): - - state_dict = copy(self.__dict__) - - STATE_VERSION = 1 - state_dict[VERSION_LABEL] = STATE_VERSION - - return state_dict - - def __setstate__(self, state): - - OLDEST_SUPPORTED_STATE = 1 - version = state.pop(VERSION_LABEL) - - if version < OLDEST_SUPPORTED_STATE: - raise BaseException("Transaction saved state is too old.") - - self.__dict__.update(state) - - -def create_transaction(event, order, price, amount): - - # floor the amount to protect against non-whole number orders - # TODO: Investigate whether we can add a robust check in blotter - # and/or tradesimulation, as well. - amount_magnitude = int(abs(amount)) - - if amount_magnitude < 1: - raise Exception("Transaction magnitude must be at least 1.") - - transaction = Transaction( - sid=event.sid, - amount=int(amount), - dt=event.dt, - price=price, - order_id=order.id - ) - - return transaction - - class LiquidityExceeded(Exception): pass diff --git a/zipline/finance/transaction.py b/zipline/finance/transaction.py new file mode 100644 index 00000000..74052872 --- /dev/null +++ b/zipline/finance/transaction.py @@ -0,0 +1,82 @@ +# +# Copyright 2015 Quantopian, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import division + +from copy import copy + +from zipline.protocol import DATASOURCE_TYPE +from zipline.utils.serialization_utils import ( + VERSION_LABEL +) + + +class Transaction(object): + + def __init__(self, sid, amount, dt, price, order_id, commission=None): + self.sid = sid + self.amount = amount + self.dt = dt + self.price = price + self.order_id = order_id + self.commission = commission + self.type = DATASOURCE_TYPE.TRANSACTION + + def __getitem__(self, name): + return self.__dict__[name] + + def to_dict(self): + py = copy(self.__dict__) + del py['type'] + return py + + def __getstate__(self): + + state_dict = copy(self.__dict__) + + STATE_VERSION = 1 + state_dict[VERSION_LABEL] = STATE_VERSION + + return state_dict + + def __setstate__(self, state): + + OLDEST_SUPPORTED_STATE = 1 + version = state.pop(VERSION_LABEL) + + if version < OLDEST_SUPPORTED_STATE: + raise BaseException("Transaction saved state is too old.") + + self.__dict__.update(state) + + +def create_transaction(event, order, price, amount): + + # floor the amount to protect against non-whole number orders + # TODO: Investigate whether we can add a robust check in blotter + # and/or tradesimulation, as well. + amount_magnitude = int(abs(amount)) + + if amount_magnitude < 1: + raise Exception("Transaction magnitude must be at least 1.") + + transaction = Transaction( + sid=event.sid, + amount=int(amount), + dt=event.dt, + price=price, + order_id=order.id + ) + + return transaction From 82affb639f24bbd8a9509c33c130088798f2b1b7 Mon Sep 17 00:00:00 2001 From: Eddie Hebert Date: Tue, 15 Dec 2015 16:20:11 -0500 Subject: [PATCH 4/4] TST: Explicitly skip versioning tests. The test had a check for a pandas version (0.12.0) which was out of date with the version in requirements, meaning the tests have not been run regularly and unstable. Skip via the decorator to make it more noticeable that tests are not being run. --- tests/test_versioning.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/tests/test_versioning.py b/tests/test_versioning.py index 2a5c077a..3a1b5ff4 100644 --- a/tests/test_versioning.py +++ b/tests/test_versioning.py @@ -14,11 +14,10 @@ # limitations under the License. import os -import pandas import pickle from nose_parameterized import parameterized -from unittest import TestCase +from unittest import TestCase, skip from zipline.finance.blotter import Order @@ -51,6 +50,7 @@ class VersioningTestCase(TestCase): # Only test versioning in minutely mode right now @parameterized.expand(object_serialization_cases(skip_daily=True)) + @skip def test_object_serialization(self, _, cls, @@ -58,14 +58,6 @@ class VersioningTestCase(TestCase): di_vars, comparison_method='dict'): - # The state generated under one version of pandas may not be - # compatible with another. To ensure that tests pass under the travis - # pandas version matrix, we only run versioning tests under the - # current version of pandas. This will need to be updated once we - # change the pandas version on prod. - if pandas.__version__ != '0.12.0': - return - # Make reference object obj = cls(*initargs) for k, v in di_vars.items():