Skip to content

Commit

Permalink
Fix order placing
Browse files Browse the repository at this point in the history
  • Loading branch information
regynald committed Jul 13, 2024
1 parent 67064e9 commit e0638dc
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 29 deletions.
16 changes: 9 additions & 7 deletions hook_odyssey/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ async def subscribe_orderbook(
yield OrderbookEvent(**event["orderbook"])

async def subscribe_subaccount_orders(
self, subaccount: str
self, subaccount: int
) -> AsyncGenerator[SubaccountOrderEvent, None]:
if not self._api_key:
raise APIKeyError("No API key provided")
Expand All @@ -136,7 +136,7 @@ async def subscribe_subaccount_orders(
}
}
"""
variables = {"subaccount": subaccount}
variables = {"subaccount": str(subaccount)}
async for event in self._graphql_client.subscribe(query, variables):
yield SubaccountOrderEvent(**event["subaccountOrders"])

Expand Down Expand Up @@ -241,7 +241,7 @@ async def account_details(self) -> AccountDetails:
return AccountDetails(**result["accountDetails"])

# Place Order
async def place_order(self, order: PlaceOrderInput):
async def place_order(self, order: PlaceOrderInput) -> bool:
if not self._api_key:
raise APIKeyError("No API key provided")
if not self._private_key or not self._signer:
Expand All @@ -264,11 +264,12 @@ async def place_order(self, order: PlaceOrderInput):
)
}
"""
variables = {"orderInput": order, "signature": signature}
variables = {"orderInput": order.to_dict(), "signature": signature.to_dict()}
try:
await self._graphql_client.execute(mutation, variables)
result = await self._graphql_client.execute(mutation, variables)
except Exception:
raise OdysseyAPIError
return result.get("placeOrderV2", False)

