Trading Examples¶
This page provides examples of trading operations with the Ethereal Python SDK.
Creating orders¶
import asyncio
from decimal import Decimal
from ethereal import AsyncRESTClient
async def create_orders():
# Initialize client with your private key
client = await AsyncRESTClient.create({
"base_url": "https://api.etherealtest.net",
"chain_config": {
"rpc_url": "https://rpc.etherealtest.net",
"private_key": "your_private_key"
}
})
# Place a limit buy order
limit_buy = await client.create_order(
order_type="LIMIT",
quantity=Decimal("0.01"), # Buy 0.01 BTC
side=0, # 0 for buy
price=Decimal("80000"), # Price in USD
ticker="BTCUSD",
time_in_force="GTD", # Good Til Date
post_only=True
)
# Place a limit sell order
limit_sell = await client.create_order(
order_type="LIMIT",
quantity=Decimal("0.01"), # Sell 0.01 BTC
side=1, # 1 for sell
price=Decimal("85000"), # Price in USD
ticker="BTCUSD"
)
# Place a market buy order
market_buy = await client.create_order(
order_type="MARKET",
quantity=Decimal("0.01"), # Buy 0.01 BTC
side=0, # 0 for buy
ticker="BTCUSD"
)
await client.close()
return limit_buy, limit_sell, market_buy
# Run the async function
asyncio.run(create_orders())
Managing orders¶
from decimal import Decimal
async def manage_orders():
# Get all orders
subaccounts = await client.subaccounts()
sid = subaccounts[0].id
sname = subaccounts[0].name
orders = await client.list_orders(subaccount_id=sid)
# Get orders for a specific product
products_by_ticker = await client.products_by_ticker()
btc_product_id = products_by_ticker["BTCUSD"].id
btc_orders = await client.list_orders(subaccount_id=sid, product_ids=[btc_product_id])
# Get a specific order by ID
order_id = '78231588-f2a4-47b9-9b96-9ff8ed58d034'
order = await client.get_order(id=order_id)
# Cancel an order
cancel_results = await client.cancel_orders(order_ids=[order_id], sender=client.chain.address, subaccount=sname)
return orders, btc_orders, order, cancel_results
Order fills and trade history¶
from decimal import Decimal
async def get_trade_history():
# Get trade history
subaccounts = await client.subaccounts()
sid = subaccounts[0].id
trades = await client.list_trades(subaccount_id=sid)
# Get fills
fills = await client.list_fills(subaccount_id=sid)
# Get all fills for a product
products_by_ticker = await client.products_by_ticker()
btc_product_id = products_by_ticker['BTCUSD'].id
btc_fills = await client.list_fills(subaccount_id=sid, product_id=btc_product_id)
# Display fill information
for fill in fills:
print(fill.model_dump())
return trades, fills, btc_fills
Advanced Orders: Stops, OTO & OCO¶
Stop orders¶
What they are. A stop becomes active when the oracle crosses the stop_price
:
- Stop-market: executes at market when triggered ⇒ set
order_type="MARKET"
. - Stop-limit: when triggered, places a limit at
price
⇒ setorder_type="LIMIT"
and include bothstop_price
andprice
. stop_type
:0 = GAIN
(take-profit),1 = LOSS
(stop-loss).- Use
reduce_only=True
on exits so you don’t increase position size.
Stop-market (long position: take-profit & stop-loss)
from decimal import Decimal
async def create_stop_orders():
# Assuming a long position opened at $1000
# Take-profit (GAIN): triggers at or above stop_price
# Closes the position in profit if the price reaches 1050
tp = await client.create_order(
order_type="MARKET", product_id=pid, side=1, quantity=qty,
reduce_only=True, stop_type=0, stop_price=Decimal("1050"),
)
# Stop-loss (LOSS): triggers at or below stop_price
# Closes the position at a loss if the price reaches 900
sl = await client.create_order(
order_type="MARKET", product_id=pid, side=1, quantity=qty,
reduce_only=True, stop_type=1, stop_price=Decimal("900"),
)
return tp, sl
Stop-limit (long position exits)
from decimal import Decimal
async def create_stop_limit_orders():
# Assuming a long position opened at $1000
# Stop-limit take-profit: trigger a limit order
# Creates a limit order at 1050 if the price reaches 1050
tp_limit = await client.create_order(
order_type="LIMIT", product_id=pid, side=1, quantity=qty, reduce_only=True,
stop_type=0, stop_price=Decimal("1050"),
price=Decimal("1050"), # limit after trigger
)
# Stop-limit stop-loss: trigger a limit order
# Creates a limit order at 899 if the price reaches 900
sl_limit = await client.create_order(
order_type="LIMIT", product_id=pid, side=1, quantity=qty, reduce_only=True,
stop_type=1, stop_price=Decimal("900"),
price=Decimal("899"),
)
return tp_limit, sl_limit
One-Triggers-Other and One-Cancels-Other (OTO/OCO)¶
Orders with a group_id
and group_contingency_type
are linked and will be triggered accordingly. You can provide any UUID as a group_id
in order to easily manage related orders. Group contingency type has two values:
- OTO (One-Triggers-Other) →
group_contingency_type=0
on the primary order only. Secondary orders share agroup_id
and omitgroup_contingency_type
. Secondaries activate after the primary order fills. - OCO (One-Cancels-Other) → every order in the group sets
group_contingency_type=1
. When one fills/cancels, all orders in the group are auto-canceled.
Important limitations:
- Only one OTO trigger order is allowed per group
- Cannot mix OTO and OCO contingency types within the same group
- Groups are isolated per subaccount (same UUID can be reused across different subaccounts)
OCO: Take-profit and stop-loss exits¶
from decimal import Decimal
import uuid
async def create_oco_exits():
# Assume a long position opened at $1000
group_id = str(uuid.uuid4())
tp = await client.create_order(
order_type="LIMIT", product_id=pid, side=1, quantity=Decimal("0.001"),
price=Decimal("1050"),
time_in_force="GTD", reduce_only=True,
stop_type=0, stop_price=Decimal("1050"),
group_id=group_id, group_contingency_type=1, # OCO
)
sl = await client.create_order(
order_type="LIMIT", product_id=pid, side=1, quantity=Decimal("0.001"),
price=Decimal("899"),
time_in_force="GTD", reduce_only=True,
stop_type=1, stop_price=Decimal("900"),
group_id=group_id, group_contingency_type=1, # OCO
)
return tp, sl
OTO Scale-out: Multiple Profit Targets¶
Entry order triggers multiple exit orders at different price levels, useful for scaling out of positions.
from decimal import Decimal
import uuid
async def create_oto_scaleout():
group_id = str(uuid.uuid4())
# Entry order (must fill first)
entry = await client.create_order(
order_type="LIMIT", product_id=pid, side=0, quantity=Decimal("0.003"),
price=Decimal("1000"),
time_in_force="GTD",
group_id=group_id, group_contingency_type=0, # OTO
)
# Scale out at different profit levels (all triggered when entry fills)
exits = []
for exit_price in [Decimal("1050"), Decimal("1100"), Decimal("1150")]:
exit_order = await client.create_order(
order_type="LIMIT", product_id=pid, side=1, quantity=Decimal("0.001"),
price=exit_price,
time_in_force="GTD", reduce_only=True,
group_id=group_id,
)
exits.append(exit_order)
return entry, exits
Bracket Order: Entry + OCO Exits¶
For a bracket where take-profit and stop-loss cancel each other, first enter the position with a market order, then create OCO exit orders.
from decimal import Decimal
import uuid
async def create_bracket_order():
# 1) Enter position immediately
entry = await client.create_order(
order_type="MARKET", product_id=pid, side=0, quantity=Decimal("0.002"),
)
# 2) Set up OCO exits that cancel each other
exit_group = str(uuid.uuid4())
tp = await client.create_order(
order_type="LIMIT", product_id=pid, side=1, quantity=Decimal("0.002"),
price=Decimal("1050"), time_in_force="GTD", reduce_only=True,
group_id=exit_group, group_contingency_type=1, # OCO
)
sl = await client.create_order(
order_type="MARKET", product_id=pid, side=1, quantity=Decimal("0.002"),
stop_type=1, stop_price=Decimal("900"), reduce_only=True,
group_id=exit_group, group_contingency_type=1, # OCO
)
return entry, tp, sl