Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
)
```

Expand Down
2 changes: 2 additions & 0 deletions enclave/_perps.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""
import json
from decimal import Decimal
from dataclasses import dataclass
from typing import Optional, Union, List

from . import _baseclient, models
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion enclave/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 3 additions & 3 deletions enclave/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
163 changes: 17 additions & 146 deletions examples/intro.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down Expand Up @@ -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=}")

Expand All @@ -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=}")

Expand All @@ -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

Expand All @@ -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!)")

# %%
2 changes: 1 addition & 1 deletion examples/wsintro.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}"),
Expand Down