Skip to content

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

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

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