From d3f61ce63e5d3dd0146569d14bb03fd208c4fb6c Mon Sep 17 00:00:00 2001 From: Guillaume De Saint Martin Date: Wed, 16 Oct 2024 18:48:51 +0200 Subject: [PATCH] [TradingView] make signal parsing more flexible --- .../test_trading_view_signals_trading.py | 52 +++++++++++++++++++ .../trading_view_signals_trading.py | 30 +++++++---- 2 files changed, 72 insertions(+), 10 deletions(-) diff --git a/Trading/Mode/trading_view_signals_trading_mode/tests/test_trading_view_signals_trading.py b/Trading/Mode/trading_view_signals_trading_mode/tests/test_trading_view_signals_trading.py index 0db69dc44..f950b0674 100644 --- a/Trading/Mode/trading_view_signals_trading_mode/tests/test_trading_view_signals_trading.py +++ b/Trading/Mode/trading_view_signals_trading_mode/tests/test_trading_view_signals_trading.py @@ -109,6 +109,58 @@ async def _stop(exchange_manager): await asyncio_tools.wait_asyncio_next_cycle() +async def test_parse_signal_data(): + errors = [] + assert Mode.TradingViewSignalsTradingMode.parse_signal_data( + """ + KEY=value + EXCHANGE=1 + PLOp=true + """, + errors + ) == { + "KEY": "value", + "EXCHANGE": "1", + "PLOp": True, + } + assert errors == [] + + errors = [] + assert Mode.TradingViewSignalsTradingMode.parse_signal_data( + "KEY=value\nEXCHANGE=1\nPLOp=false\n", + errors + ) == { + "KEY": "value", + "EXCHANGE": "1", + "PLOp": False, + } + assert errors == [] + + errors = [] + assert Mode.TradingViewSignalsTradingMode.parse_signal_data( + "KEY=value\\nEXCHANGE=1\\nPLOp=ABC", + errors + ) == { + "KEY": "value", + "EXCHANGE": "1", + "PLOp": "ABC", + } + assert errors == [] + + errors = [] + assert Mode.TradingViewSignalsTradingMode.parse_signal_data( + "KEY=value\\nEXCHANGE\\nPLOp=ABC", + errors + ) == { + "KEY": "value", + "PLOp": "ABC", + } + assert len(errors) == 1 + assert "EXCHANGE" in str(errors[0]) + assert "nPLOp" not in str(errors[0]) + assert "KEY" not in str(errors[0]) + + async def test_trading_view_signal_callback(tools): exchange_manager, symbol, mode, producer, consumer = tools context = script_keywords.get_base_context(producer.trading_mode) diff --git a/Trading/Mode/trading_view_signals_trading_mode/trading_view_signals_trading.py b/Trading/Mode/trading_view_signals_trading_mode/trading_view_signals_trading.py index a76a9979d..fce9d3c4f 100644 --- a/Trading/Mode/trading_view_signals_trading_mode/trading_view_signals_trading.py +++ b/Trading/Mode/trading_view_signals_trading_mode/trading_view_signals_trading.py @@ -127,19 +127,20 @@ async def create_consumers(self) -> list: consumers = await super().create_consumers() return consumers + await self._get_feed_consumers() - def _adapt_symbol(self, parsed_data): - if self.SYMBOL_KEY not in parsed_data: + @classmethod + def _adapt_symbol(cls, parsed_data): + if cls.SYMBOL_KEY not in parsed_data: return - symbol = parsed_data[self.SYMBOL_KEY] - for suffix in self.TRADINGVIEW_FUTURES_SUFFIXES: + symbol = parsed_data[cls.SYMBOL_KEY] + for suffix in cls.TRADINGVIEW_FUTURES_SUFFIXES: if symbol.endswith(suffix): - parsed_data[self.SYMBOL_KEY] = symbol.split(suffix)[0] + parsed_data[cls.SYMBOL_KEY] = symbol.split(suffix)[0] return - async def _trading_view_signal_callback(self, data): + @classmethod + def parse_signal_data(cls, signal_data: str, errors: list) -> dict: parsed_data = {} - signal_data = data.get("metadata", "") - for line in signal_data.split("\n"): + for line in signal_data.replace("\\n", "\n").split("\n"): if not line.strip(): # ignore empty lines continue @@ -152,9 +153,18 @@ async def _trading_view_signal_callback(self, data): value = lower_val == "true" parsed_data[values[0].strip()] = value except IndexError: - self.logger.error(f"Invalid signal line in trading view signal, ignoring it. Line: \"{line}\"") + errors.append(f"Invalid signal line in trading view signal, ignoring it. Line: \"{line}\"") - self._adapt_symbol(parsed_data) + cls._adapt_symbol(parsed_data) + return parsed_data + + + async def _trading_view_signal_callback(self, data): + signal_data = data.get("metadata", "") + errors = [] + parsed_data = self.parse_signal_data(signal_data, errors) + for error in errors: + self.logger.error(error) try: if parsed_data[self.EXCHANGE_KEY].lower() in self.exchange_manager.exchange_name and \ (parsed_data[self.SYMBOL_KEY] == self.merged_simple_symbol or