> For the complete documentation index, see [llms.txt](https://docs.ojolabs.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ojolabs.xyz/markets/api/programmatic-trading/creating-orders.md).

# Creating Orders

Step-by-step guide for creating, signing, submitting, and managing orders programmatically with the Python SDK.

## Prerequisites

Install the SDK and have your credentials ready:

```bash
pip install turbine-py-client
```

You need a wallet private key and API credentials. If you don't have API credentials yet, the SDK can register them for you (see Auto-Registration below).

## Initialize the Client

```python
import os
import time
from dotenv import load_dotenv
from turbine_client import TurbineClient, Outcome, Side, OrderArgs

load_dotenv()

client = TurbineClient(
    host=os.environ["TURBINE_HOST"],            # https://api.turbinefi.com
    chain_id=int(os.environ.get("CHAIN_ID", "137")),
    private_key=os.environ["TURBINE_PRIVATE_KEY"],
    api_key_id=os.environ["TURBINE_API_KEY_ID"],
    api_private_key=os.environ["TURBINE_API_PRIVATE_KEY"],
)
```

### Auto-Registration

If you don't have `TURBINE_API_KEY_ID` and `TURBINE_API_PRIVATE_KEY` yet, register them first:

```python
credentials = TurbineClient.request_api_credentials(
    host="https://api.turbinefi.com",
    private_key=os.environ["TURBINE_PRIVATE_KEY"],
)

# Save these — the private key is not recoverable
print(f"TURBINE_API_KEY_ID={credentials['api_key_id']}")
print(f"TURBINE_API_PRIVATE_KEY={credentials['api_private_key']}")
```

## Check the Orderbook

Before placing an order, inspect the current orderbook to find appropriate prices:

```python
market_id = "0x..."  # Get from client.get_markets() or client.get_quick_market()

ob = client.get_orderbook(market_id, outcome=Outcome.YES)

print("YES Orderbook:")
print("  Bids (buy orders):")
for level in ob.bids[:5]:
    print(f"    {level.price} (${level.price / 1e6:.4f}) x {level.size / 1e6:.2f} shares")

print("  Asks (sell orders):")
for level in ob.asks[:5]:
    print(f"    {level.price} (${level.price / 1e6:.4f}) x {level.size / 1e6:.2f} shares")

# Calculate mid price
if ob.bids and ob.asks:
    mid = (ob.bids[0].price + ob.asks[0].price) // 2
    print(f"\n  Mid: {mid} (${mid / 1e6:.4f})")
    print(f"  Spread: {ob.asks[0].price - ob.bids[0].price}")
```

## Create and Submit an Order

### Using create\_limit\_buy / create\_limit\_sell

The simplest approach. The client handles signing and nonce generation:

```python
# Buy 10 YES shares at $0.45
signed = client.create_limit_buy(
    market_id=market_id,
    outcome=Outcome.YES,
    price=450000,       # $0.45
    size=10000000,      # 10 shares
    expiration=int(time.time()) + 3600,  # 1 hour
)

print(f"Order hash: {signed.order_hash}")
print(f"Cost if filled: {450000 * 10000000 / 1e6 / 1e6:.2f} USDC")  # $4.50

# Submit to the orderbook
result = client.post_order(signed)
print(f"Result: {result}")
```

```python
# Sell 5 NO shares at $0.60
signed = client.create_limit_sell(
    market_id=market_id,
    outcome=Outcome.NO,
    price=600000,       # $0.60
    size=5000000,       # 5 shares
    expiration=int(time.time()) + 3600,
)

result = client.post_order(signed)
```

### Using OrderArgs

For more control, construct `OrderArgs` explicitly:

```python
args = OrderArgs(
    market_id=market_id,
    side=Side.BUY,
    outcome=Outcome.YES,
    price=500000,                        # $0.50
    size=1000000,                        # 1 share
    expiration=int(time.time()) + 3600,  # 1 hour
    nonce=0,                             # auto-generated
    maker_fee_recipient="0x0000000000000000000000000000000000000000",
)

signed = client.create_order(args)
result = client.post_order(signed)
```

## Price and Size Encoding

All prices and sizes are integers with 6 decimal places:

| Value | Raw        | Meaning                 |
| ----- | ---------- | ----------------------- |
| Price | `500000`   | $0.50 (50% probability) |
| Price | `100000`   | $0.10 (10% probability) |
| Price | `900000`   | $0.90 (90% probability) |
| Size  | `1000000`  | 1 share                 |
| Size  | `10000000` | 10 shares               |
| Size  | `500000`   | 0.5 shares              |

Valid prices: `1` to `999999` (exclusive of 0 and 1,000,000).

Cost to buy: `price * size / 1,000,000`. For example, buying 10 shares at `450000` ($0.45) costs `450000 * 10000000 / 1000000 = 4500000` = $4.50 USDC.

Payout if you win: `size`. So 10 shares pay `10000000` = $10 USDC. Profit = $10 - $4.50 = $5.50.

## USDC Approval

Before your first order can settle, the settlement contract needs USDC approval. Use the gasless max permit (one-time, no native gas needed):

```python
# One-time gasless max approval per settlement contract
result = client.approve_usdc_for_settlement()
print(f"Approval TX: {result}")
```

This signs an EIP-2612 max permit and submits it to the relayer. All subsequent orders on that settlement contract reuse the existing allowance.

To check the current allowance:

```python
allowance = client.get_usdc_allowance()
print(f"Current allowance: {allowance / 1e6:.2f} USDC")
```

### Per-Order Permit (Alternative)

You can attach a permit to an individual order instead:

```python
permit = client.sign_usdc_permit(value=5000000)  # $5 USDC
signed.permit_signature = permit
result = client.post_order(signed)
```

## Order Lifecycle

{% stepper %}
{% step %}

### Created

`create_limit_buy()` or `create_order()` signs the order locally and returns a `SignedOrder`.
{% endstep %}

{% step %}

### Submitted

`post_order()` sends it to the API. The matching engine checks for compatible counter-orders.
{% endstep %}

{% step %}

### Matched

If a compatible order exists, a trade is created. Both orders are matched at the maker's price.
{% endstep %}

{% step %}

### Settled

The matched trade is settled on-chain via the settlement contract.
{% endstep %}

{% step %}

### Failed / Pending

Check `get_failed_trades()` / `get_pending_trades()` for settlement status.
{% endstep %}
{% endstepper %}

## Cancel Orders

### Cancel a Single Order

```python
result = client.cancel_order(
    order_hash="0xOrderHash...",
    market_id=market_id,    # optional validation
    side=Side.BUY,          # optional validation
)
print(f"Cancelled: {result}")
```

### Cancel All Orders for a Market

```python
result = client.cancel_market_orders(market_id=market_id)
print(f"Cancelled all: {result}")
```

## Monitor Order Status

### Check Your Open Orders

```python
orders = client.get_orders(market_id=market_id, status="open")

for o in orders:
    side = "BUY" if o.side == 0 else "SELL"
    outcome = "YES" if o.outcome == 0 else "NO"
    filled_pct = o.filled_size / o.size * 100 if o.size > 0 else 0
    print(
        f"{side} {outcome}: {o.remaining_size / 1e6:.2f} remaining "
        f"@ {o.price} (${o.price / 1e6:.4f}) | "
        f"filled: {filled_pct:.1f}% | {o.status}"
    )
```

### Check a Specific Order

```python
order = client.get_order("0xOrderHash...")
print(f"Status: {order.status}")
print(f"Filled: {order.filled_size / 1e6:.2f} / {order.size / 1e6:.2f}")
print(f"Remaining: {order.remaining_size / 1e6:.2f}")
```

### Monitor Failed and Pending Trades

After orders match, trades go through on-chain settlement. Monitor the pipeline:

```python
# Trades waiting for settlement TX
pending = client.get_pending_trades()
for t in pending:
    print(f"Pending: {t.fill_size / 1e6:.2f} @ {t.fill_price} (${t.fill_price / 1e6:.4f}) | tx={t.tx_hash}")

# Trades that failed settlement
failed = client.get_failed_trades()
for t in failed:
    print(f"Failed: {t.fill_size / 1e6:.2f} @ {t.fill_price} (${t.fill_price / 1e6:.4f}) | reason={t.reason}")

# Check a specific settlement TX
status = client.get_settlement_status("0xTxHash...")
print(f"Found: {status.found}, Status: {status.status}, Error: {status.error}")
```

## Complete Example

A script that checks the orderbook, places a buy order, and monitors it:

```python
import os
import time
from dotenv import load_dotenv
from turbine_client import TurbineClient, Outcome, Side

load_dotenv()

client = TurbineClient(
    host=os.environ["TURBINE_HOST"],
    chain_id=int(os.environ.get("CHAIN_ID", "137")),
    private_key=os.environ["TURBINE_PRIVATE_KEY"],
    api_key_id=os.environ["TURBINE_API_KEY_ID"],
    api_private_key=os.environ["TURBINE_API_PRIVATE_KEY"],
)

# Get active BTC quick market
qm = client.get_quick_market("BTC")
market_id = qm.market_id
print(f"Market: Will BTC be above ${qm.start_price / 1e8:,.2f}?")
print(f"Market ID: {market_id}")

# Ensure USDC approval (gasless, one-time)
allowance = client.get_usdc_allowance()
if allowance < 2**128:
    print("Approving USDC (gasless)...")
    client.approve_usdc_for_settlement()

# Check orderbook
ob = client.get_orderbook(market_id, outcome=Outcome.YES)
if ob.asks:
    best_ask = ob.asks[0]
    print(f"Best YES ask: {best_ask.price} (${best_ask.price / 1e6:.4f}) x {best_ask.size / 1e6:.2f}")

# Place a limit buy for YES at $0.45
signed = client.create_limit_buy(
    market_id=market_id,
    outcome=Outcome.YES,
    price=450000,       # $0.45
    size=2000000,       # 2 shares
    expiration=int(time.time()) + 900,  # 15 minutes
)

print(f"\nSubmitting order: BUY 2 YES @ 450000 ($0.45)")
print(f"Order hash: {signed.order_hash}")
print(f"Cost if filled: $0.90 USDC")

result = client.post_order(signed)
print(f"Response: {result}")

# Wait and check status
time.sleep(5)
order = client.get_order(signed.order_hash)
print(f"\nOrder status: {order.status}")
print(f"Filled: {order.filled_size / 1e6:.2f} / {order.size / 1e6:.2f}")

if order.status == "open" and order.remaining_size > 0:
    print("Order still open. Cancelling...")
    client.cancel_order(signed.order_hash)
    print("Cancelled.")
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ojolabs.xyz/markets/api/programmatic-trading/creating-orders.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
