diff --git a/findmyorder/default_settings.toml b/findmyorder/default_settings.toml index 716a9db..f5595f8 100644 --- a/findmyorder/default_settings.toml +++ b/findmyorder/default_settings.toml @@ -14,11 +14,14 @@ [default] # Dynaconf settings verification -VALUE = "Production - Default" +# VALUE = "Production - Default" # Module Enable/Disable findmyorder_enabled = true +[default.findmyorder.template] +parser_library = "standard" +enabled = true # Keyword to be use to identify an order action_identifier = "BUY SELL LONG SHORT" # Keyword identifier for stoploss @@ -33,14 +36,12 @@ order_type_identifier = "spot future margin" leverage_type_identifier = "cross isolated" # Keyword identifier for comments comment_identifier = "comment=" - # Stoploss default value is none is provided stop_loss = 1000 # Take-Profit default value is none is provided take_profit = 1000 # Quantity default value is none is provided quantity = 1 - # Settings to enable or disable # instrument mapping instrument_mapping = true diff --git a/findmyorder/handler/__init__.py b/findmyorder/handler/__init__.py new file mode 100644 index 0000000..9047ec9 --- /dev/null +++ b/findmyorder/handler/__init__.py @@ -0,0 +1,9 @@ +""" +Supported Handlers + +""" + +from .basic import BasicHandler +from .standard import StandardHandler + +__all__ = ["StandardHandler", "BasicHandler"] diff --git a/findmyorder/handler/basic.py b/findmyorder/handler/basic.py new file mode 100644 index 0000000..d2eb018 --- /dev/null +++ b/findmyorder/handler/basic.py @@ -0,0 +1,53 @@ +""" +Basic Parser + +""" + +from pyparsing import ( + Optional, + Word, + alphas, + nums, + one_of, + pyparsing_common, +) + +from .handler import ParserClient + + +class BasicHandler(ParserClient): + + def __init__(self, **kwargs): + """ + Initialize the Handler object + + """ + + super().__init__(**kwargs) + self.client = "basic" + + async def identify_order( + self, + my_string: str, + ) -> dict: + """ + Identify an order and return a dictionary + with the order parameters + + Args: + my_string (str): Message + + Returns: + dict with the order parameters: + action, instrument + + """ + action = ( + one_of(self.action_identifier, caseless=True) + .set_results_name("action") + .set_parse_action(pyparsing_common.upcase_tokens) + ) + instrument = Word(alphas + nums).set_results_name("instrument") + order_grammar = action("action") + Optional(instrument, default=None) + order = order_grammar.parse_string(instring=my_string, parse_all=False) + return order.asDict() diff --git a/findmyorder/handler/handler.py b/findmyorder/handler/handler.py new file mode 100644 index 0000000..e924a77 --- /dev/null +++ b/findmyorder/handler/handler.py @@ -0,0 +1,125 @@ +from datetime import datetime, timezone + +from loguru import logger + + +class ParserClient: + """ + Parser Handler Base Class + + Args: + **kwargs: + + Methods: + search(self) + identify_order(self) + get_order(self) + replace_instrument(self) + + """ + + def __init__(self, **kwargs): + """ + Initialize the chat client. + """ + self.name = kwargs.get("name", None) + self.client = None + self.enabled = kwargs.get("enabled", None) + self.action_identifier = kwargs.get("action_identifier", "BUY SELL") + self.action_identifier = self.action_identifier.lower() + self.stop_loss_identifier = kwargs.get("stop_loss_identifier", None) + self.take_profit_identifier = kwargs.get("take_profit_identifier", None) + self.quantity_identifier = kwargs.get("quantity_identifier", None) + self.order_type_identifier = kwargs.get("order_type_identifier", None) + self.leverage_type_identifier = kwargs.get("leverage_type_identifier", None) + self.comment_identifier = kwargs.get("comment_identifier", None) + self.stop_loss = kwargs.get("stop_loss", None) + self.take_profit = kwargs.get("take_profit", None) + self.quantity = kwargs.get("quantity", None) + self.instrument_mapping = kwargs.get("instrument_mapping", None) + self.mapping = kwargs.get("mapping", None) + self.ignore_instrument = kwargs.get("ignore_instrument", None) + + async def identify_order( + self, + my_string: str, + ) -> dict: + """ + Identify an order and return a dictionary + with the order parameters to be implemented in + the child class + + """ + + async def search(self, message: str) -> bool: + """ + Search an order. + + Args: + message (str): Message + + Returns: + bool + + """ + if message: + order_identifier = message.split()[0].lower() + # logger.debug("Order identifier: {}", order_identifier) + # logger.debug("Action identifiers: {}", self.action_identifiers) + if order_identifier in self.action_identifier: + + # logger.debug("Order identifier found in {}", order_identifier) + return True + + return False + + async def replace_instrument(self, order): + """ + Replace instrument by an alternative instrument, if the + instrument is not in the mapping, it will be ignored. + + Args: + order (dict): + + Returns: + dict + """ + instrument = order["instrument"] + for item in self.mapping: + if item["id"] == instrument: + order["instrument"] = item["alt"] + break + logger.debug("Instrument symbol changed", order) + return order + + async def get_order( + self, + msg: str, + ): + """ + Get an order from a message. The message can be + an order or an order identifier + + Args: + msg (str): Message + + Returns: + dict + + """ + if not await self.search(msg): + logger.debug("No order identified") + return None + order = await self.identify_order(msg) + if isinstance(order, dict): + order["timestamp"] = datetime.now(timezone.utc).strftime( + "%Y-%m-%dT%H:%M:%SZ" + ) + if self.instrument_mapping: + logger.debug("mapping") + await self.replace_instrument(order) + if order["instrument"] in self.ignore_instrument: + logger.debug("Ignoring instrument {}", order["instrument"]) + return + logger.debug("Order identified {}", order) + return order diff --git a/findmyorder/handler/standard.py b/findmyorder/handler/standard.py new file mode 100644 index 0000000..efad238 --- /dev/null +++ b/findmyorder/handler/standard.py @@ -0,0 +1,91 @@ +""" +Standard Parser + +""" + +from loguru import logger +from pyparsing import ( + Combine, + Optional, + Suppress, + Word, + alphas, + nums, + one_of, + pyparsing_common, +) + +from .handler import ParserClient + + +class StandardHandler(ParserClient): + + def __init__(self, **kwargs): + """ + Initialize the Handler object + + """ + + super().__init__(**kwargs) + self.client = "standard" + + async def identify_order( + self, + my_string: str, + ) -> dict: + """ + Identify an order and return a dictionary + with the order parameters + + Args: + my_string (str): Message + + Returns: + dict + + """ + if not await self.search(my_string): + logger.debug("No order identified") + return None + else: + action = ( + one_of(self.action_identifier, caseless=True) + .set_results_name("action") + .set_parse_action(pyparsing_common.upcase_tokens) + ) + instrument = Word(alphas + nums).set_results_name("instrument") + stop_loss = Combine( + Suppress(self.stop_loss_identifier) + Word(nums) + ).set_results_name("stop_loss") + take_profit = Combine( + Suppress(self.take_profit_identifier) + Word(nums) + ).set_results_name("take_profit") + quantity = Combine( + Suppress(self.quantity_identifier) + + Word(nums) + + Optional(Suppress("%")) + ).set_results_name("quantity") + order_type = one_of( + self.order_type_identifier, caseless=True + ).set_results_name("order_type") + leverage_type = one_of( + self.leverage_type_identifier, caseless=True + ).set_results_name("leverage_type") + comment = Combine( + Suppress(self.comment_identifier) + Word(alphas) + ).set_results_name("comment") + + order_grammar = ( + action("action") + + Optional(instrument, default=None) + + Optional(stop_loss, default=self.stop_loss) + + Optional(take_profit, default=self.take_profit) + + Optional(quantity, default=self.quantity) + + Optional(order_type, default=None) + + Optional(leverage_type, default=None) + + Optional(comment, default=None) + ) + + order = order_grammar.parse_string(instring=my_string, parse_all=False) + logger.debug("Order parsed {}", order) + return order.asDict() diff --git a/findmyorder/main.py b/findmyorder/main.py index d7412f5..23cb0ca 100644 --- a/findmyorder/main.py +++ b/findmyorder/main.py @@ -3,19 +3,9 @@ """ -from datetime import datetime +import importlib from loguru import logger -from pyparsing import ( - Combine, - Optional, - Suppress, - Word, - alphas, - nums, - one_of, - pyparsing_common, -) from findmyorder import __version__ @@ -54,24 +44,98 @@ def __init__( None """ - async def search(self, my_string: str) -> bool: + self.enabled = settings.findmyorder_enabled + if not self.enabled: + logger.info("Module is disabled. No Client will be created.") + return + self.client_classes = self.get_all_client_classes() + self.clients = [] + # Create a client for each client in settings + for name, client_config in settings.findmyorder.items(): + if ( + # Skip empty client configs + client_config is None + # Skip non-dict client configs + or not isinstance(client_config, dict) + # Skip template and empty string client names + or name in ["", "template"] + # Skip disabled clients + or not client_config.get("enabled") + ): + continue + + # Create the client + logger.debug("Creating FMO parser {}", name) + client = self._create_client(**client_config, name=name) + # If the client has a valid client attribute, append it to the list + if client and getattr(client, "client", None): + self.clients.append(client) + + # Log the number of clients that were created + logger.info(f"Loaded {len(self.clients)} clients") + if not self.clients: + logger.warning( + "No Client were created. Check your settings or disable the module." + ) + + def _create_client(self, **kwargs): """ - Search an order. + Create a client based on the given protocol. - Args: - my_string (str): Message + This function takes in a dictionary of keyword arguments, `kwargs`, + containing the necessary information to create a client. The required + key in `kwargs` is "parser_library", which specifies the parser to use + to identify the order. The value of "parser_library" must match one of the + libraries supported by findmyorder. + + This function retrieves the class used to create the client based on the + value of "parser_library" from the mapping of parser names to client classes + stored in `self.client_classes`. If the value of "parser_library" does not + match any of the libraries supported, the function logs an error message + and returns None. + + If the class used to create the client is found, the function creates a + new instance of the class using the keyword arguments in `kwargs` and + returns it. + + The function returns a client object based on the specified protocol + or None if the library is not supported. + + Parameters: + **kwargs (dict): A dictionary of keyword arguments containing the + necessary information for creating the client. The required key is + "parser_library". Returns: - bool + A client object based on the specified protocol or None if the + library is not supported. """ - if my_string: - string_check = my_string.split()[0].lower() - # logger.debug("Searching order identifier in {}", string_check) - if string_check in settings.action_identifier.lower(): - logger.debug("Order identifier found in {}", string_check) - return True - return False + library = kwargs.get("parser_library", "standard") + cls = self.client_classes.get((f"{library.capitalize()}Handler")) + return None if cls is None else cls(**kwargs) + + def get_all_client_classes(self): + """ + Retrieves all client classes from the `findmyorder.handler` module. + + This function imports the `findmyorder.handler` module and retrieves + all the classes defined in it. + + The function returns a dictionary where the keys are the + names of the classes and the values are the corresponding + class objects. + + Returns: + dict: A dictionary containing all the client classes + from the `findmyorder.handler` module. + """ + provider_module = importlib.import_module("findmyorder.handler") + return { + name: cls + for name, cls in provider_module.__dict__.items() + if isinstance(cls, type) + } async def get_info(self): """ @@ -81,115 +145,55 @@ async def get_info(self): str """ - return f"{__class__.__name__} {__version__}\n" + version_info = f"ℹ️ {type(self).__name__} {__version__}\n" + client_info = "".join(f"🔎 {client.name}\n" for client in self.clients) + return version_info + client_info.strip() - async def identify_order( - self, - my_string: str, - ) -> dict: + async def search(self, message: str) -> bool: """ - Identify an order and return a dictionary - with the order parameters + Search an order. Args: - my_string (str): Message + message (str): Message Returns: - dict + bool """ - try: - action = ( - one_of(settings.action_identifier, caseless=True) - .set_results_name("action") - .set_parse_action(pyparsing_common.upcase_tokens) - ) - instrument = Word(alphas + nums).set_results_name("instrument") - stop_loss = Combine( - Suppress(settings.stop_loss_identifier) + Word(nums) - ).set_results_name("stop_loss") - take_profit = Combine( - Suppress(settings.take_profit_identifier) + Word(nums) - ).set_results_name("take_profit") - quantity = Combine( - Suppress(settings.quantity_identifier) - + Word(nums) - + Optional(Suppress("%")) - ).set_results_name("quantity") - order_type = one_of( - settings.order_type_identifier, caseless=True - ).set_results_name("order_type") - leverage_type = one_of( - settings.leverage_type_identifier, caseless=True - ).set_results_name("leverage_type") - comment = Combine( - Suppress(settings.comment_identifier) + Word(alphas) - ).set_results_name("comment") - - order_grammar = ( - action("action") - + Optional(instrument, default=None) - + Optional(stop_loss, default=settings.stop_loss) - + Optional(take_profit, default=settings.take_profit) - + Optional(quantity, default=settings.quantity) - + Optional(order_type, default=None) - + Optional(leverage_type, default=None) - + Optional(comment, default=None) - ) - - order = order_grammar.parse_string(instring=my_string, parse_all=False) - logger.debug("Order parsed {}", order) - return order.asDict() - - except Exception as error: - logger.error(error) - return error + for client in self.clients: + logger.debug("Searching with client: {}", client) + if await client.search(message): + return True + return False - async def get_order( - self, - msg: str, - ): + async def identify_order(self, message: str) -> bool: """ - Get an order from a message. The message can be - an order or an order identifier + Search an order. Args: - msg (str): Message + message (str): Message Returns: - dict + bool """ - if not await self.search(msg): - logger.debug("No order identified") - return None - order = await self.identify_order(msg) - if isinstance(order, dict): - order["timestamp"] = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ") - if settings.instrument_mapping: - logger.debug("mapping") - await self.replace_instrument(order) - if order["instrument"] in settings.ignore_instrument: - logger.debug("Ignoring instrument {}", order["instrument"]) - return - logger.debug("Order identified {}", order) - return order + for client in self.clients: + return await client.identify_order(message) - async def replace_instrument(self, order): + async def get_order( + self, + message: str, + ): """ - Replace instrument by an alternative instrument, if the - instrument is not in the mapping, it will be ignored. + Get an order from a message. The message can be + an order or an order identifier Args: - order (dict): + message (str): Message Returns: dict + """ - instrument = order["instrument"] - for item in settings.mapping: - if item["id"] == instrument: - order["instrument"] = item["alt"] - break - logger.debug("Instrument symbol changed", order) - return order + for client in self.clients: + return await client.get_order(message) diff --git a/pyproject.toml b/pyproject.toml index df40851..5294f1b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ pyparsing = "^3.0.9" [tool.poetry.group.dev.dependencies] python-semantic-release = ">=8.0.8" -ruff = "^0.4.0" +ruff = "^0.5.0" black = "^24.0.0" pre-commit = "^3.3.1" @@ -142,6 +142,7 @@ addopts = """ -v --show-capture=stderr """ +asyncio_mode = "auto" [tool.coverage.run] omit = [ diff --git a/tests/test_unit.py b/tests/test_unit.py index 16acc3b..7c78ef5 100644 --- a/tests/test_unit.py +++ b/tests/test_unit.py @@ -12,8 +12,7 @@ @pytest.fixture(scope="session", autouse=True) def set_test_settings(): - settings.configure(FORCE_ENV_FOR_DYNACONF="testing") - + settings.configure(FORCE_ENV_FOR_DYNACONF="fmo") @pytest.fixture(name="fmo") @@ -25,35 +24,7 @@ def fmo(): @pytest.fixture def order(): """return valid order""" - return "buy EURUSD sl=200 tp=400 q=2%" - - -@pytest.fixture -def short_order(): - """return valid order""" - return "Buy EURUSD" - - -@pytest.fixture -def order_2(): - """return order 2""" - return """ - 📊 FUTURES Exchanges: Binance, ByBit USDT - - #AAVEUSDT - - 🟢LONG ENTRY :- 65.20 - 63.70 - - Leverage: Cross (2X) - - 👇TAKE PROFIT - - 1) 65.70 - 2) 66.20 - 3) 66.70 - - Stop Loss : - 62.00 -""" + return "buy GOLD sl=200 tp=400 q=2%" @pytest.fixture @@ -61,7 +32,7 @@ def result_order(): """return standard expected results""" return { "action": "BUY", - "instrument": "EURUSD", + "instrument": "XAUUSD", "stop_loss": 200, "take_profit": 400, "quantity": 2, @@ -79,40 +50,9 @@ def ignore_order(): @pytest.fixture -def crypto_order(): - """return valid order""" - return "SHORT ETH sl=200 tp=400 q=2%" - - -@pytest.fixture -def crypto_short_order(): - """return valid order""" - return "Sell ETH" - - -@pytest.fixture -def result_crypto_order(): - """return standard expected results""" - return { - "action": "SHORT", - "instrument": "WETH", - "stop_loss": 1000, - "take_profit": 1000, - "quantity": 10, - "order_type": None, - "leverage_type": None, - "comment": None, - "timestamp": datetime.now(), - } - - -@pytest.fixture -def order_with_emoji(): - """return emoji type order""" - return """⚡️⚡️ #BNB/USDT ⚡️⚡️ - Exchanges: ByBit USDT, Binance Futures - Signal Type: Regular (Long) - Leverage: Cross (20.0X)""" +def invalid_order(): + """return fmo""" + return "This is not an order" @pytest.fixture @@ -120,12 +60,6 @@ def bot_command(): return "/bal" -@pytest.fixture -def invalid_order(): - """return fmo""" - return "This is not an order" - - @pytest.mark.asyncio async def test_settings(): """Search Testing""" @@ -139,13 +73,15 @@ async def test_info(fmo): result = await fmo.get_info() print(result) assert result is not None - assert str(result).startswith("FindMyOrder") + assert "FindMyOrder" in result + assert "ℹ️" in result @pytest.mark.asyncio -async def test_search_valid_order(fmo, crypto_order): +async def test_search_valid_order(fmo, order): """Search Testing""" - assert await fmo.search(crypto_order) is True + print(settings) + assert await fmo.search(order) is True @pytest.mark.asyncio @@ -168,21 +104,9 @@ async def test_search_exception(fmo): @pytest.mark.asyncio -async def test_search_normal_order(fmo, order): - """Search Testing""" - assert await fmo.search(order) is True - - -@pytest.mark.asyncio -async def test_search_normal_order_variation(fmo, crypto_order): - """Search Testing""" - assert await fmo.search(crypto_order) is True - - -@pytest.mark.asyncio -async def test_identify_order(fmo, short_order): +async def test_identify_order(fmo, order): """Identify Testing""" - result = await fmo.identify_order(short_order) + result = await fmo.identify_order(order) assert result is not None @@ -190,31 +114,16 @@ async def test_identify_order(fmo, short_order): async def test_identify_order_invalid_input(fmo, invalid_order): """Identify Testing""" result = await fmo.identify_order(invalid_order) - assert str(result).startswith("Expected") + print(result) + assert result is None @pytest.mark.asyncio -async def test_valid_get_order(fmo, order, result_order): - """get order Testing""" +async def test_replace_instrument(fmo, order, result_order): + """replace instrument Testing""" result = await fmo.get_order(order) - assert result["action"] == result_order["action"] - assert result["instrument"] == result_order["instrument"] - assert int(result["stop_loss"]) == result_order["stop_loss"] - assert int(result["take_profit"]) == result_order["take_profit"] - assert int(result["quantity"]) == result_order["quantity"] - assert result["order_type"] == result_order["order_type"] - assert result["leverage_type"] == result_order["leverage_type"] - assert result["comment"] == result_order["comment"] - assert type(result["timestamp"] is datetime) - - -@pytest.mark.asyncio -async def test_short_valid_get_order(fmo, short_order, result_order): - """get order Testing""" - result = await fmo.get_order(short_order) - assert result["action"] == result_order["action"] + print(result) assert result["instrument"] == result_order["instrument"] - assert int(result["quantity"]) == 1 assert type(result["timestamp"] is datetime) @@ -233,19 +142,28 @@ async def test_invalid_get_order(fmo, invalid_order): @pytest.mark.asyncio -async def test_mapping_order(fmo, crypto_short_order, result_crypto_order): - """replace instrument Testing""" - result = await fmo.get_order(crypto_short_order) +async def test_standard_get_order(fmo, order, result_order): + """get order Testing""" + result = await fmo.get_order(order) print(result) - assert settings.instrument_mapping is True - assert result["instrument"] == result_crypto_order["instrument"] + assert result["action"] == result_order["action"] + assert result["instrument"] == result_order["instrument"] + assert int(result["stop_loss"]) == result_order["stop_loss"] + assert int(result["take_profit"]) == result_order["take_profit"] + assert int(result["quantity"]) == result_order["quantity"] + assert result["order_type"] == result_order["order_type"] + assert result["leverage_type"] == result_order["leverage_type"] + assert result["comment"] == result_order["comment"] assert type(result["timestamp"] is datetime) -@pytest.mark.asyncio -async def test_identify_order2(fmo, order_2): - """Identify Testing""" - result = await fmo.identify_order(order_2) - assert result is not None - # result = await fmo.get_order(order_2) - # assert result["action"] == "LONG" +# @pytest.mark.asyncio +# async def test_create_client_exception(fmo, caplog): +# result = fmo.create_client() +# assert result is not None +# assert any( +# record.message +# == "No Client were created. Check your settings or disable the module." +# for record in caplog.records +# if record.levelname == "WARNING" +# ) diff --git a/tests/test_unit_exception.py b/tests/test_unit_exception.py new file mode 100644 index 0000000..83ba5df --- /dev/null +++ b/tests/test_unit_exception.py @@ -0,0 +1,39 @@ +""" +FindMyOrder Exception Testing +""" + +import pytest + +from findmyorder import FindMyOrder +from findmyorder.config import settings + + +@pytest.fixture(scope="session", autouse=True) +def set_test_settings(): + settings.configure(FORCE_ENV_FOR_DYNACONF="exception") + + +@pytest.mark.asyncio +async def test_module_exception(caplog): + result = FindMyOrder() + print(result) + assert any( + record.message == "Module is disabled. No Client will be created." + for record in caplog.records + if record.levelname == "INFO" + ) + + +# @pytest.mark.asyncio +async def test_create_client_exception(caplog): + settings.findmyorder_enabled = True + test_class = FindMyOrder() + result = test_class._create_client() + print(result) + assert result is not None + assert any( + record.message + == "No Client were created. Check your settings or disable the module." + for record in caplog.records + if record.levelname == "WARNING" + ) diff --git a/tests/test_unit_format_basic.py b/tests/test_unit_format_basic.py new file mode 100644 index 0000000..3f730db --- /dev/null +++ b/tests/test_unit_format_basic.py @@ -0,0 +1,60 @@ +""" +FindMyOrder Unit Testing +""" + +from datetime import datetime + +import pytest + +from findmyorder import FindMyOrder +from findmyorder.config import settings + + +@pytest.fixture(scope="session", autouse=True) +def set_test_settings(): + settings.configure(FORCE_ENV_FOR_DYNACONF="basic") + + +@pytest.fixture(name="fmo") +def fmo(): + """return fmo""" + return FindMyOrder() + + +@pytest.fixture +def order(): + """return valid order""" + return "Short ETH" + + +@pytest.fixture +def result_order(): + """return standard expected results""" + return { + "action": "SHORT", + "instrument": "WETH", + "timestamp": datetime.now(), + } + + +@pytest.mark.asyncio +async def test_settings(): + """Search Testing""" + assert settings.VALUE == "On Testing" + assert settings.findmyorder_enabled is True + + +@pytest.mark.asyncio +async def test_identify_order(fmo, order, result_order): + """Identify Testing""" + result = await fmo.identify_order(order) + assert result is not None + + +async def test_standard_get_order(fmo, order, result_order): + """get order Testing""" + result = await fmo.get_order(order) + print(result) + assert result["action"] == result_order["action"] + assert result["instrument"] == result_order["instrument"] + assert type(result["timestamp"] is datetime) diff --git a/tests/test_unit_format_future.py b/tests/test_unit_format_future.py new file mode 100644 index 0000000..66715d9 --- /dev/null +++ b/tests/test_unit_format_future.py @@ -0,0 +1,131 @@ +# """ +# FindMyOrder Unit Testing +# """ + +# from datetime import datetime + +# import pytest + +# from findmyorder import FindMyOrder +# from findmyorder.config import settings + + +# @pytest.fixture(scope="session", autouse=True) +# def set_test_settings(): +# settings.configure(FORCE_ENV_FOR_DYNACONF="fmo") + + +# @pytest.fixture(name="fmo") +# def fmo(): +# """return fmo""" +# return FindMyOrder() + + +# @pytest.fixture +# def order_format_2(): +# """return order 2""" +# return """ +# 📊 FUTURES Exchanges: Binance, ByBit USDT + +# #AAVEUSDT + +# 🟢LONG ENTRY :- 65.20 - 63.70 + +# Leverage: Cross (2X) + +# 👇TAKE PROFIT + +# 1) 65.70 +# 2) 66.20 +# 3) 66.70 + +# Stop Loss : - 62.00 +# """ + + +# @pytest.fixture +# def order_format_3(): +# """return emoji type order""" +# return """⚡️⚡️ #BNB/USDT ⚡️⚡️ +# Exchanges: ByBit USDT, Binance Futures +# Signal Type: Regular (Long) +# Leverage: Cross (20.0X)""" + + +# @pytest.fixture +# def result_order(): +# """return standard expected results""" +# return { +# "action": "BUY", +# "instrument": "EURUSD", +# "stop_loss": 200, +# "take_profit": 400, +# "quantity": 2, +# "order_type": None, +# "leverage_type": None, +# "comment": None, +# "timestamp": datetime.now(), +# } + +# @pytest.mark.asyncio +# async def test_settings(): +# """Search Testing""" +# assert settings.VALUE == "On Testing" +# assert settings.findmyorder_enabled is True + +# @pytest.mark.asyncio +# async def test_identify_order_2(fmo, order_format_2): +# """Identify Testing""" +# result = await fmo.identify_order(order_format_2) +# assert result is None + + +# @pytest.mark.asyncio +# async def test_identify_order_3(fmo, order_format_3): +# """Identify Testing""" +# result = await fmo.identify_order(order_format_3) +# assert result is None + + +# @pytest.mark.asyncio +# async def test_identify_order_2(fmo, order_format_2): +# """Identify Testing""" +# result = await fmo.identify_order(order_format_2) +# assert result is None + + +# @pytest.mark.asyncio +# async def test_identify_order_3(fmo, order_format_3): +# """Identify Testing""" +# result = await fmo.identify_order(order_format_3) +# assert result is None + +# @pytest.mark.asyncio +# async def test_basic_valid_get_order(fmo, order_basic, result_order): +# """get order Testing""" +# result = await fmo.get_order(order_basic) +# assert result["action"] == result_order["action"] +# assert result["instrument"] == result_order["instrument"] +# assert int(result["quantity"]) == 1 +# assert type(result["timestamp"] is datetime) + + +# async def test_standard_get_order(fmo, order_standard, result_order): +# """get order Testing""" +# result = await fmo.get_order(order_standard) +# print(result) +# assert result["action"] == result_order["action"] +# assert result["instrument"] == result_order["instrument"] +# assert int(result["stop_loss"]) == result_order["stop_loss"] +# assert int(result["take_profit"]) == result_order["take_profit"] +# assert int(result["quantity"]) == result_order["quantity"] +# assert result["order_type"] == result_order["order_type"] +# assert result["leverage_type"] == result_order["leverage_type"] +# assert result["comment"] == result_order["comment"] +# assert type(result["timestamp"] is datetime) + + +# async def test_create_client_exception(fmo, caplog): +# result = fmo.create_client(parser_library="none") +# assert result is not None +# assert "No Client were created" in caplog.text