Skip to content

Commit

Permalink
Merge pull request #11 from 8ball030/feat/additional_endpoints
Browse files Browse the repository at this point in the history
[feat] added in additional endpoints
  • Loading branch information
8ball030 authored Dec 25, 2023
2 parents 8ecc7ca + f2d44f6 commit 622538c
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 6 deletions.
83 changes: 82 additions & 1 deletion lyra/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from dotenv import load_dotenv
from rich import print

from lyra.enums import Environment, InstrumentType
from lyra.enums import Environment, InstrumentType, OrderStatus
from lyra.lyra import LyraClient
from lyra.utils import get_logger

Expand Down Expand Up @@ -75,6 +75,11 @@ def subaccounts():
"""Interact with subaccounts."""


@cli.group("orders")
def orders():
"""Interact with orders."""


@instruments.command("fetch")
@click.pass_context
@click.option(
Expand Down Expand Up @@ -127,5 +132,81 @@ def fetch_subaccount(ctx, subaccount_id):
print(subaccount)


@orders.command("fetch")
@click.pass_context
@click.option(
"--instrument-name",
"-i",
type=str,
default=None,
)
@click.option(
"--label",
"-l",
type=str,
default=None,
)
@click.option(
"--page",
"-p",
type=int,
default=1,
)
@click.option(
"--page-size",
"-s",
type=int,
default=100,
)
@click.option(
"--status",
"-s",
type=click.Choice([f.value for f in OrderStatus]),
default=None,
)
def fetch_orders(ctx, instrument_name, label, page, page_size, status):
"""Fetch orders."""
print("Fetching orders")
client = ctx.obj["client"]
orders = client.fetch_orders(
instrument_name=instrument_name,
label=label,
page=page,
page_size=page_size,
status=status,
)
print(orders)


@orders.command("cancel")
@click.pass_context
@click.option(
"--order-id",
"-o",
type=str,
)
@click.option(
"--instrument-name",
"-i",
type=str,
)
def cancel_order(ctx, order_id, instrument_name):
"""Cancel order."""
print("Cancelling order")
client = ctx.obj["client"]
result = client.cancel(order_id=order_id, instrument_name=instrument_name)
print(result)


@orders.command("cancel_all")
@click.pass_context
def cancel_all_orders(ctx):
"""Cancel all orders."""
print("Cancelling all orders")
client = ctx.obj["client"]
result = client.cancel_all()
print(result)


if __name__ == "__main__":
cli() # pylint: disable=no-value-for-parameter
10 changes: 10 additions & 0 deletions lyra/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ class OrderType(Enum):
MARKET = "market"


class OrderStatus(Enum):
"""Order statuses."""

OPEN = "open"
FILLED = "filled"
REJECTED = "rejected"
CANCELLED = "cancelled"
EXPIRED = "expired"


class TimeInForce(Enum):
"""Time in force."""

Expand Down
72 changes: 67 additions & 5 deletions lyra/lyra.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from web3 import Web3
from websocket import create_connection

from lyra.enums import InstrumentType, OrderSide, OrderType, TimeInForce, UnderlyingCurrency
from lyra.enums import InstrumentType, OrderSide, OrderStatus, OrderType, TimeInForce, UnderlyingCurrency
from lyra.utils import get_logger

BASE_URL = "https://api-demo.lyra.finance"
Expand Down Expand Up @@ -54,7 +54,7 @@ def _create_signature_headers(self):
"X-LyraSignature": Web3.to_hex(signature.signature),
}

def __init__(self, private_key, env, logger=None, verbose=False):
def __init__(self, private_key, env, logger=None, verbose=False, subaccount_id=None):
"""
Initialize the LyraClient class.
"""
Expand All @@ -63,6 +63,8 @@ def __init__(self, private_key, env, logger=None, verbose=False):
self.logger = logger or get_logger()
self.web3_client = Web3()
self.wallet = self.web3_client.eth.account.from_key(private_key)
if not subaccount_id:
self.subaccount_id = self.fetch_subaccounts(self.wallet.address)['subaccount_ids'][0]

