From 159761d97f6b842bd5505c19c127eae86b44ffa2 Mon Sep 17 00:00:00 2001 From: urischwartz-cb <143205923+urischwartz-cb@users.noreply.github.com> Date: Thu, 1 Feb 2024 14:30:55 -0500 Subject: [PATCH] Release v1.1.1 (#23) --- CHANGELOG.md | 5 ++ coinbase/__version__.py | 2 +- coinbase/rest/__init__.py | 6 +++ coinbase/rest/perpetuals.py | 56 ++++++++++++++++++++ tests/rest/test_perpetuals.py | 98 +++++++++++++++++++++++++++++++++++ 5 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 coinbase/rest/perpetuals.py create mode 100644 tests/rest/test_perpetuals.py diff --git a/CHANGELOG.md b/CHANGELOG.md index b5dfaf8..a0d918f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## [1.1.1] - 2024-FEB-1 + +### Added +- Support for Perpetuals API endpoints + ## [1.1.0] - 2024-JAN-31 ### Added diff --git a/coinbase/__version__.py b/coinbase/__version__.py index 6849410..a82b376 100644 --- a/coinbase/__version__.py +++ b/coinbase/__version__.py @@ -1 +1 @@ -__version__ = "1.1.0" +__version__ = "1.1.1" diff --git a/coinbase/rest/__init__.py b/coinbase/rest/__init__.py index 842ad9e..37b5fe7 100755 --- a/coinbase/rest/__init__.py +++ b/coinbase/rest/__init__.py @@ -39,6 +39,12 @@ class RESTClient(RESTBase): stop_limit_order_gtd_buy, stop_limit_order_gtd_sell, ) + from .perpetuals import ( + allocate_portfolio, + get_perps_portfolio_summary, + get_perps_position, + list_perps_positions, + ) from .portfolios import ( create_portfolio, delete_portfolio, diff --git a/coinbase/rest/perpetuals.py b/coinbase/rest/perpetuals.py new file mode 100644 index 0000000..8de5b03 --- /dev/null +++ b/coinbase/rest/perpetuals.py @@ -0,0 +1,56 @@ +from typing import Optional + +from coinbase.constants import API_PREFIX + + +def allocate_portfolio( + self, portfolio_uuid: str, symbol: str, amount: str, currency: str, **kwargs +): + """ + Allocate more funds to an isolated position in your Perpetuals portfolio. + + https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_allocateportfolio + """ + endpoint = f"{API_PREFIX}/intx/allocate" + + data = { + "portfolio_uuid": portfolio_uuid, + "symbol": symbol, + "amount": amount, + "currency": currency, + } + + return self.post(endpoint, data=data, **kwargs) + + +def get_perps_portfolio_summary(self, portfolio_uuid: str, **kwargs): + """ + Get a summary of your Perpetuals portfolio. + + https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getintxportfoliosummary + """ + endpoint = f"{API_PREFIX}/intx/portfolio/{portfolio_uuid}" + + return self.get(endpoint, **kwargs) + + +def list_perps_positions(self, portfolio_uuid: str, **kwargs): + """ + Get a list of open positions in your Perpetuals portfolio. + + https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getintxpositions + """ + endpoint = f"{API_PREFIX}/intx/positions/{portfolio_uuid}" + + return self.get(endpoint, **kwargs) + + +def get_perps_position(self, portfolio_uuid: str, symbol: str, **kwargs): + """ + Get a specific open position in your Perpetuals portfolio + + https://docs.cloud.coinbase.com/advanced-trade-api/reference/retailbrokerageapi_getintxposition + """ + endpoint = f"{API_PREFIX}/intx/positions/{portfolio_uuid}/{symbol}" + + return self.get(endpoint, **kwargs) diff --git a/tests/rest/test_perpetuals.py b/tests/rest/test_perpetuals.py new file mode 100644 index 0000000..5da35a9 --- /dev/null +++ b/tests/rest/test_perpetuals.py @@ -0,0 +1,98 @@ +import unittest + +from requests_mock import Mocker + +from coinbase.rest import RESTClient + +from ..constants import TEST_API_KEY, TEST_API_SECRET + + +class PerpetualsTest(unittest.TestCase): + def test_allocate_portfolio(self): + client = RESTClient(TEST_API_KEY, TEST_API_SECRET) + + expected_response = {"key_1": "value_1", "key_2": "value_2"} + + with Mocker() as m: + m.request( + "POST", + "https://api.coinbase.com/api/v3/brokerage/intx/allocate", + json=expected_response, + ) + response = client.allocate_portfolio( + portfolio_uuid="test_uuid", + symbol="BTC-PERP-INTX", + amount="100", + currency="USD", + ) + + captured_request = m.request_history[0] + captured_json = captured_request.json() + + self.assertEqual(captured_request.query, "") + self.assertEqual( + captured_json, + { + "portfolio_uuid": "test_uuid", + "symbol": "BTC-PERP-INTX", + "amount": "100", + "currency": "USD", + }, + ) + self.assertEqual(response, expected_response) + + def test_get_perps_portfolio_summary(self): + client = RESTClient(TEST_API_KEY, TEST_API_SECRET) + + expected_response = {"key_1": "value_1", "key_2": "value_2"} + + with Mocker() as m: + m.request( + "GET", + "https://api.coinbase.com/api/v3/brokerage/intx/portfolio/test_uuid", + json=expected_response, + ) + portfolios = client.get_perps_portfolio_summary(portfolio_uuid="test_uuid") + + captured_request = m.request_history[0] + + self.assertEqual(captured_request.query, "") + self.assertEqual(portfolios, expected_response) + + def test_list_perps_positions(self): + client = RESTClient(TEST_API_KEY, TEST_API_SECRET) + + expected_response = {"key_1": "value_1", "key_2": "value_2"} + + with Mocker() as m: + m.request( + "GET", + "https://api.coinbase.com/api/v3/brokerage/intx/positions/test_uuid", + json=expected_response, + ) + portfolios = client.list_perps_positions(portfolio_uuid="test_uuid") + + captured_request = m.request_history[0] + + self.assertEqual(captured_request.query, "") + self.assertEqual(portfolios, expected_response) + + def test_get_perps_position(self): + client = RESTClient(TEST_API_KEY, TEST_API_SECRET) + + expected_response = {"key_1": "value_1", "key_2": "value_2"} + + with Mocker() as m: + m.request( + "GET", + "https://api.coinbase.com/api/v3/brokerage/intx/positions/test_uuid/BTC-PERP-INTX", + json=expected_response, + ) + portfolios = client.get_perps_position( + portfolio_uuid="test_uuid", symbol="BTC-PERP-INTX" + ) + + captured_request = m.request_history[0] + + self.assertEqual(captured_request.query, "") + self.assertEqual(portfolios, expected_response)