open-position
Place trades on Eterna with proper sizing, leverage, and risk management
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Place trades on Eterna with proper sizing, leverage, and risk management
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Close positions and cancel orders on Eterna
Guide user through depositing crypto and transferring funds to the trading wallet
Live market scanning, technical analysis, and trade idea generation using Eterna CLI
Always-active router for Eterna trading — detects user state and invokes the right skill
Withdraw crypto from Eterna to an external wallet
| name | open_position |
| description | Place trades on Eterna with proper sizing, leverage, and risk management |
| metadata.openclaw.requires.bins | [{"name":"eterna","install":"npm install -g @eterna-hybrid-exchange/cli","postInstall":"eterna login"}] |
Place trades with proper instrument checks, leverage, position sizing, and TP/SL.
minOrderQty, qtyStep, tickSize for proper rounding.const symbol = "LINKUSDT"; // replace
const [balance, positions, instruments, ticker] = await Promise.all([
eterna.getBalance(),
eterna.getPositions(symbol),
eterna.getInstruments(symbol),
eterna.getTickers(symbol),
]);
const equity = parseFloat(balance.list[0].totalEquity);
const existingPos = positions.list.filter((p) => parseFloat(p.size) > 0);
const spec = instruments.list[0];
const price = parseFloat(ticker.list[0].lastPrice);
return {
equity,
availableBalance: balance.list[0].totalAvailableBalance,
existingPositions: existingPos.map((p) => ({ side: p.side, size: p.size, entry: p.avgPrice })),
contract: {
minOrderQty: spec.lotSizeFilter.minOrderQty,
qtyStep: spec.lotSizeFilter.qtyStep,
tickSize: spec.priceFilter.tickSize,
maxLeverage: spec.leverageFilter.maxLeverage,
},
currentPrice: price,
};
If equity < $20, suggest depositing more. If there's already a position on this symbol, warn the user.
Before executing, show the user exactly what you'll do:
Long LINKUSDT at ~$9.36
- Size: 5.3 LINK (~$50 notional, 2x leverage)
- Margin used: ~$25 (50% of equity)
- Stop loss: $9.17 (-2%)
- Take profit: $9.69 (+3.5%)
- Risk/reward: 1.75:1
Should I place this?
Be clear about margin vs notional. "Size: X LINK (~$Y notional, Zx leverage)" so the user knows both the position value and how much margin is used.
Only after user confirms:
const symbol = "LINKUSDT";
const side = "Buy"; // or "Sell" for short
const leverage = 2;
const equityFraction = 0.25; // 25% of equity
const slPercent = 0.02; // 2% stop
const tpPercent = 0.035; // 3.5% target
// Get specs and price
const [instruments, ticker, balance] = await Promise.all([
eterna.getInstruments(symbol),
eterna.getTickers(symbol),
eterna.getBalance(),
]);
const spec = instruments.list[0];
const minQty = parseFloat(spec.lotSizeFilter.minOrderQty);
const qtyStep = parseFloat(spec.lotSizeFilter.qtyStep);
const tickSize = parseFloat(spec.priceFilter.tickSize);
const price = parseFloat(ticker.list[0].lastPrice);
const equity = parseFloat(balance.list[0].totalEquity);
// Set leverage first
await eterna.setLeverage({ symbol, leverage });
// Calculate qty — round DOWN to qtyStep
const positionValue = equity * equityFraction * leverage;
let qty = Math.floor((positionValue / price) / qtyStep) * qtyStep;
if (qty < minQty) qty = minQty;
// Calculate TP/SL — round to tickSize
let sl, tp;
if (side === "Buy") {
sl = Math.floor((price * (1 - slPercent)) / tickSize) * tickSize;
tp = Math.ceil((price * (1 + tpPercent)) / tickSize) * tickSize;
} else {
sl = Math.ceil((price * (1 + slPercent)) / tickSize) * tickSize;
tp = Math.floor((price * (1 - tpPercent)) / tickSize) * tickSize;
}
const order = await eterna.placeOrder({
symbol, side, orderType: "Market",
qty: qty.toString(), leverage,
stopLoss: sl.toString(), takeProfit: tp.toString(),
});
return {
orderId: order.orderId, symbol, side,
qty: qty.toString(),
estimatedEntry: price.toString(),
stopLoss: sl.toString(), takeProfit: tp.toString(),
leverage,
marginUsed: (qty * price / leverage).toFixed(2) + " USDT",
notionalValue: (qty * price).toFixed(2) + " USDT",
};
After placing, verify the position:
const positions = await eterna.getPositions("LINKUSDT");
return positions.list.filter((p) => parseFloat(p.size) > 0).map((p) => ({
symbol: p.symbol, side: p.side, size: p.size,
entryPrice: p.avgPrice, markPrice: p.markPrice,
unrealisedPnl: p.unrealisedPnl,
leverage: p.leverage, takeProfit: p.takeProfit, stopLoss: p.stopLoss,
}));
qtyStep, prices to tickSize.| Method | Returns |
|---|---|
eterna.getBalance() | { list: [{ totalEquity, totalAvailableBalance, coin: [...] }] } |
eterna.getPositions(symbol?) | { list: [{ symbol, side, size, avgPrice, markPrice, unrealisedPnl, leverage, takeProfit, stopLoss }] } |
eterna.getInstruments(symbol?) | { list: [{ lotSizeFilter: { minOrderQty, qtyStep }, priceFilter: { tickSize }, leverageFilter: { maxLeverage } }] } |
eterna.getTickers(symbol?) | { list: [{ lastPrice, ... }] } — strings |
eterna.setLeverage({ symbol, leverage }) | {} — must call before placeOrder |
eterna.placeOrder({ symbol, side, orderType, qty, leverage?, stopLoss?, takeProfit?, price?, reduceOnly? }) | { orderId, orderLinkId } |
eterna.getOrders(symbol?) | { list: [{ symbol, orderId, side, orderType, qty, price, orderStatus }] } |