Repository: jborchma/qtrade

Issue:
retrieve account executions
thanks to all contributors for qtrade, which works well for me. 

The ability to get the latest execution would be a great addition (unless already available and i am not aware of).
In particular, that info is required to compute intra-day PnL. 

https://www.questrade.com/api/documentation/rest-operations/account-calls/accounts-id-executions

Best

Discussion:
@jborchma: Thank you so much for the suggestion! I added the method in the new version. Please let me know if I overlooked any bugs!@John9909: that was very fast response, will be trying very shortly, thanks very much!@John9909: hi there, this week i tried get_account_executions( ) and it all worked well. Thanks again.

Btw i noticed that for get_account_activities( ):
 if the initial date is more than 30 days before today, I receive en error (as opposed to returning 30 days' worth of data, as get_account_executions( )  does). 

Best

Solution patch:
diff --git a/.github/workflows/qtrade-actions.yml b/.github/workflows/qtrade-actions.yml
index c27bd0d..8234e11 100644
--- a/.github/workflows/qtrade-actions.yml
+++ b/.github/workflows/qtrade-actions.yml
@@ -8,7 +8,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        python-version: ["3.8", "3.9", "3.10", "3.11"]
+        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
 
     steps:
       - uses: actions/checkout@v3
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 @@ class Questrade:
 
         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.
 


Test patch:
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 @@ ACTIVITY_RESPONSE = {
         }
     ]
 }
+
+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):