Loading...
Loading...
Place, manage, and cancel orders using REST API or SDK hooks. Covers market, limit, IOC, FOK, POST_ONLY order types and batch operations
npx skill4agent add orderlynetwork/skills orderly-trading-orderstrading| Type | Description | Use Case |
|---|---|---|
| Order at specific price | Precise entry/exit |
| Execute at best available price | Immediate execution |
| Immediate-or-Cancel | Partial fill acceptable |
| Fill-or-Kill | All or nothing |
| Maker-only order | Earn maker rebates |
| Best ask price guaranteed | Quick sell |
| Best bid price guaranteed | Quick buy |
POST /v1/orderinterface OrderRequest {
symbol: string; // e.g., "PERP_ETH_USDC"
side: 'BUY' | 'SELL';
order_type: 'LIMIT' | 'MARKET' | 'IOC' | 'FOK' | 'POST_ONLY' | 'ASK' | 'BID';
order_price?: number; // Required for LIMIT orders
order_quantity: number; // Base asset quantity
visible_quantity?: number; // For hidden orders (0 = hidden)
client_order_id?: string; // Your custom ID
trigger_price?: string; // For stop orders
}import { signAsync } from '@noble/ed25519';
async function placeOrder(order: OrderRequest) {
const timestamp = Date.now();
const body = JSON.stringify(order);
const message = `${timestamp}POST/v1/order${body}`;
const signature = await signAsync(new TextEncoder().encode(message), privateKey);
// Encode as base64url (browser & Node.js compatible)
const base64 = btoa(String.fromCharCode(...signature));
const base64url = base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
const response = await fetch('https://api.orderly.org/v1/order', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'orderly-timestamp': String(timestamp),
'orderly-account-id': accountId,
'orderly-key': `ed25519:${publicKeyBase58}`,
'orderly-signature': base64url,
},
body,
});
return response.json();
}
// Place a limit buy order
const order = await placeOrder({
symbol: 'PERP_ETH_USDC',
side: 'BUY',
order_type: 'LIMIT',
order_price: 3000,
order_quantity: 0.1,
});import { useOrderEntry, OrderSide, OrderType } from '@orderly.network/hooks';
function OrderForm({ symbol }: { symbol: string }) {
const {
submit,
setValue,
getValue,
helper,
reset,
isSubmitting
} = useOrderEntry(symbol, {
initialOrder: {
side: OrderSide.BUY,
order_type: OrderType.LIMIT,
price: '',
order_quantity: '',
},
});
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
// Validate before submission
const validationResult = await helper.validate();
if (!validationResult) {
console.error('Validation failed');
return;
}
try {
await submit();
reset();
console.log('Order placed successfully');
} catch (error) {
console.error('Order failed:', error);
}
};
return (
<form onSubmit={handleSubmit}>
<select
onChange={(e) => setValue('side', e.target.value as OrderSide)}
value={getValue('side')}
>
<option value={OrderSide.BUY}>Buy</option>
<option value={OrderSide.SELL}>Sell</option>
</select>
<select
onChange={(e) => setValue('order_type', e.target.value as OrderType)}
value={getValue('order_type')}
>
<option value={OrderType.LIMIT}>Limit</option>
<option value={OrderType.MARKET}>Market</option>
</select>
<input
type="text"
placeholder="Price"
value={getValue('price') || ''}
onChange={(e) => setValue('price', e.target.value)}
/>
<input
type="text"
placeholder="Quantity"
value={getValue('order_quantity') || ''}
onChange={(e) => setValue('order_quantity', e.target.value)}
/>
<button type="submit" disabled={isSubmitting}>
{isSubmitting ? 'Placing...' : 'Place Order'}
</button>
</form>
);
}// Get order rules for a symbol
const rulesResponse = await fetch('https://api.orderly.org/v1/public/info/PERP_ETH_USDC');
const rules = await rulesResponse.json();
/*
Rules include:
- base_min: Minimum order size
- base_max: Maximum order size
- base_tick: Size increment
- quote_min: Minimum price
- quote_max: Maximum price
- quote_tick: Price increment
- min_notional: Minimum order value
*/
function validateOrder(order: OrderRequest, rules: OrderRules): boolean {
// Price filter
if (order.order_price) {
const price = parseFloat(order.order_price);
if (price < rules.quote_min || price > rules.quote_max) {
throw new Error('Price out of range');
}
if ((price - rules.quote_min) % rules.quote_tick !== 0) {
throw new Error('Invalid price tick');
}
}
// Size filter
const quantity = parseFloat(order.order_quantity);
if (quantity < rules.base_min || quantity > rules.base_max) {
throw new Error('Quantity out of range');
}
if ((quantity - rules.base_min) % rules.base_tick !== 0) {
throw new Error('Invalid quantity tick');
}
// Min notional
const notional = (parseFloat(order.order_price) || 0) * quantity;
if (notional < rules.min_notional) {
throw new Error(`Minimum order value is ${rules.min_notional}`);
}
return true;
}// REST API
DELETE /v1/order?order_id={order_id}&symbol={symbol}
// React SDK
import { useOrderStream } from '@orderly.network/hooks';
function OrderList() {
const [orders, { cancelOrder }] = useOrderStream({
status: OrderStatus.INCOMPLETE,
});
return orders.map((order) => (
<div key={order.order_id}>
{order.symbol} - {order.side} - {order.order_qty}
<button onClick={() => cancelOrder(order.order_id)}>
Cancel
</button>
</div>
));
}// REST API - Cancel all open orders
DELETE /v1/orders?symbol={symbol} // Optional symbol filter
// React SDK
const [orders, { cancelAllOrders }] = useOrderStream();
await cancelAllOrders(); // Cancel all
await cancelAllOrders({ symbol: 'PERP_ETH_USDC' }); // Cancel for specific symbolDELETE /v1/client/order?client_order_id={client_order_id}&symbol={symbol}// Batch create (max 10 orders)
POST /v1/batch-order
Body: {
orders: [
{ symbol: 'PERP_ETH_USDC', side: 'BUY', order_type: 'LIMIT', order_price: 3000, order_quantity: 0.1 },
{ symbol: 'PERP_BTC_USDC', side: 'BUY', order_type: 'LIMIT', order_price: 50000, order_quantity: 0.01 }
]
}
// Batch cancel (max 10 orders)
DELETE /v1/batch-order?order_ids={id1},{id2},...
// Example
const batchResponse = await fetch('https://api.orderly.org/v1/batch-order', {
method: 'POST',
headers: { /* auth headers */ },
body: JSON.stringify({
orders: [
{ symbol: 'PERP_ETH_USDC', side: 'BUY', order_type: 'LIMIT', order_price: 3000, order_quantity: 0.1 },
{ symbol: 'PERP_BTC_USDC', side: 'BUY', order_type: 'LIMIT', order_price: 50000, order_quantity: 0.01 }
]
}),
});// REST API
PUT /v1/order
Body: {
order_id: '123456',
order_price: '3100', // New price
order_quantity: '0.2', // New quantity
}import { useOrderStream, OrderStatus } from '@orderly.network/hooks';
function OrderMonitor() {
const [orders, { cancelOrder }] = useOrderStream({
status: OrderStatus.INCOMPLETE,
});
return (
<table>
<thead>
<tr>
<th>Symbol</th>
<th>Side</th>
<th>Price</th>
<th>Quantity</th>
<th>Filled</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{orders.map((order) => (
<tr key={order.order_id}>
<td>{order.symbol}</td>
<td>{order.side}</td>
<td>{order.price}</td>
<td>{order.order_qty}</td>
<td>{order.filled_qty}</td>
<td>{order.status}</td>
<td>
<button onClick={() => cancelOrder(order.order_id)}>
Cancel
</button>
</td>
</tr>
))}
</tbody>
</table>
);
}// Basic algo order structure
POST /v1/algo/order
Body: {
symbol: 'PERP_ETH_USDC',
type: 'CLOSE_POSITION',
algoType: 'TAKE_PROFIT',
trigger_price: '3500',
quantity: '0.1',
}| Endpoint | Rate Limit |
|---|---|
| POST /v1/order | 10 req/sec |
| DELETE /v1/order | 10 req/sec |
| PUT /v1/order | 10 req/sec |
| POST /v1/batch-order | 1 req/sec |
| DELETE /v1/batch-order | 10 req/sec |
NEW → PARTIAL_FILLED → FILLED
↘ CANCELLED
↘ REJECTED (invalid orders)
↘ EXPIRED (GTD orders)GET /v1/client/holdingprice_rangequote_tickbase_tickGET /v1/public/info/{symbol}