Skip to content

Trading Examples

This page provides examples of trading operations with the Ethereal Python SDK.

Setup

All examples on this page use the AsyncRESTClient. Here's the basic pattern used throughout:

import asyncio
from decimal import Decimal
from ethereal import AsyncRESTClient

async def main():
    # Initialize client
    client = await AsyncRESTClient.create({
        "base_url": "https://api.ethereal.trade",
        "chain_config": {
            "rpc_url": "https://rpc.ethereal.trade",
            "private_key": "your_private_key"
        }
    })

    # Your code here

    await client.close()

asyncio.run(main())

The examples below show the code that goes in the "Your code here" section. For a complete standalone example, see Creating orders.

Creating orders

This complete example shows the full pattern including imports, initialization, and cleanup:

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.ethereal.trade",
        "chain_config": {
            "rpc_url": "https://rpc.ethereal.trade",
            "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

# 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
)

Order fills and 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())

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 ⇒ set order_type="LIMIT" and include both stop_price and price.
  • 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)

# Assuming a long position opened at $1000
# Define the product and quantity for the examples
products_by_ticker = await client.products_by_ticker()
pid = products_by_ticker["BTCUSD"].id  # Product ID
qty = Decimal("0.01")  # Quantity to close

# 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"),
)

Stop-limit (long position exits)

# Assuming a long position opened at $1000
# Define the product and quantity for the examples
products_by_ticker = await client.products_by_ticker()
pid = products_by_ticker["BTCUSD"].id  # Product ID
qty = Decimal("0.01")  # Quantity to close

# 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"),
)

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 a group_id and omit group_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

import uuid

# Assume a long position opened at $1000
# Define the product for the examples
products_by_ticker = await client.products_by_ticker()
pid = products_by_ticker["BTCUSD"].id  # Product ID

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
)

OTO Scale-out: Multiple Profit Targets

Entry order triggers multiple exit orders at different price levels, useful for scaling out of positions.

import uuid

# Define the product for the examples
products_by_ticker = await client.products_by_ticker()
pid = products_by_ticker["BTCUSD"].id  # Product ID

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)

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.

import uuid

# Define the product for the examples
products_by_ticker = await client.products_by_ticker()
pid = products_by_ticker["BTCUSD"].id  # Product ID

# 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
)