diff --git a/README.md b/README.md index 7302313..976a3d0 100644 --- a/README.md +++ b/README.md @@ -40,11 +40,13 @@ print(client.wait_until_ready()) # should print True ```python buy_order = client.perps.add_order( - "BTC-USD.P", - enclave.models.BUY, - Decimal(42_000), - Decimal(0.1), - order_type=enclave.models.LIMIT, + client.perps.OrderParams( + market="BTC-USD.P", + side=enclave.models.BUY, + price=Decimal(42_000), + size=Decimal(0.1), + order_type=enclave.models.LIMIT + ) ) ``` diff --git a/enclave/_perps.py b/enclave/_perps.py index 389b19c..e7ff52d 100644 --- a/enclave/_perps.py +++ b/enclave/_perps.py @@ -3,6 +3,7 @@ """ import json from decimal import Decimal +from dataclasses import dataclass from typing import Optional, Union, List from . import _baseclient, models @@ -423,6 +424,7 @@ def cancel_order(self, *, client_order_id: Optional[str] = None, order_id: Optio return self.bc.delete(f"/v1/perps/orders/{path}") + @dataclass class OrderParams: market: str side: str diff --git a/enclave/client.py b/enclave/client.py index 327ea12..89101f9 100644 --- a/enclave/client.py +++ b/enclave/client.py @@ -32,7 +32,7 @@ class Client: or from a file using `from_api_file` with the key id on the first line and the secret on the second line. """ - def __init__(self, api_key: str, api_secret: str, base_url: str = models.PROD): + def __init__(self, api_key: str, api_secret: str, base_url: str = models.PROD_PERMISSIONLESS): self.bc = _baseclient.BaseClient(api_key, api_secret, base_url) self.cross = _cross.Cross(self.bc) diff --git a/enclave/models.py b/enclave/models.py index 22f9e6b..3205b67 100644 --- a/enclave/models.py +++ b/enclave/models.py @@ -10,12 +10,12 @@ PUT: Final[str] = "PUT" VERBS: Final[Set[str]] = {GET, POST, DELETE, PUT} -DEV: Final[str] = "https://api-dev.enclavemarket.dev" +DEV: Final[str] = "https://api-dev-permissionless.enclavemarket.dev" DEV_PERMISSIONLESS: Final[str] = "https://api-dev-permissionless.enclavemarket.dev" STAGING: Final[str] = "https://api-staging.enclavemarket.dev" -SANDBOX: Final[str] = "https://api-sandbox.enclave.market" +SANDBOX: Final[str] = "https://api-sandbox.enclave.trade" SANDBOX_PERMISSIONLESS: Final[str] = "https://api-sandbox.enclave.trade" -PROD: Final[str] = "https://api.enclave.market" +PROD: Final[str] = "https://api.enclave.trade" PROD_PERMISSIONLESS: Final[str] = "https://api.enclave.trade" BUY: Final[str] = "buy" diff --git a/examples/intro.py b/examples/intro.py index 991d363..ee78295 100644 --- a/examples/intro.py +++ b/examples/intro.py @@ -9,89 +9,14 @@ from enclave.client import Client -def spot(client: Client) -> None: - """Demonstrate some spot trading functionality.""" - - # get the balance of AVAX - balance = Decimal(client.get_balance("AVAX").json()["result"]["freeBalance"]) - print(f"Free AVAX balance: {balance=}") - - # get the AVAX-USDC trading pair to find the min order sizes - spot_trading_pairs = client.get_markets().json()["result"]["spot"]["tradingPairs"] - avax_trading_pair = [pairs for pairs in spot_trading_pairs if pairs["market"] == "AVAX-USDC"][0] - print(f"{avax_trading_pair=}") - avax_base_min, avax_quote_min = Decimal(avax_trading_pair["baseIncrement"]), Decimal( - avax_trading_pair["quoteIncrement"] - ) - print(f"{avax_base_min=} {avax_quote_min=}") - - # get top of book for avax usdc - avax_top_of_book = client.spot.get_depth("AVAX-USDC", depth=1).json()["result"] - print(f"{avax_top_of_book=}") - avax_ask_price, avax_ask_size = (Decimal(x) for x in avax_top_of_book["asks"][0]) - print(f"{avax_ask_price=}, {avax_ask_size=}") - - # place a sell limit order of the smallest size one tick above the top of book (so we don't get filled) - assert balance >= avax_base_min - custom_id = f"demo{int(time.time_ns())}" - sell_order = client.spot.add_order( - "AVAX-USDC", - enclave.models.SELL, - avax_ask_price + avax_quote_min, - avax_base_min, - order_type=enclave.models.LIMIT, - client_order_id=custom_id, - ).json()["result"] - print(f"{sell_order=}") - - # cancel all orders in the market - cancel_res = client.spot.cancel_orders("AVAX-USDC").json() - print(f"{cancel_res=}") - - # get the order status - order_status = client.spot.get_order(client_order_id=custom_id).json()["result"] - print(f"{order_status=}") - filled_size = Decimal(order_status["filledSize"]) - print(f"{filled_size=}") - - # cause a trade and query fills - custom_id = f"demo{int(time.time_ns())}" - sell_order = client.spot.add_order( - "AVAX-USDC", - enclave.models.SELL, - None, - avax_base_min, - order_type=enclave.models.MARKET, - client_order_id=custom_id, - ).json()["result"] - - print(f"{sell_order=}") - - fills_by_custom_id = client.spot.get_fills_by_id(client_order_id=custom_id).json()["result"] - print(f"found {len(fills_by_custom_id)} fills by custom id") - - fills_by_order_id = client.spot.get_fills_by_id(order_id=sell_order["orderId"]).json()["result"] - print(f"found {len(fills_by_order_id)} fills by order id") - - all_fills = client.spot.get_fills().json()["result"] - print(f"found {len(all_fills)} fills for all orders") - - def perps(client: Client) -> None: """Demonstrate some perps trading functionality.""" - # get USDC balance - usdc_balance = Decimal(client.get_balance("USDC").json()["result"]["freeBalance"]) - print(f"Free USDC balance: {usdc_balance=}") - - # transfer USDC from the main account to perps - assert usdc_balance >= Decimal(1) - margin_deposit = client.perps.transfer("USDC", Decimal(1)).json() - print(f"{margin_deposit=}") margin_balance = client.perps.get_balance().json() print(f"{margin_balance=}") available_margin = Decimal(margin_balance["result"]["availableMargin"]) print(f"{available_margin=}") + assert available_margin >= Decimal(1) # other than margin, leverage etc, perps is the same API as spot perps_trading_pairs = client.get_markets().json()["result"]["perps"]["tradingPairs"] @@ -121,12 +46,14 @@ def perps(client: Client) -> None: custom_id = f"demo{int(time.time_ns())}" buy_order = client.perps.add_order( - "BTC-USD.P", - enclave.models.BUY, - buy_price, - buy_size, - order_type=enclave.models.LIMIT, - client_order_id=custom_id, + client.perps.OrderParams( + market="BTC-USD.P", + side=enclave.models.BUY, + price=buy_price, + size=buy_size, + order_type=enclave.models.LIMIT, + client_order_id=custom_id + ) ).json() print(f"{buy_order=}") @@ -143,12 +70,14 @@ def perps(client: Client) -> None: # cause a trade and query fills custom_id = f"demo{int(time.time_ns())}" buy_order = client.perps.add_order( - "BTC-USD.P", - enclave.models.BUY, - None, - buy_size, - order_type=enclave.models.MARKET, - client_order_id=custom_id, + client.perps.OrderParams( + market="BTC-USD.P", + side=enclave.models.BUY, + price=None, + size=buy_size, + order_type=enclave.models.MARKET, + client_order_id=custom_id + ) ).json()["result"] print(f"{buy_order=}") @@ -170,56 +99,6 @@ def perps(client: Client) -> None: print(f"{margin_balance=}") -def cross(client: Client) -> None: - """Demonstrate some cross trading functionality.""" - - # get the balance of AVAX - balance = Decimal(client.get_balance("USDC").json()["result"]["freeBalance"]) - print(f"Free USDC balance: {balance=}") - - # get the AVAX-USDC trading pair to find the min order sizes for cross - cross_configs = client.get_markets().json()["result"]["tokenConfig"] - usdc_trading_pair = [token for token in cross_configs if token["id"] == "USDC"][0] - print(f"{usdc_trading_pair=}") - # doing a buy order so we need the sizes for the quote currency, USDC - min_usdc, max_usdc = Decimal(usdc_trading_pair["minOrderSize"]), Decimal(usdc_trading_pair["maxOrderSize"]) - print(f"{min_usdc=} {max_usdc=}") - - # get the oracle price for AVAX-USDC - avax_usdc_price = Decimal(client.cross.get_price("AVAX-USDC").json()["result"]["price"]) - print(f"{avax_usdc_price=}") - - # buy AVAX for USDC at no more than the current price + $1 - assert min_usdc <= balance <= max_usdc - custom_id = f"demo{int(time.time_ns())}" - buy_order = client.cross.add_order( - "AVAX-USDC", - enclave.models.BUY, - min_usdc, - cancel_above=avax_usdc_price + Decimal(1), - customer_order_id=custom_id, - ).json() - print(f"{buy_order=}") - - # cancel order - cancel_res = client.cross.cancel_order(customer_order_id=custom_id).json() - print(f"{cancel_res=}") - - # get the order details - order_status = client.cross.get_order(customer_order_id=custom_id).json()["result"] - print(f"{order_status=}") - print(f"amount filled: {order_status['filledSize']=}, status: {order_status['status']=}") - - fills_by_custom_id = client.cross.get_fills_by_id(customer_order_id=custom_id).json()["result"] - print(f"found {len(fills_by_custom_id)} fills by custom id") - - fills_by_order_id = client.cross.get_fills_by_id(internal_order_id=buy_order["result"]["internalOrderId"]).json()["result"] - print(f"found {len(fills_by_order_id)} fills by order id") - - all_fills = client.cross.get_fills().json()["result"] - print(f"found {len(all_fills)} fills for all orders") - - if __name__ == "__main__": # For more auth options, see auth.py @@ -234,18 +113,10 @@ def cross(client: Client) -> None: authed_hello = enclave_client.authed_hello().json() print(f"{authed_hello=}") - # run the spot example - print(f"\nRunning spot example...\n{'*' * 80}") - spot(enclave_client) - # run the perps example print(f"\nRunning perps example...\n{'*' * 80}") perps(enclave_client) - # run the cross example - print(f"\nRunning cross example...\n{'*' * 80}") - cross(enclave_client) - print("\nHave a nice day! (Thank you!)") # %% diff --git a/examples/wsintro.py b/examples/wsintro.py index 6c6e7f2..ffbf26f 100644 --- a/examples/wsintro.py +++ b/examples/wsintro.py @@ -44,7 +44,7 @@ async def main() -> None: ws = WebSocketClient( API_KEY, API_SECRET, - "wss://api-sandbox.enclave.market/ws", + "wss://api-sandbox.enclave.trade/ws", on_connect=lambda: print("On Connect"), on_auth=lambda: print("On Auth"), on_error=lambda x: print(f"On Error: {x}"),