From a3b49bfcebb3dc2233953a18a21c59995c155199 Mon Sep 17 00:00:00 2001 From: Juan Pablo Amoroso Date: Thu, 30 May 2019 12:27:36 -0300 Subject: [PATCH] Fixed filter composition with or. Now takes account of operator precedence --- backtester/datahandler/schema.py | 12 +++++------- backtester/test/datahandler/test_filter.py | 16 +++++++++++++--- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/backtester/datahandler/schema.py b/backtester/datahandler/schema.py index 8dfb185..f8acb31 100644 --- a/backtester/datahandler/schema.py +++ b/backtester/datahandler/schema.py @@ -76,17 +76,15 @@ class Filter: def __init__(self, query): self.query = query - def _compose_filter(self, operator, other): + def __and__(self, other): assert isinstance(other, Filter) - - new_query = "({}) {} ({})".format(self.query, operator, other.query) + new_query = "({}) & ({})".format(self.query, other.query) return Filter(query=new_query) - def __and__(self, other): - return self._compose_filter("&", other) - def __or__(self, other): - return self._compose_filter("|", other) + assert isinstance(other, Filter) + new_query = "(({}) | ({}))".format(self.query, other.query) + return Filter(query=new_query) def __invert__(self): return Filter("!({})".format(self.query)) diff --git a/backtester/test/datahandler/test_filter.py b/backtester/test/datahandler/test_filter.py index 944731b..e9ca48d 100644 --- a/backtester/test/datahandler/test_filter.py +++ b/backtester/test/datahandler/test_filter.py @@ -43,7 +43,17 @@ def test_compose_filters_with_and(): def test_compose_filters_with_or(): """Test composition of two filters with or""" strike_field = Field("strike", "strike") - ft1 = strike_field >= 100 - ft2 = strike_field < 200 + ft1 = strike_field >= 200 + ft2 = strike_field < 100 composed = ft1 | ft2 - assert composed.query == "(strike >= 100) | (strike < 200)" + assert composed.query == "((strike >= 200) | (strike < 100))" + + +def test_compose_many_filters(): + symbol_field = Field("underlying", "underlying") + strike_field = Field("strike", "strike") + ft1 = symbol_field == "SPX" + ft2 = strike_field >= 200 + ft3 = strike_field < 100 + composed = ft1 & (ft2 | ft3) + assert composed.query == "(underlying == 'SPX') & (((strike >= 200) | (strike < 100)))"