def create_account(self, wallet):
"""Call the create account endpoint."""
Expand Down Expand Up @@ -156,8 +158,7 @@ def submit_order(self, order, ws):
while True:
message = json.loads(ws.recv())
if message['id'] == id:
print('Got order response:', message)
return message
return message['result']['order']

def sign_authentication_header(self):
timestamp = str(int(time.time() * 1000))
Expand All @@ -182,7 +183,7 @@ def login_client(self, ws):
{'method': 'public/login', 'params': self.sign_authentication_header(), 'id': str(int(time.time()))}
)
ws.send(login_request)
time.sleep(2)
time.sleep(1)

def create_subaccount(
amount,
Expand Down Expand Up @@ -282,3 +283,64 @@ def fetch_ticker(self, instrument_name):
response = requests.post(url, json=payload, headers=headers)
results = json.loads(response.content)["result"]
return results

def fetch_orders(
self,
instrument_name: str = None,
label: str = None,
page: int = 1,
page_size: int = 100,
status: OrderStatus = None,
):
"""
Fetch the orders for a given instrument name.
"""
url = f"{BASE_URL}/private/get_orders"
payload = {"instrument_name": instrument_name, "subaccount_id": self.subaccount_id}
for key, value in {"label": label, "page": page, "page_size": page_size, "status": status}.items():
if value:
payload[key] = value
headers = self._create_signature_headers()
response = requests.post(url, json=payload, headers=headers)
results = response.json()["result"]['orders']
return results

def cancel(self, order_id, instrument_name):
"""
Cancel an order
"""

ws = self.connect_ws()
self.login_client(ws)
id = str(int(time.time()))
payload = {"order_id": order_id, "subaccount_id": self.subaccount_id, "instrument_name": instrument_name}
ws.send(json.dumps({'method': 'private/cancel', 'params': payload, 'id': id}))
while True:
message = json.loads(ws.recv())
if message['id'] == id:
return message['result']

def cancel_all(self):
"""
Cancel all orders
"""
ws = self.connect_ws()
self.login_client(ws)
id = str(int(time.time()))
payload = {"subaccount_id": self.subaccount_id}
ws.send(json.dumps({'method': 'private/cancel_all', 'params': payload, 'id': id}))
while True:
message = json.loads(ws.recv())
if message['id'] == id:
return message['result']

def get_positions(self):
"""
Get positions
"""
url = f"{BASE_URL}/private/get_positions"
payload = {"subaccount_id": self.subaccount_id}
headers = self._create_signature_headers()
response = requests.post(url, json=payload, headers=headers)
results = response.json()["result"]['positions']
return results
46 changes: 46 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,49 @@ def test_fetch_subaccount(lyra_client):
subaccount_id = lyra_client.fetch_subaccounts()['subaccount_ids'][0]
subaccount = lyra_client.fetch_subaccount(subaccount_id)
assert subaccount['subaccount_id'] == subaccount_id


def test_fetch_orders(lyra_client):
"""
Test the LyraClient class.
"""
orders = lyra_client.fetch_orders()
assert orders


def test_cancel_order(lyra_client):
"""
Test the LyraClient class.
"""
order = lyra_client.create_order(
price=200,
amount=1,
instrument_name="ETH-PERP",
side=OrderSide.BUY,
order_type=OrderType.LIMIT,
)
order_id = order['order_id']
result = lyra_client.cancel(instrument_name="ETH-PERP", order_id=order_id)
assert result['order_id'] == order_id


def test_cancel_all_orders(lyra_client):
"""Test all open orders are cancelled."""
lyra_client.create_order(
price=200,
amount=1,
instrument_name="ETH-PERP",
side=OrderSide.BUY,
order_type=OrderType.LIMIT,
)
open_orders = lyra_client.fetch_orders(status="open")
assert open_orders
lyra_client.cancel_all()
open_orders = lyra_client.fetch_orders(status="open")
assert not open_orders


def test_get_positions(lyra_client):
"""Test get positions."""
positions = lyra_client.get_positions()
assert isinstance(positions, list)

0 comments on commit 622538c

Please sign in to comment.