diff --git a/beanprice/price.py b/beanprice/price.py index 66348f4..225854e 100644 --- a/beanprice/price.py +++ b/beanprice/price.py @@ -164,12 +164,17 @@ def parse_single_source(source: str) -> PriceSource: Raises: ValueError: If invalid. """ - match = re.match(r"([a-zA-Z]+[a-zA-Z0-9\._]+)/(\^?)([a-zA-Z0-9:=_\-\.\(\)]+)$", source) + match = re.match( + r"([a-zA-Z]+[a-zA-Z0-9\._]+)/(\^*)([a-zA-Z0-9:=_\-\.\(\)\^]+)$", source + ) if not match: raise ValueError('Invalid source name: "{}"'.format(source)) - short_module_name, invert, symbol = match.groups() + short_module_name, carets, symbol = match.groups() module = import_source(short_module_name) - return PriceSource(module, symbol, bool(invert)) + invert = len(carets) % 2 == 1 + # Every pair of carets is replaced by a single caret in the ticker. + actual_symbol = ("^" * (len(carets) // 2)) + symbol + return PriceSource(module, actual_symbol, invert) def import_source(module_name: str): diff --git a/beanprice/price_test.py b/beanprice/price_test.py index 53bced0..443f68b 100644 --- a/beanprice/price_test.py +++ b/beanprice/price_test.py @@ -372,6 +372,18 @@ def test_source_valid(self): psource = price.parse_single_source("yahoo/CNYUSD=X") self.assertEqual(PS(yahoo, "CNYUSD=X", False), psource) + psource = price.parse_single_source("yahoo/^CNYUSD=X") + self.assertEqual(PS(yahoo, "CNYUSD=X", True), psource) + + psource = price.parse_single_source("yahoo/^^GSPC") + self.assertEqual(PS(yahoo, "^GSPC", False), psource) + + psource = price.parse_single_source("yahoo/^^^GSPC") + self.assertEqual(PS(yahoo, "^GSPC", True), psource) + + psource = price.parse_single_source("yahoo/TICK^ER") + self.assertEqual(PS(yahoo, "TICK^ER", False), psource) + # Make sure that an invalid name at the tail doesn't succeed. with self.assertRaises(ValueError): psource = price.parse_single_source("yahoo/CNYUSD&X")