diff --git a/gamestonk_terminal/portfolio/brokers/degiro/degiro_controller.py b/gamestonk_terminal/portfolio/brokers/degiro/degiro_controller.py index 3071c88be4e..634dfbfcea4 100644 --- a/gamestonk_terminal/portfolio/brokers/degiro/degiro_controller.py +++ b/gamestonk_terminal/portfolio/brokers/degiro/degiro_controller.py @@ -2,7 +2,6 @@ import argparse from typing import List from prompt_toolkit.completion import NestedCompleter -from gamestonk_terminal.rich_config import console import gamestonk_terminal.config_terminal as config from gamestonk_terminal import feature_flags as gtff @@ -30,7 +29,7 @@ class DegiroController(BaseController): "topnews", "update", ] - PATH = "/portfolio/bro/derigo/" + PATH = "/portfolio/bro/degiro/" def __init__(self, queue: List[str] = None): """Constructor""" @@ -44,25 +43,9 @@ class DegiroController(BaseController): def print_help(self): """Print help.""" - help_text = """ - login connect to degiro's api - logout disconnect from degiro's api + DegiroView.help_display() - hold view holdings - lookup view search for a product by name - - create create an order - update update an order - cancel cancel an order using the id - pending view pending orders - - companynews view news about a company with it's isin - lastnews view latest news - topnews view top news preview - """ - console.print(text=help_text, menu="Portfolio - Brokers - Degiro") - - def cancel(self, other_args: List[str]): + def call_cancel(self, other_args: List[str]): """Cancel an order using the `id`.""" # PARSE ARGS @@ -79,7 +62,7 @@ class DegiroController(BaseController): self.__degiro_view.cancel(ns_parser=ns_parser) - def companynews(self, other_args: List[str]): + def call_companynews(self, other_args: List[str]): """Display news related to a company using its ISIN.""" # PARSE ARGS @@ -96,7 +79,7 @@ class DegiroController(BaseController): self.__degiro_view.companynews(ns_parser=ns_parser) - def create(self, other_args: List[str]): + def call_create(self, other_args: List[str]): """Create an order.""" # PARSE ARGS @@ -174,7 +157,7 @@ class DegiroController(BaseController): self.__degiro_view.create(ns_parser=ns_parser) - def hold(self, other_args): + def call_hold(self, other_args): """Display held products.""" # PARSE ARGS @@ -186,7 +169,7 @@ class DegiroController(BaseController): self.__degiro_view.hold(ns_parser=ns_parser) - def lastnews(self, other_args: List[str]): + def call_lastnews(self, other_args: List[str]): """Display latest news.""" # PARSE ARGS @@ -206,7 +189,7 @@ class DegiroController(BaseController): self.__degiro_view.lastnews(ns_parser=ns_parser) - def login(self, other_args: List[str]): + def call_login(self, other_args: List[str]): """Connect to Degiro's API.""" # PARSE ARGS @@ -246,7 +229,7 @@ class DegiroController(BaseController): self.__degiro_view.login(ns_parser=ns_parser) - def logout(self, other_args: List[str]): + def call_logout(self, other_args: List[str]): """Log out from Degiro's API.""" # PARSE ARGS @@ -258,7 +241,7 @@ class DegiroController(BaseController): self.__degiro_view.logout(ns_parser=ns_parser) - def lookup(self, other_args: List[str]): + def call_lookup(self, other_args: List[str]): """Search for products by their name.""" # PARSING ARGS @@ -289,7 +272,7 @@ class DegiroController(BaseController): self.__degiro_view.lookup(ns_parser=ns_parser) - def pending(self, other_args: List[str]): + def call_pending(self, other_args: List[str]): """Display pending orders.""" # PARSING ARGS @@ -301,7 +284,7 @@ class DegiroController(BaseController): self.__degiro_view.pending(ns_parser=ns_parser) - def topnews(self, other_args: List[str]): + def call_topnews(self, other_args: List[str]): """Display top news.""" # PARSING ARGS @@ -313,7 +296,7 @@ class DegiroController(BaseController): self.__degiro_view.topnews(ns_parser=ns_parser) - def update(self, other_args: List[str]): + def call_update(self, other_args: List[str]): """Update an order.""" # PARSING ARGS diff --git a/gamestonk_terminal/portfolio/brokers/degiro/degiro_model.py b/gamestonk_terminal/portfolio/brokers/degiro/degiro_model.py index 93f060f9d3c..73b06655fdd 100644 --- a/gamestonk_terminal/portfolio/brokers/degiro/degiro_model.py +++ b/gamestonk_terminal/portfolio/brokers/degiro/degiro_model.py @@ -249,7 +249,7 @@ class DegiroModel: return news def login(self, credentials: Credentials): - self.__trading_api = TradingAPI(credentials=credentials) + self.__trading_api.credentials.CopyFrom(credentials) self.__trading_api.connect() self.__setup_extra_credentials() diff --git a/gamestonk_terminal/portfolio/brokers/degiro/degiro_view.py b/gamestonk_terminal/portfolio/brokers/degiro/degiro_view.py index b09bfe61835..e4e7eb6ab1b 100644 --- a/gamestonk_terminal/portfolio/brokers/degiro/degiro_view.py +++ b/gamestonk_terminal/portfolio/brokers/degiro/degiro_view.py @@ -290,6 +290,10 @@ class DegiroView: credentials.username = ns_parser.username credentials.password = ns_parser.password + if "REPLACE_ME" in (credentials.username, credentials.username): + print("You didn't provide me with Degiro's credentials. Login failed.") + return + if ns_parser.otp is not None: credentials.one_time_password = ns_parser.otp if ns_parser.topt_secret is not None: diff --git a/tests/gamestonk_terminal/portfolio/brokers/__init__.py b/tests/gamestonk_terminal/portfolio/brokers/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/gamestonk_terminal/portfolio/brokers/degiro/test___init__.py b/tests/gamestonk_terminal/portfolio/brokers/degiro/test___init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/gamestonk_terminal/portfolio/brokers/degiro/test_degiro_api.py b/tests/gamestonk_terminal/portfolio/brokers/degiro/test_degiro_api.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/gamestonk_terminal/portfolio/brokers/degiro/test_degiro_controller.py b/tests/gamestonk_terminal/portfolio/brokers/degiro/test_degiro_controller.py new file mode 100644 index 00000000000..3d6105952e1 --- /dev/null +++ b/tests/gamestonk_terminal/portfolio/brokers/degiro/test_degiro_controller.py @@ -0,0 +1,314 @@ +# IMPORTATION STANDARD +import os + +# IMPORTATION THIRDPARTY +import pytest + +# IMPORTATION INTERNAL +from gamestonk_terminal.portfolio.brokers.degiro import degiro_controller + +# pylint: disable=E1101 +# pylint: disable=W0603 +# pylint: disable=E1111 + + +@pytest.mark.vcr(record_mode="none") +@pytest.mark.parametrize( + "queue, expected", + [ + (["load", "help"], []), + (["quit", "help"], ["help"]), + ], +) +def test_menu_with_queue(expected, mocker, queue): + path_controller = "gamestonk_terminal.portfolio.brokers.degiro.degiro_controller" + + # MOCK SWITCH + mocker.patch( + target=f"{path_controller}.DegiroController.switch", + return_value=["quit"], + ) + result_menu = degiro_controller.DegiroController(queue=queue).menu() + + assert result_menu == expected + + +@pytest.mark.vcr(record_mode="none") +def test_menu_without_queue_completion(mocker): + path_controller = "gamestonk_terminal.portfolio.brokers.degiro.degiro_controller" + + # ENABLE AUTO-COMPLETION : HELPER_FUNCS.MENU + mocker.patch( + target="gamestonk_terminal.feature_flags.USE_PROMPT_TOOLKIT", + new=True, + ) + mocker.patch( + target="gamestonk_terminal.parent_classes.session", + ) + mocker.patch( + target="gamestonk_terminal.parent_classes.session.prompt", + return_value="quit", + ) + + # DISABLE AUTO-COMPLETION : CONTROLLER.COMPLETER + mocker.patch.object( + target=degiro_controller.gtff, + attribute="USE_PROMPT_TOOLKIT", + new=True, + ) + mocker.patch( + target=f"{path_controller}.session", + ) + mocker.patch( + target=f"{path_controller}.session.prompt", + return_value="quit", + ) + + result_menu = degiro_controller.DegiroController(queue=None).menu() + + assert result_menu == [] + + +@pytest.mark.vcr(record_mode="none") +@pytest.mark.parametrize( + "mock_input", + ["help", "homee help", "home help", "mock"], +) +def test_menu_without_queue_sys_exit(mock_input, mocker): + path_controller = "gamestonk_terminal.portfolio.brokers.degiro.degiro_controller" + + # DISABLE AUTO-COMPLETION + mocker.patch.object( + target=degiro_controller.gtff, + attribute="USE_PROMPT_TOOLKIT", + new=False, + ) + mocker.patch( + target=f"{path_controller}.session", + return_value=None, + ) + + # MOCK USER INPUT + mocker.patch("builtins.input", return_value=mock_input) + + # MOCK SWITCH + class SystemExitSideEffect: + def __init__(self): + self.first_call = True + + def __call__(self, *args, **kwargs): + if self.first_call: + self.first_call = False + raise SystemExit() + return ["quit"] + + mock_switch = mocker.Mock(side_effect=SystemExitSideEffect()) + mocker.patch( + target=f"{path_controller}.DegiroController.switch", + new=mock_switch, + ) + + result_menu = degiro_controller.DegiroController(queue=None).menu() + + assert result_menu == [] + + +@pytest.mark.vcr(record_mode="none") +@pytest.mark.record_stdout +def test_print_help(): + controller = degiro_controller.DegiroController(queue=None) + controller.print_help() + + +@pytest.mark.vcr(record_mode="none") +@pytest.mark.parametrize( + "an_input, expected_queue", + [ + ("", []), + ("/help", ["quit", "quit", "quit", "help"]), + ("help/help", ["help"]), + ("q", ["quit"]), + ("h", []), + ( + "r", + ["quit", "quit", "quit", "reset", "portfolio", "bro", "degiro"], + ), + ], +) +def test_switch(an_input, expected_queue): + controller = degiro_controller.DegiroController(queue=None) + queue = controller.switch(an_input=an_input) + + assert queue == expected_queue + + +@pytest.mark.vcr(record_mode="none") +def test_call_cls(mocker): + mocker.patch("os.system") + + controller = degiro_controller.DegiroController(queue=None) + controller.call_cls([]) + + assert controller.queue == [] + os.system.assert_called_once_with("cls||clear") + + +@pytest.mark.vcr(record_mode="none") +@pytest.mark.parametrize( + "func, queue, expected_queue", + [ + ( + "call_exit", + [], + ["quit", "quit", "quit", "quit"], + ), + ("call_exit", ["help"], ["quit", "quit", "quit", "quit", "help"]), + ("call_home", [], ["quit", "quit", "quit"]), + ("call_help", [], []), + ("call_quit", [], ["quit"]), + ("call_quit", ["help"], ["quit", "help"]), + ( + "call_reset", + [], + ["quit", "quit", "quit", "reset", "portfolio", "bro", "degiro"], + ), + ( + "call_reset", + ["help"], + ["quit", "quit", "quit", "reset", "portfolio", "bro", "degiro", "help"], + ), + ], +) +def test_call_func_expect_queue(expected_queue, func, queue): + controller = degiro_controller.DegiroController(queue=queue) + result = getattr(controller, func)([]) + + assert result is None + assert controller.queue == expected_queue + + +@pytest.mark.vcr(record_mode="none") +@pytest.mark.parametrize( + "tested_func, other_args, mocked_func, called_args, called_kwargs", + [ + ( + "call_cancel", + [ + "MOCK_ORDER_ID", + ], + "DegiroView.cancel", + [], + dict(), + ), + ( + "call_companynews", + [ + "MOCK_ISIN", + ], + "DegiroView.companynews", + [], + dict(), + ), + ( + "call_create", + [ + "--action=buy", + "--symbol=MOCK_SYMBOL" "--price=1", + "--size=2", + ], + "DegiroView.create", + [], + dict(), + ), + ( + "call_hold", + [], + "DegiroView.hold", + [], + dict(), + ), + ( + "call_lastnews", + [ + "--limit=10", + ], + "DegiroView.lastnews", + [], + dict(), + ), + ( + "call_login", + [ + "--username=MOKC_USERNAME", + "--password=MOKC_PASSWORD", + "--topt-secret=MOCK_TOPT_SECRET", + ], + "DegiroView.login", + [], + dict(), + ), + ( + "call_logout", + [], + "DegiroView.logout", + [], + dict(), + ), + ( + "call_lookup", + [ + "MOCK_SEARCH_TEXT", + "--limit=1", + "--offset=2", + ], + "DegiroView.lookup", + [], + dict(), + ), + ( + "call_pending", + [], + "DegiroView.pending", + [], + dict(), + ), + ( + "call_topnews", + [], + "DegiroView.topnews", + [], + dict(), + ), + ( + "call_update", + [ + "--price=1", + ], + "DegiroView.update", + [], + dict(), + ), + ], +) +def test_call_func( + tested_func, mocked_func, other_args, called_args, called_kwargs, mocker +): + path_controller = "gamestonk_terminal.portfolio.brokers.degiro.degiro_controller" + + if mocked_func: + mock = mocker.Mock() + mocker.patch( + target=f"{path_controller}.{mocked_func}", + new=mock, + ) + + controller = degiro_controller.DegiroController(queue=None) + getattr(controller, tested_func)(other_args) + + if called_args or called_kwargs: + mock.assert_called_once_with(*called_args, **called_kwargs) + else: + mock.assert_called_once() + else: + controller = degiro_controller.DegiroController(queue=None) + getattr(controller, tested_func)(other_args) diff --git a/tests/gamestonk_terminal/portfolio/brokers/degiro/test_degiro_model.py b/tests/gamestonk_terminal/portfolio/brokers/degiro/test_degiro_model.py new file mode 100644 index 00000000000..f782a490e0b --- /dev/null +++ b/tests/gamestonk_terminal/portfolio/brokers/degiro/test_degiro_model.py @@ -0,0 +1,342 @@ +# IMPORTATION STANDARD + +# IMPORTATION THIRDPARTY +import pandas as pd +import pytest +from degiro_connector.trading.models import trading_pb2 + +# IMPORTATION INTERNAL +from gamestonk_terminal.portfolio.brokers.degiro.degiro_model import DegiroModel + +# pylint: disable=E1101 +# pylint: disable=W0603 +# pylint: disable=E1111 + + +@pytest.fixture(scope="module") +def vcr_config(): + return { + "filter_headers": [ + ("User-Agent", None), + ("cookie", None), + ], + "filter_query_parameters": [ + ("intAccount", "MOCK_INT_ACCOUNT"), + ("sessionId", "MOCK_SESSION_ID"), + ], + "filter_post_data_parameters": [ + ("username", "MOCK_USERNAME"), + ("password", "MOCK_PASSWORD"), + ("oneTimePassword", "MOCK_ONE_TIME_PASSWORD"), + ], + } + + +@pytest.mark.vcr(record_mode="none") +@pytest.mark.parametrize( + "func, kwargs, mocked_func, mock_return", + [ + ( + "cancel", + dict(order_id="MOCK_ORDER_ID"), + "delete_order", + True, + ), + ( + "companynews", + dict(isin="MOCK_ISIN"), + "get_news_by_company", + trading_pb2.NewsByCompany(), + ), + ( + "create_check", + dict(order=trading_pb2.Order()), + "check_order", + trading_pb2.Order.CheckingResponse(), + ), + ( + "create_confirm", + dict(confirmation_id="MOCK_CONFIRMATION_ID", order=trading_pb2.Order()), + "confirm_order", + trading_pb2.Order.ConfirmationResponse(), + ), + ( + "lastnews", + dict(limit=1), + "get_latest_news", + trading_pb2.LatestNews(), + ), + ( + "logout", + dict(), + "logout", + True, + ), + ( + "lookup", + dict(limit=1, offset=2, search_text="MOCK_SEARCH_TXT"), + "product_search", + trading_pb2.ProductSearch(), + ), + ( + "topnews", + dict(), + "get_top_news_preview", + trading_pb2.TopNewsPreview(), + ), + ( + "update", + dict(order=trading_pb2.Order()), + "update_order", + trading_pb2.Update.Orders(), + ), + ], +) +def test_call_func(func, kwargs, mocked_func, mock_return, mocker): + model = DegiroModel() + + # MOCK MOCKED_FUNC + mock_func = mocker.Mock(return_value=mock_return) + mocker.patch.object( + target=model.__dict__["_DegiroModel__trading_api"], + attribute=mocked_func, + new=mock_func, + ) + + result = getattr(model, func)(**kwargs) + + mock_func.assert_called_once() + assert isinstance(result, type(mock_return)) + + +@pytest.mark.vcr(record_mode="none") +def test_pending(mocker): + model = DegiroModel() + + # MOCK API FUNCTION + mock_func = mocker.Mock(return_value=trading_pb2.Update()) + mocker.patch.object( + target=model.__dict__["_DegiroModel__trading_api"], + attribute="get_update", + new=mock_func, + ) + + result = model.pending() + + mock_func.assert_called_once() + assert isinstance(result, trading_pb2.Update.Orders) + + +@pytest.mark.vcr(record_mode="none") +def test_update_pending_order(mocker): + model = DegiroModel() + + # MOCK API FUNCTION + mock_update = trading_pb2.Update() + mock_update.orders.values.extend( + [ + trading_pb2.Order( + id="MOCK_ORDER_ID", + product_id=1, + size=2, + price=3, + ), + ] + ) + mock_func = mocker.Mock(return_value=mock_update) + mocker.patch.object( + target=model.__dict__["_DegiroModel__trading_api"], + attribute="get_update", + new=mock_func, + ) + + result = model.update_pending_order(order_id="MOCK_ORDER_ID") + + mock_func.assert_called_once() + assert isinstance(result, trading_pb2.Order) + + +@pytest.mark.vcr(record_mode="none") +def test_update_pending_order_no_order_id(mocker): + model = DegiroModel() + + # MOCK API FUNCTION + mock_update = trading_pb2.Update() + mock_update.orders.values.extend( + [ + trading_pb2.Order( + product_id=1, + size=2, + price=3, + ), + ] + ) + mock_func = mocker.Mock(return_value=mock_update) + mocker.patch.object( + target=model.__dict__["_DegiroModel__trading_api"], + attribute="get_update", + new=mock_func, + ) + + result = model.update_pending_order(order_id="MOCK_ORDER_ID") + + mock_func.assert_called_once() + assert result is None + + +@pytest.mark.vcr(record_mode="none") +def test_update_pending_order_none(mocker): + model = DegiroModel() + + # MOCK API FUNCTION + mock_update = trading_pb2.Update() + mock_func = mocker.Mock(return_value=mock_update) + mocker.patch.object( + target=model.__dict__["_DegiroModel__trading_api"], + attribute="get_update", + new=mock_func, + ) + + result = model.update_pending_order(order_id="MOCK_ORDER_ID") + + mock_func.assert_called_once() + assert result is None + + +@pytest.mark.vcr(record_mode="none") +def test_hold_positions_empty_update(mocker): + model = DegiroModel() + + # MOCK API FUNCTION + mock_update = trading_pb2.Update() + mock_func = mocker.Mock(return_value=mock_update) + mocker.patch.object( + target=model.__dict__["_DegiroModel__trading_api"], + attribute="get_update", + new=mock_func, + ) + + result = model.hold_positions() + + assert isinstance(result, pd.DataFrame) + + +@pytest.mark.vcr(record_mode="none") +def test_login_default_credentials(): + model = DegiroModel() + + credentials = model.login_default_credentials() + + assert isinstance(credentials, trading_pb2.Credentials) + + +@pytest.mark.vcr(record_mode="none") +def test_login(mocker): + model = DegiroModel() + + # MOCK CONNECT + mock_connect = mocker.Mock() + mocker.patch.object( + target=model.__dict__["_DegiroModel__trading_api"], + attribute="connect", + new=mock_connect, + ) + + # MOCK GET_CLIENT_DETAILS + mock_client_details_table = { + "data": { + "intAccount": 12345, + } + } + mock_get_client_details = mocker.Mock(return_value=mock_client_details_table) + mocker.patch.object( + target=model.__dict__["_DegiroModel__trading_api"], + attribute="get_client_details", + new=mock_get_client_details, + ) + + model.login(credentials=trading_pb2.Credentials()) + + mock_connect.assert_called_once() + mock_get_client_details.assert_called_once() + + +@pytest.mark.vcr(record_mode="none") +@pytest.mark.parametrize( + "kwargs, expected", + [ + ( + dict(price=10, size=None, up_to=22), + 2, + ), + ( + dict(price=10, size=2, up_to=None), + 2, + ), + ], +) +def test_create_calculate_size(expected, kwargs): + model = DegiroModel() + + result = model.create_calculate_size(**kwargs) + + assert result == expected + + +@pytest.mark.vcr(record_mode="none") +def test_create_calculate_product_id_product_id(): + model = DegiroModel() + + result = model.create_calculate_product_id(product=1, symbol=None) + + assert result == 1 + + +@pytest.mark.vcr(record_mode="none") +def test_create_calculate_product_id_product_symbol(mocker): + model = DegiroModel() + + result = model.create_calculate_product_id(product=1, symbol=None) + + assert result == 1 + + # MOCK CONNECT + product_search = trading_pb2.ProductSearch() + product = product_search.products.add() + product["id"] = 1 + product["symbol"] = "MOCK_SYMBOL" + mock_product_search = mocker.Mock(return_value=product_search) + mocker.patch.object( + target=model.__dict__["_DegiroModel__trading_api"], + attribute="product_search", + new=mock_product_search, + ) + + result = model.create_calculate_product_id(product=None, symbol="MOCK_SYMBOL") + + assert result == 1 + + +@pytest.mark.vcr(record_mode="none") +def test_create_calculate_product_id_product_symbol_no_result(mocker): + model = DegiroModel() + + result = model.create_calculate_product_id(product=1, symbol=None) + + assert result == 1 + + # MOCK CONNECT + product_search = trading_pb2.ProductSearch() + product = product_search.products.add() + product["id"] = 1 + product["symbol"] = "MOCK_WRONG_SYMBOL" + mock_product_search = mocker.Mock(return_value=product_search) + mocker.patch.object( + target=model.__dict__["_DegiroModel__trading_api"], + attribute="product_search", + new=mock_product_search, + ) + + result = model.create_calculate_product_id(product=None, symbol="MOCK_SYMBOL") + + assert result is None diff --git a/tests/gamestonk_terminal/portfolio/brokers/degiro/test_degiro_view.py b/tests/gamestonk_terminal/portfolio/brokers/degiro/test_degiro_view.py new file mode 100644 index 00000000000..0b5401b8844 --- /dev/null +++ b/tests/gamestonk_terminal/portfolio/brokers/degiro/test_degiro_view.py @@ -0,0 +1,37 @@ +# IMPORTATION STANDARD + +# IMPORTATION THIRDPARTY +import pytest + +# IMPORTATION INTERNAL +from gamestonk_terminal.portfolio.brokers.degiro.degiro_view import DegiroView + + +# pylint: disable=E1101 +# pylint: disable=W0603 +# pylint: disable=E1111 + + +@pytest.fixture(scope="module") +def vcr_config(): + return { + "filter_headers": [ + ("User-Agent", None), + ("cookie", None), + ], + "filter_query_parameters": [ + ("intAccount", "MOCK_INT_ACCOUNT"), + ("sessionId", "MOCK_SESSION_ID"), + ], + "filter_post_data_parameters": [ + ("username", "MOCK_USERNAME"), + ("password", "MOCK_PASSWORD"), + ("oneTimePassword", "MOCK_ONE_TIME_PASSWORD"), + ], + } + + +@pytest.mark.vcr(record_mode="none") +@pytest.mark.record_stdout +def test_help_display(): + DegiroView.help_display() diff --git a/tests/gamestonk_terminal/portfolio/brokers/degiro/txt/test_degiro_controller/test_print_help.txt b/tests/gamestonk_terminal/portfolio/brokers/degiro/txt/test_degiro_controller/test_print_help.txt new file mode 100644 index 00000000000..717f6171854 --- /dev/null +++ b/tests/gamestonk_terminal/portfolio/brokers/degiro/txt/test_degiro_controller/test_print_help.txt @@ -0,0 +1,17 @@ + +Degiro: + login connect to degiro's api + logout disconnect from degiro's api + + hold view holdings + lookup view search for a product by name + + create create an order + update update an order + cancel cancel an order using the id + pending view pending orders + + companynews view news about a company with it's isin + lastnews view latest news + topnews view top news preview + diff --git a/tests/gamestonk_terminal/portfolio/brokers/degiro/txt/test_degiro_view/test_help_display.txt b/tests/gamestonk_terminal/portfolio/brokers/degiro/txt/test_degiro_view/test_help_display.txt new file mode 100644 index 00000000000..717f6171854 --- /dev/null +++ b/tests/gamestonk_terminal/portfolio/brokers/degiro/txt/test_degiro_view/test_help_display.txt @@ -0,0 +1,17 @@ + +Degiro: + login connect to degiro's api + logout disconnect from degiro's api + + hold view holdings + lookup view search for a product by name + + create create an order + update update an order + cancel cancel an order using the id + pending view pending orders + + companynews view news about a company with it's isin + lastnews view latest news + topnews view top news preview +