diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0777576..430494b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,22 +1,20 @@ repos: - repo: https://github.com/psf/black - rev: 23.1.0 + rev: 24.3.0 hooks: - id: black - language_version: python3.10 - repo: https://github.com/pre-commit/mirrors-isort rev: v5.10.1 hooks: - id: isort - repo: https://github.com/pycqa/flake8 - rev: 6.0.0 + rev: 7.0.0 hooks: - id: flake8 additional_dependencies: [flake8-docstrings] files: ^qtrade/ - language_version: python3.10 - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.6.0 hooks: - id: trailing-whitespace - id: debug-statements diff --git a/qtrade/_version.py b/qtrade/_version.py index 15b9737..25f7e21 100644 --- a/qtrade/_version.py +++ b/qtrade/_version.py @@ -1,3 +1,3 @@ """Qtrade version.""" -__version__ = "0.5.0" +__version__ = "0.6.0" diff --git a/qtrade/questrade.py b/qtrade/questrade.py index 1a0198a..218bff1 100644 --- a/qtrade/questrade.py +++ b/qtrade/questrade.py @@ -377,6 +377,73 @@ def get_account_activities(self, account_id: int, start_date: str, end_date: str return activities + def get_account_executions(self, account_id: int, start_date: str, end_date: str) -> List[Dict]: + """Get account executions. + + This method will get the account executionss for a given account ID in a given time + interval. + + This method will in general return a list of dictionaries, where each dictionary represents + one account execution. Each dictionary is of the form + + .. code-block:: python + + + {"symbol": "AAPL", + "symbolId": 8049, + "quantity": 10, + "side": "Buy", + "price": 536.87, + "id": 53817310, + "orderId": 177106005, + "orderChainId": 17710600, + "exchangeExecId": "XS1771060050147", + "timestam": 2014-03-31T13:38:29.000000-04:00, + "notes": "", + "venue": "LAMP", + "totalCost": 5368.7, + "orderPlacementCommission": 0, + "commission": 4.95, + "executionFee": 0, + "secFee": 0, + "canadianExecutionFee": 0, + "parentId": 0, + } + + Parameters + ---------- + account_id: int + Accound ID for which the executionss will be returned. + startDate: str + Start date of time period, format YYYY-MM-DD + endDate: str + End date of time period, format YYYY-MM-DD + + Returns + ------- + list: + List of dictionaries, where each list entry is a dictionary with execution + information. + + """ + payload = { + "startTime": str(start_date) + "T00:00:00-05:00", + "endTime": str(end_date) + "T00:00:00-05:00", + } + + log.info("Getting account executions...") + response = self._send_message( + "get", "accounts/" + str(account_id) + "/executions", params=payload + ) + + try: + executions = response["executions"] + except Exception: + print(response) + raise Exception + + return executions + def ticker_information(self, tickers: Union[str, List[str]]) -> Union[Dict, List[Dict]]: """Get ticker information. diff --git a/tests/test_questrade.py b/tests/test_questrade.py index 35061c2..4745d1c 100644 --- a/tests/test_questrade.py +++ b/tests/test_questrade.py @@ -1,5 +1,6 @@ """Questrade test module """ + from unittest import mock import pytest @@ -160,6 +161,33 @@ } ] } + +EXECUTION_RESPONSE = { + "executions": [ + { + "symbol": "AAPL", + "symbolId": 8049, + "quantity": 10, + "side": "Buy", + "price": 536.87, + "id": 53817310, + "orderId": 177106005, + "orderChainId": 17710600, + "exchangeExecId": "XS1771060050147", + "timestam": "2014-03-31T13:38:29.000000-04:00", + "notes": "", + "venue": "LAMP", + "totalCost": 5368.7, + "orderPlacementCommission": 0, + "commission": 4.95, + "executionFee": 0, + "secFee": 0, + "canadianExecutionFee": 0, + "parentId": 0, + } + ] +} + TICKER_INFO = { "averageVol20Days": 2, "averageVol3Months": 4, @@ -358,6 +386,17 @@ def mocked_activities_get(*args, **kwargs): return MockResponse(None, 404) +def mocked_executions_get(*args, **kwargs): + """mocking executions requests get""" + if args[1] == "http://www.api_url.com/v1/accounts/123/executions" and kwargs["params"] == { + "endTime": "2018-08-10T00:00:00-05:00", + "startTime": "2018-08-07T00:00:00-05:00", + }: + return MockResponse(EXECUTION_RESPONSE, 200) + else: + return MockResponse(None, 404) + + def mocked_ticker_get(*args, **kwargs): """mocking ticker info requests get""" if args[1] == "http://www.api_url.com/v1/symbols" and kwargs["params"] == {"names": "XYZ"}: @@ -544,6 +583,21 @@ def test_get_activity(mock_get): _ = qtrade.get_account_activities(987, "2018-08-07", "2018-08-10") +@mock.patch("builtins.open", mock.mock_open(read_data=ACCESS_TOKEN_YAML)) +@mock.patch.object(Session, "request", side_effect=mocked_executions_get) +def test_get_execution(mock_get): + """This function tests the get account executions method.""" + qtrade = Questrade(token_yaml="access_token.yml") + executions = qtrade.get_account_executions(123, "2018-08-07", "2018-08-10") + assert executions[0]["quantity"] == 10 + assert executions[0]["side"] == "Buy" + assert len(executions) == 1 + assert len(executions[0]) == 19 + + with pytest.raises(Exception): + _ = qtrade.get_account_executions(987, "2018-08-07", "2018-08-10") + + @mock.patch("builtins.open", mock.mock_open(read_data=ACCESS_TOKEN_YAML)) @mock.patch.object(Session, "request", side_effect=mocked_ticker_get) def test_get_ticker_information(mock_get):