Skip to content

Commit

Permalink
Add market order example (#201)
Browse files Browse the repository at this point in the history
* Add market order example

* Implement standardized order chain helper functions

* Revise market order example to use new chain helpers

* Update order examples to reflect new API structure
  • Loading branch information
samtin0x authored Jul 22, 2024
1 parent 74af544 commit fd85b1e
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 29 deletions.
16 changes: 4 additions & 12 deletions v4-client-py-v2/dydx_v4_client/indexer/rest/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
DELAYMSG_MODULE_ADDRESS = "dydx1mkkvp26dngu6n8rmalaxyp3gwkjuzztq5zx6tr"


# Market Statistic Day Types
class MarketStatisticDay:
ONE = "1"
SEVEN = "7"
THIRTY = "30"
# Order Side
class OrderSide:
BUY = "BUY"
SELL = "SELL"


# Order Types
Expand All @@ -20,20 +19,13 @@ class OrderType:
TAKE_PROFIT_MARKET = "TAKE_PROFIT_MARKET"


# Order Side
class OrderSide:
BUY = "BUY"
SELL = "SELL"


# Order TimeInForce
class OrderTimeInForce:
GTT = "TIME_IN_FORCE_UNSPECIFIED"
IOC = "TIME_IN_FORCE_IOC"
FOK = "TIME_IN_FORCE_FILL_OR_KILL"


# Order Execution
class OrderExecution:
DEFAULT = "DEFAULT"
IOC = "IOC"
Expand Down
64 changes: 64 additions & 0 deletions v4-client-py-v2/dydx_v4_client/node/chain_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from dydx_v4_client.indexer.rest.constants import (
OrderType,
OrderExecution,
OrderTimeInForce,
)
from v4_proto.dydxprotocol.clob.order_pb2 import Order


class OrderHelper:
@staticmethod
def calculate_time_in_force(
order_type: OrderType,
time_in_force: Order.TimeInForce,
post_only: bool = False,
execution: OrderExecution = OrderExecution.DEFAULT,
) -> Order.TimeInForce:
if order_type == OrderType.MARKET:
return Order.TimeInForce.TIME_IN_FORCE_IOC
elif order_type == OrderType.LIMIT:
if post_only:
return Order.TimeInForce.TIME_IN_FORCE_POST_ONLY
else:
return time_in_force
elif order_type in [OrderType.STOP_LIMIT, OrderType.TAKE_PROFIT_LIMIT]:
if execution == OrderExecution.DEFAULT:
return Order.TimeInForce.TIME_IN_FORCE_UNSPECIFIED
elif execution == OrderExecution.POST_ONLY:
return Order.TimeInForce.TIME_IN_FORCE_POST_ONLY
elif execution == OrderExecution.FOK:
return Order.TimeInForce.TIME_IN_FORCE_FILL_OR_KILL
elif execution == OrderExecution.IOC:
return Order.TimeInForce.TIME_IN_FORCE_IOC
elif order_type in [OrderType.STOP_MARKET, OrderType.TAKE_PROFIT_MARKET]:
if execution in [OrderExecution.DEFAULT, OrderExecution.POST_ONLY]:
raise ValueError(
f"Execution value {execution.value} not supported for {order_type.value}"
)
elif execution == OrderExecution.FOK:
return Order.TimeInForce.TIME_IN_FORCE_FILL_OR_KILL
elif execution == OrderExecution.IOC:
return Order.TimeInForce.TIME_IN_FORCE_IOC
raise ValueError(
"Invalid combination of order type, time in force, and execution"
)

@staticmethod
def calculate_client_metadata(order_type: OrderType) -> int:
return (
1
if order_type
in [OrderType.MARKET, OrderType.STOP_MARKET, OrderType.TAKE_PROFIT_MARKET]
else 0
)

@staticmethod
def calculate_condition_type(order_type: OrderType) -> Order.ConditionType:
if order_type in [OrderType.LIMIT, OrderType.MARKET]:
return Order.ConditionType.CONDITION_TYPE_UNSPECIFIED
elif order_type in [OrderType.STOP_LIMIT, OrderType.STOP_MARKET]:
return Order.ConditionType.CONDITION_TYPE_STOP_LOSS
elif order_type in [OrderType.TAKE_PROFIT_LIMIT, OrderType.TAKE_PROFIT_MARKET]:
return Order.ConditionType.CONDITION_TYPE_TAKE_PROFIT
else:
raise ValueError("Invalid order type")
37 changes: 23 additions & 14 deletions v4-client-py-v2/dydx_v4_client/node/market.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

from v4_proto.dydxprotocol.clob.order_pb2 import Order, OrderId

from dydx_v4_client.indexer.rest.constants import OrderType, OrderExecution
from dydx_v4_client.node.chain_helpers import OrderHelper
from dydx_v4_client.node.message import order, order_id


Expand Down Expand Up @@ -51,28 +53,35 @@ def order_id(

def order(
self,
order_id: Order,
order_id: OrderId,
order_type: OrderType,
side: Order.Side,
size: float,
price: int,
time_in_force: Order.TimeInForce,
reduce_only: bool,
post_only: bool = False,
good_til_block: int = None,
good_til_block_time: int = None,
client_metadata: int = 0,
condition_type: Order.ConditionType = Order.ConditionType.CONDITION_TYPE_UNSPECIFIED,
execution: OrderExecution = OrderExecution.DEFAULT,
conditional_order_trigger_subticks: int = 0,
) -> Order:
order_time_in_force = OrderHelper.calculate_time_in_force(
order_type, time_in_force, post_only, execution
)
client_metadata = OrderHelper.calculate_client_metadata(order_type)
condition_type = OrderHelper.calculate_condition_type(order_type)

return order(
order_id,
side,
self.calculate_quantums(size),
self.calculate_subticks(price),
time_in_force,
reduce_only,
good_til_block,
good_til_block_time,
client_metadata,
condition_type,
conditional_order_trigger_subticks,
order_id=order_id,
side=side,
quantums=self.calculate_quantums(size),
subticks=self.calculate_subticks(price),
time_in_force=order_time_in_force,
reduce_only=reduce_only,
good_til_block=good_til_block,
good_til_block_time=good_til_block_time,
client_metadata=client_metadata,
condition_type=condition_type,
conditional_order_trigger_subticks=conditional_order_trigger_subticks,
)
2 changes: 1 addition & 1 deletion v4-client-py-v2/dydx_v4_client/node/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def place_order(order: Order):


def cancel_order(
order_id,
order_id: OrderId,
good_til_block: int = None,
good_til_block_time: int = None,
):
Expand Down
51 changes: 51 additions & 0 deletions v4-client-py-v2/examples/market_order_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import asyncio
import random

from dydx_v4_client import MAX_CLIENT_ID, NodeClient, OrderFlags, Wallet
from v4_proto.dydxprotocol.clob.order_pb2 import Order

from dydx_v4_client.indexer.rest.constants import OrderType
from dydx_v4_client.indexer.rest.indexer_client import IndexerClient
from dydx_v4_client.network import TESTNET
from dydx_v4_client.node.market import Market
from tests.conftest import DYDX_TEST_MNEMONIC, TEST_ADDRESS

MARKET_ID = "ETH-USD"


async def place_market_order(size: float):
node = await NodeClient.connect(TESTNET.node)
indexer = IndexerClient(TESTNET.rest_indexer)

market = Market(
(await indexer.markets.get_perpetual_markets(MARKET_ID))["markets"][MARKET_ID]
)
wallet = await Wallet.from_mnemonic(node, DYDX_TEST_MNEMONIC, TEST_ADDRESS)

order_id = market.order_id(
TEST_ADDRESS, 0, random.randint(0, MAX_CLIENT_ID), OrderFlags.SHORT_TERM
)

current_block = await node.latest_block_height()

new_order = market.order(
order_id=order_id,
order_type=OrderType.MARKET,
side=Order.Side.SIDE_SELL,
size=size,
price=0, # Set to 0 for market orders
time_in_force=Order.TimeInForce.TIME_IN_FORCE_UNSPECIFIED,
reduce_only=False,
good_til_block=current_block + 10,
)

transaction = await node.place_order(
wallet=wallet,
order=new_order,
)

print(transaction)
wallet.sequence += 1


asyncio.run(place_market_order(0.00001))
4 changes: 3 additions & 1 deletion v4-client-py-v2/examples/short_term_order_cancel_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import time

from dydx_v4_client import MAX_CLIENT_ID, NodeClient, Order, OrderFlags, Wallet
from dydx_v4_client.indexer.rest.constants import OrderType
from dydx_v4_client.indexer.rest.indexer_client import IndexerClient
from dydx_v4_client.network import TESTNET
from dydx_v4_client.node.market import Market
Expand Down Expand Up @@ -32,10 +33,11 @@ async def test():
wallet,
market.order(
order_id,
OrderType.LIMIT,
Order.Side.SIDE_SELL,
size=0.01,
price=40000,
time_in_force=Order.TIME_IN_FORCE_UNSPECIFIED,
time_in_force=Order.TimeInForce.TIME_IN_FORCE_UNSPECIFIED,
reduce_only=False,
good_til_block=good_til_block,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from pathlib import Path

from dydx_v4_client import MAX_CLIENT_ID, NodeClient, Order, OrderFlags, Wallet
from dydx_v4_client.indexer.rest.constants import OrderType
from dydx_v4_client.indexer.rest.indexer_client import IndexerClient
from dydx_v4_client.network import TESTNET
from dydx_v4_client.node.market import Market
Expand Down Expand Up @@ -48,6 +49,7 @@ async def test():
wallet,
market.order(
order_id,
OrderType.LIMIT,
to_order_side[order["side"]],
size=0.01,
price=order.get("price", 1350),
Expand Down
2 changes: 1 addition & 1 deletion v4-client-py-v2/tests/test_mutating_node_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ async def test_order(
# codespace: "sdk"\n code: 32\n raw_log: "account sequence mismatch, expected 1460, got 1459: incorrect account sequence"
# If the time is too long the result is:
# codespace: "clob"\n code:...hj67cghhf9jypslcf9sh2n5k6art Number:0} ClientId:13850897 OrderFlags:64 ClobPairId:0}: Stateful order does not exist"
time.sleep(2)
time.sleep(1.5)

wallet = await get_wallet(node_client, private_key, test_address)

Expand Down

0 comments on commit fd85b1e

Please sign in to comment.