# Cancel Order
async def cancel_order(self, order_hash: str) -> bool:
Expand All @@ -289,7 +290,7 @@ async def cancel_order(self, order_hash: str) -> bool:
# Transfer History
async def transfer_history(
self,
subaccount: str,
subaccount: int,
market_hash: Optional[str] = None,
trasfer_type: Optional[TransferType] = None,
cursor: Optional[str] = None,
Expand Down Expand Up @@ -329,7 +330,7 @@ async def transfer_history(
}
"""
variables = {
"subaccount": subaccount,
"subaccount": str(subaccount),
"marketHash": market_hash,
"transferType": trasfer_type.value if trasfer_type else None,
"cursor": cursor,
Expand All @@ -339,3 +340,4 @@ async def transfer_history(
except Exception:
raise OdysseyAPIError
return TransferHistory(**result["transferHistory"])
return TransferHistory(**result["transferHistory"])
8 changes: 4 additions & 4 deletions hook_odyssey/signing.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ def sign_order(self, order: PlaceOrderInput) -> Tuple[str, str]:
"instrumentType": 2, # Change if not Perpetual
"instrumentId": order.instrumentHash,
"direction": 0 if order.direction == OrderDirection.BUY else 1,
"maker": order.subaccount,
"maker": int(order.subaccount),
"taker": 0,
"amount": order.size,
"limitPrice": order.limitPrice if order.limitPrice is not None else 0,
"amount": int(order.size),
"limitPrice": int(order.limitPrice) if order.limitPrice is not None else 0,
"expiration": order.expiration if order.expiration is not None else 0,
"nonce": order.nonce,
"nonce": int(order.nonce),
"counter": 0,
"postOnly": order.postOnly if order.postOnly is not None else False,
"reduceOnly": order.reduceOnly if order.reduceOnly is not None else False,
Expand Down
77 changes: 61 additions & 16 deletions hook_odyssey/types.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from dataclasses import dataclass
from decimal import Decimal
from enum import Enum
from typing import List, Optional
from typing import Any, Dict, List, Optional


class EventType(Enum):
Expand Down Expand Up @@ -308,7 +308,7 @@ def __init__(self, eventType: str, balances: List[dict]):
@dataclass
class Position:
instrument: Instrument
subaccount: str
subaccount: int
marketHash: str
sizeHeld: Decimal
isLong: bool
Expand All @@ -324,7 +324,7 @@ def __init__(
averageCost: str,
):
self.instrument = Instrument(**instrument)
self.subaccount = subaccount
self.subaccount = int(subaccount)
self.marketHash = marketHash
try:
self.sizeHeld = to_decimal(int(sizeHeld))
Expand Down Expand Up @@ -431,15 +431,15 @@ def __init__(self, tier: str, makerFeeBips: int, takerFeeBips: int):
class PlaceOrderInput:
marketHash: str
instrumentHash: str
subaccount: int
subaccount: str # BigInts are represented as strings for go marshalling
orderType: OrderType
direction: OrderDirection
size: int
limitPrice: Optional[int]
size: str # BigInts are represented as strings for go marshalling
limitPrice: Optional[str] # BigInts are represented as strings for go marshalling
volatilityBips: Optional[int]
timeInForce: TimeInForce
expiration: Optional[int]
nonce: int
nonce: str # BigInts are represented as strings for go marshalling
postOnly: Optional[bool]
reduceOnly: Optional[bool]

Expand All @@ -452,27 +452,66 @@ def __init__(
direction: OrderDirection,
size: Decimal,
timeInForce: TimeInForce,
limitPrice: Decimal = Decimal(0),
nonce: int,
limitPrice: Optional[Decimal] = None,
volatilityBips: Optional[int] = None,
nonce: int = 0,
expiration: int = 0,
expiration: Optional[int] = None,
postOnly: bool = False,
reduceOnly: bool = False,
):
self.marketHash = marketHash
self.instrumentHash = instrumentHash
self.subaccount = subaccount
self.subaccount = str(subaccount)
self.orderType = orderType
self.direction = direction
self.size = from_decimal(size)
self.limitPrice = from_decimal(limitPrice)
self.volatilityBips = volatilityBips
self.size = str(from_decimal(size))
self.timeInForce = timeInForce
self.expiration = expiration
self.nonce = nonce
self.nonce = str(nonce)
if limitPrice is not None:
try:
self.limitPrice = str(from_decimal(limitPrice))
except ValueError:
raise ValueError(f"Invalid limitPrice: {limitPrice}")
else:
self.limitPrice = None
if volatilityBips is not None:
try:
self.volatilityBips = volatilityBips
except ValueError:
raise ValueError(f"Invalid volatilityBips: {volatilityBips}")
else:
self.volatilityBips = None
if expiration is not None:
try:
self.expiration = expiration
except ValueError:
raise ValueError(f"Invalid expiration: {expiration}")
else:
self.expiration = None
self.postOnly = postOnly
self.reduceOnly = reduceOnly

def to_dict(self):
d = {
"marketHash": self.marketHash,
"instrumentHash": self.instrumentHash,
"subaccount": self.subaccount,
"orderType": self.orderType.value,
"direction": self.direction.value,
"size": self.size,
"timeInForce": self.timeInForce.value,
"nonce": self.nonce,
"postOnly": self.postOnly,
"reduceOnly": self.reduceOnly,
}
if self.limitPrice is not None:
d["limitPrice"] = self.limitPrice
if self.volatilityBips is not None:
d["volatilityBips"] = self.volatilityBips
if self.expiration is not None:
d["expiration"] = self.expiration
return d


@dataclass
class SigningKeyInput:
Expand All @@ -487,6 +526,12 @@ class SignatureInput:
signatureType: SignatureType
signature: str

def to_dict(self) -> Dict[str, Any]:
return {
"signatureType": self.signatureType.value,
"signature": self.signature,
}


@dataclass
class TransferHistoryItem:
Expand Down
7 changes: 5 additions & 2 deletions tests/test_signer.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from copy import deepcopy
from decimal import Decimal

import pytest
Expand Down Expand Up @@ -42,6 +43,7 @@ def sample_order():
size=Decimal(1),
limitPrice=Decimal(2),
timeInForce=TimeInForce.GTC,
nonce=0,
)


Expand Down Expand Up @@ -96,9 +98,10 @@ def test_different_orders_produce_different_hashes(signer, sample_order):
hash1 = signer.get_order_hash(sample_order)

# Create a slightly different order
different_order = PlaceOrderInput(**sample_order.__dict__)
different_order.size = from_decimal(Decimal(2))
different_order = deepcopy(sample_order)
different_order.size = str(from_decimal(Decimal(2)))

hash2 = signer.get_order_hash(different_order)

assert hash1 != hash2
assert hash1 != hash2

0 comments on commit e0638dc

Please sign in to comment.