Hyperliquid Trading Bots mit Bun: Vollstandige SDK-Anleitung (2026)

Hyperliquid ist die am schnellsten wachsende Perpetual-DEX, die Milliarden an täglichem Volumen mit Ausführungen unter einer Sekunde verarbeitet. Ihr offizielles npm-Paket ermöglicht es, Trading-Bots einfach mit Bun zu erstellen. Diese Anleitung behandelt die Einrichtung, Orderausführung und Produktionsstrategien.

Starten Sie auf Hyperliquid: Melden Sie sich mit unserem Empfehlungslink an, um diesen Leitfaden zu unterstutzen und mit reduzierten Gebuhren zu handeln.

Was ist Hyperliquid?

Hyperliquid ist eine dezentrale Perpetual-Futures-Börse, die auf ihrer eigenen L1-Blockchain läuft. Hauptmerkmale:

  • Geschwindigkeit: ~200ms Blockzeit, 100k+ TPS Kapazität
  • Liquidität: $1B+ tägliches Volumen, enge Spreads
  • Keine Gasgebühren: Trading ist kostenlos (nur Funding-Zahlungen)
  • Selbstverwahrung: Handeln Sie direkt aus Ihrer Wallet
  • 50-facher Hebel: Bei wichtigen Handelspaaren

Einrichtung mit Bun

Installation

# Create project
mkdir hyperliquid-bot && cd hyperliquid-bot
bun init -y

# Install Hyperliquid SDK
bun add hyperliquid

# Install additional dependencies
bun add dotenv

Projektstruktur

hyperliquid-bot/
├── src/
│   ├── index.ts
│   ├── client.ts
│   ├── strategies/
│   │   └── grid.ts
│   └── utils/
│       └── helpers.ts
├── .env
├── package.json
└── tsconfig.json

Umgebungskonfiguration

# .env
HYPERLIQUID_PRIVATE_KEY=your_private_key_here
HYPERLIQUID_WALLET_ADDRESS=0x...
# Use mainnet or testnet
HYPERLIQUID_TESTNET=false

Client-Einrichtung

// src/client.ts
import Hyperliquid from "hyperliquid";
import "dotenv/config";

const privateKey = process.env.HYPERLIQUID_PRIVATE_KEY;
const walletAddress = process.env.HYPERLIQUID_WALLET_ADDRESS;
const testnet = process.env.HYPERLIQUID_TESTNET === "true";

if (!privateKey || !walletAddress) {
  throw new Error("Missing HYPERLIQUID_PRIVATE_KEY or HYPERLIQUID_WALLET_ADDRESS");
}

export const sdk = new Hyperliquid({
  privateKey,
  testnet,
  walletAddress,
});

// Initialize the SDK
export async function initClient() {
  await sdk.connect();
  console.log(`Connected to Hyperliquid ${testnet ? "testnet" : "mainnet"}`);
  return sdk;
}

Marktdaten abrufen

Alle Märkte abrufen

// Get available perpetual markets
async function getMarkets() {
  const meta = await sdk.info.perpetuals.getMeta();

  console.log("Available markets:");
  for (const asset of meta.universe) {
    console.log(`${asset.name}: ${asset.szDecimals} decimals, max leverage ${asset.maxLeverage}x`);
  }

  return meta.universe;
}

Orderbuch abrufen

// Fetch orderbook for a symbol
async function getOrderbook(symbol: string) {
  const book = await sdk.info.perpetuals.getL2Book({ coin: symbol });

  console.log(`${symbol} Orderbook:`);
  console.log("Bids:", book.levels[0].slice(0, 5)); // Top 5 bids
  console.log("Asks:", book.levels[1].slice(0, 5)); // Top 5 asks

  const bestBid = parseFloat(book.levels[0][0].px);
  const bestAsk = parseFloat(book.levels[1][0].px);
  const spread = ((bestAsk - bestBid) / bestBid * 100).toFixed(4);

  console.log(`Spread: ${spread}%`);

  return book;
}

// Usage
await getOrderbook("BTC");

Benutzerstatus abrufen

// Get account balance and positions
async function getAccountState() {
  const state = await sdk.info.perpetuals.getClearinghouseState({
    user: walletAddress,
  });

  console.log("Account equity:", state.marginSummary.accountValue);
  console.log("Available balance:", state.withdrawable);

  console.log("\nOpen positions:");
  for (const position of state.assetPositions) {
    if (parseFloat(position.position.szi) !== 0) {
      console.log(`${position.position.coin}:`);
      console.log(`  Size: ${position.position.szi}`);
      console.log(`  Entry: ${position.position.entryPx}`);
      console.log(`  Unrealized PnL: ${position.position.unrealizedPnl}`);
    }
  }

  return state;
}

Echtzeit-Preisfeeds

// Subscribe to price updates via WebSocket
async function subscribeToPrices(symbols: string[]) {
  sdk.subscriptions.subscribeToAllMids((data) => {
    for (const symbol of symbols) {
      if (data.mids[symbol]) {
        console.log(`${symbol}: $${data.mids[symbol]}`);
      }
    }
  });

  console.log(`Subscribed to: ${symbols.join(", ")}`);
}

// Subscribe to trades
async function subscribeToTrades(symbol: string) {
  sdk.subscriptions.subscribeToTrades({ coin: symbol }, (trade) => {
    console.log(`${symbol} Trade: ${trade.side} ${trade.sz} @ ${trade.px}`);
  });
}

Trades ausführen

Market-Orders

// Place a market order
async function marketOrder(
  symbol: string,
  isBuy: boolean,
  size: number
) {
  const order = await sdk.exchange.placeOrder({
    coin: symbol,
    is_buy: isBuy,
    sz: size,
    limit_px: isBuy ? 999999 : 0.01, // Market order simulation
    order_type: { limit: { tif: "Ioc" } }, // Immediate or cancel
    reduce_only: false,
  });

  console.log(`Market ${isBuy ? "buy" : "sell"} ${size} ${symbol}`);
  console.log("Order response:", order);

  return order;
}

// Usage
await marketOrder("ETH", true, 0.1); // Buy 0.1 ETH

Limit-Orders

// Place a limit order
async function limitOrder(
  symbol: string,
  isBuy: boolean,
  size: number,
  price: number
) {
  const order = await sdk.exchange.placeOrder({
    coin: symbol,
    is_buy: isBuy,
    sz: size,
    limit_px: price,
    order_type: { limit: { tif: "Gtc" } }, // Good til cancelled
    reduce_only: false,
  });

  console.log(`Limit ${isBuy ? "buy" : "sell"} ${size} ${symbol} @ ${price}`);
  return order;
}

// Place order at 1% below current price
async function placeBuyAtDiscount(symbol: string, size: number) {
  const book = await sdk.info.perpetuals.getL2Book({ coin: symbol });
  const midPrice = (parseFloat(book.levels[0][0].px) + parseFloat(book.levels[1][0].px)) / 2;
  const buyPrice = midPrice * 0.99; // 1% discount

  return limitOrder(symbol, true, size, buyPrice);
}

Stop-Loss und Take-Profit

// Place a stop loss order
async function stopLoss(
  symbol: string,
  size: number,
  triggerPrice: number
) {
  const order = await sdk.exchange.placeOrder({
    coin: symbol,
    is_buy: false, // Sell to close long
    sz: size,
    limit_px: triggerPrice * 0.99, // Slightly below trigger
    order_type: {
      trigger: {
        triggerPx: triggerPrice.toString(),
        isMarket: true,
        tpsl: "sl",
      },
    },
    reduce_only: true,
  });

  console.log(`Stop loss set at ${triggerPrice}`);
  return order;
}

// Place a take profit order
async function takeProfit(
  symbol: string,
  size: number,
  triggerPrice: number
) {
  const order = await sdk.exchange.placeOrder({
    coin: symbol,
    is_buy: false,
    sz: size,
    limit_px: triggerPrice * 1.01,
    order_type: {
      trigger: {
        triggerPx: triggerPrice.toString(),
        isMarket: true,
        tpsl: "tp",
      },
    },
    reduce_only: true,
  });

  console.log(`Take profit set at ${triggerPrice}`);
  return order;
}

Orders stornieren

// Cancel a specific order
async function cancelOrder(symbol: string, orderId: number) {
  const result = await sdk.exchange.cancelOrder({
    coin: symbol,
    o: orderId,
  });

  console.log(`Cancelled order ${orderId}:`, result);
  return result;
}

// Cancel all orders for a symbol
async function cancelAllOrders(symbol: string) {
  const openOrders = await sdk.info.perpetuals.getOpenOrders({
    user: walletAddress,
  });

  const symbolOrders = openOrders.filter(o => o.coin === symbol);

  for (const order of symbolOrders) {
    await cancelOrder(symbol, order.oid);
  }

  console.log(`Cancelled ${symbolOrders.length} orders for ${symbol}`);
}

// Cancel all orders across all symbols
async function cancelAllOrdersGlobal() {
  const result = await sdk.exchange.cancelAllOrders();
  console.log("Cancelled all orders:", result);
  return result;
}

Einen Grid-Trading-Bot erstellen

// src/strategies/grid.ts
interface GridConfig {
  symbol: string;
  lowerPrice: number;
  upperPrice: number;
  gridCount: number;
  totalSize: number;
}

class GridBot {
  private config: GridConfig;
  private gridPrices: number[] = [];
  private orderSize: number;

  constructor(config: GridConfig) {
    this.config = config;
    this.orderSize = config.totalSize / config.gridCount;
    this.calculateGridPrices();
  }

  private calculateGridPrices() {
    const { lowerPrice, upperPrice, gridCount } = this.config;
    const step = (upperPrice - lowerPrice) / (gridCount - 1);

    for (let i = 0; i < gridCount; i++) {
      this.gridPrices.push(lowerPrice + step * i);
    }

    console.log("Grid prices:", this.gridPrices);
  }

  async placeInitialOrders() {
    const book = await sdk.info.perpetuals.getL2Book({
      coin: this.config.symbol
    });
    const midPrice = (
      parseFloat(book.levels[0][0].px) +
      parseFloat(book.levels[1][0].px)
    ) / 2;

    console.log(`Current price: ${midPrice}`);

    // Place buy orders below current price
    // Place sell orders above current price
    for (const price of this.gridPrices) {
      const isBuy = price < midPrice;

      await sdk.exchange.placeOrder({
        coin: this.config.symbol,
        is_buy: isBuy,
        sz: this.orderSize,
        limit_px: price,
        order_type: { limit: { tif: "Gtc" } },
        reduce_only: false,
      });

      console.log(`Placed ${isBuy ? "buy" : "sell"} @ ${price.toFixed(2)}`);

      // Small delay to avoid rate limits
      await Bun.sleep(100);
    }
  }

  async monitorAndReplace() {
    // Subscribe to fills and replace executed orders
    sdk.subscriptions.subscribeToUserFills((fill) => {
      console.log(`Fill: ${fill.side} ${fill.sz} @ ${fill.px}`);

      // Place opposite order at next grid level
      const fillPrice = parseFloat(fill.px);
      const isBuy = fill.side === "B";

      // Find next grid price
      const gridIndex = this.gridPrices.findIndex(
        p => Math.abs(p - fillPrice) < 1
      );

      if (gridIndex !== -1) {
        const nextIndex = isBuy ? gridIndex + 1 : gridIndex - 1;
        if (nextIndex >= 0 && nextIndex < this.gridPrices.length) {
          const nextPrice = this.gridPrices[nextIndex];

          // Place opposite order
          sdk.exchange.placeOrder({
            coin: this.config.symbol,
            is_buy: !isBuy,
            sz: this.orderSize,
            limit_px: nextPrice,
            order_type: { limit: { tif: "Gtc" } },
            reduce_only: false,
          });

          console.log(`Replaced with ${!isBuy ? "buy" : "sell"} @ ${nextPrice}`);
        }
      }
    });
  }
}

// Usage
const gridBot = new GridBot({
  symbol: "ETH",
  lowerPrice: 2000,
  upperPrice: 2200,
  gridCount: 10,
  totalSize: 1.0, // 1 ETH total
});

await gridBot.placeInitialOrders();
await gridBot.monitorAndReplace();

Risikomanagement

// Position sizing based on account risk
async function calculatePositionSize(
  symbol: string,
  riskPercent: number,
  stopLossPercent: number
): Promise {
  const state = await sdk.info.perpetuals.getClearinghouseState({
    user: walletAddress,
  });

  const accountValue = parseFloat(state.marginSummary.accountValue);
  const riskAmount = accountValue * (riskPercent / 100);

  const book = await sdk.info.perpetuals.getL2Book({ coin: symbol });
  const currentPrice = (
    parseFloat(book.levels[0][0].px) +
    parseFloat(book.levels[1][0].px)
  ) / 2;

  // Position size = Risk Amount / (Stop Loss Distance)
  const stopLossDistance = currentPrice * (stopLossPercent / 100);
  const positionSize = riskAmount / stopLossDistance;

  console.log(`Account: $${accountValue.toFixed(2)}`);
  console.log(`Risk: ${riskPercent}% = $${riskAmount.toFixed(2)}`);
  console.log(`Position size: ${positionSize.toFixed(4)} ${symbol}`);

  return positionSize;
}

// Example: Risk 1% with 2% stop loss
const size = await calculatePositionSize("BTC", 1, 2);

Fehlerbehandlung

// Robust order placement with retries
async function placeOrderWithRetry(
  orderParams: any,
  maxRetries = 3
): Promise {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const result = await sdk.exchange.placeOrder(orderParams);

      if (result.response.type === "error") {
        throw new Error(result.response.data);
      }

      return result;
    } catch (error) {
      console.error(`Attempt ${attempt} failed:`, error.message);

      if (attempt === maxRetries) {
        throw error;
      }

      // Exponential backoff
      await Bun.sleep(1000 * Math.pow(2, attempt));
    }
  }
}

// Graceful shutdown
process.on("SIGINT", async () => {
  console.log("\nShutting down...");

  try {
    await sdk.exchange.cancelAllOrders();
    console.log("Cancelled all orders");
  } catch (error) {
    console.error("Error cancelling orders:", error);
  }

  process.exit(0);
});

Vollständiger Trading-Bot

// src/index.ts
import { initClient, sdk } from "./client";
import "dotenv/config";

const walletAddress = process.env.HYPERLIQUID_WALLET_ADDRESS!;

interface BotConfig {
  symbol: string;
  sizeUsd: number;
  takeProfitPercent: number;
  stopLossPercent: number;
}

async function runBot(config: BotConfig) {
  await initClient();

  console.log(`Starting bot for ${config.symbol}`);
  console.log(`Size: $${config.sizeUsd}`);
  console.log(`TP: ${config.takeProfitPercent}%, SL: ${config.stopLossPercent}%`);

  // Get current price
  const book = await sdk.info.perpetuals.getL2Book({ coin: config.symbol });
  const currentPrice = (
    parseFloat(book.levels[0][0].px) +
    parseFloat(book.levels[1][0].px)
  ) / 2;

  const size = config.sizeUsd / currentPrice;
  const tpPrice = currentPrice * (1 + config.takeProfitPercent / 100);
  const slPrice = currentPrice * (1 - config.stopLossPercent / 100);

  console.log(`Current price: $${currentPrice.toFixed(2)}`);
  console.log(`Size: ${size.toFixed(4)} ${config.symbol}`);
  console.log(`TP: $${tpPrice.toFixed(2)}, SL: $${slPrice.toFixed(2)}`);

  // Place market buy
  await sdk.exchange.placeOrder({
    coin: config.symbol,
    is_buy: true,
    sz: size,
    limit_px: currentPrice * 1.01,
    order_type: { limit: { tif: "Ioc" } },
    reduce_only: false,
  });

  console.log("Opened long position");

  // Place TP and SL
  await sdk.exchange.placeOrder({
    coin: config.symbol,
    is_buy: false,
    sz: size,
    limit_px: tpPrice,
    order_type: {
      trigger: {
        triggerPx: tpPrice.toString(),
        isMarket: true,
        tpsl: "tp",
      },
    },
    reduce_only: true,
  });

  await sdk.exchange.placeOrder({
    coin: config.symbol,
    is_buy: false,
    sz: size,
    limit_px: slPrice,
    order_type: {
      trigger: {
        triggerPx: slPrice.toString(),
        isMarket: true,
        tpsl: "sl",
      },
    },
    reduce_only: true,
  });

  console.log("Set TP and SL orders");

  // Monitor position
  sdk.subscriptions.subscribeToUserFills((fill) => {
    console.log(`Fill: ${fill.side} ${fill.sz} @ ${fill.px}`);

    if (fill.closedPnl) {
      console.log(`Closed PnL: $${fill.closedPnl}`);
      process.exit(0);
    }
  });
}

// Run
runBot({
  symbol: "ETH",
  sizeUsd: 100,
  takeProfitPercent: 2,
  stopLossPercent: 1,
});

Best Practices

  1. Zuerst Testnet verwenden: Testen Sie Strategien immer auf dem Testnet, bevor Sie zum Mainnet wechseln
  2. Klein anfangen: Beginnen Sie mit minimalen Positionsgrößen
  3. Verbindungsabbrüche behandeln: Implementieren Sie Reconnection-Logik für WebSocket
  4. Alles protokollieren: Führen Sie detaillierte Logs für das Debugging
  5. Feste Limits setzen: Implementieren Sie maximale Positionsgrößen und tägliche Verlustlimits
  6. Latenz überwachen: Verfolgen Sie die Orderausführungszeiten

API-Ratenlimits

EndpunktRatenlimit
Info (Lesen)1200/Min
Exchange (Schreiben)600/Min
WebSocket50 Abonnements

Fazit

Das npm-Paket von Hyperliquid kombiniert mit der Geschwindigkeit von Bun macht es ideal für den Bau von Trading-Bots. Beginnen Sie mit einfachen Strategien, implementieren Sie ein ordentliches Risikomanagement und testen Sie immer gründlich auf dem Testnet, bevor Sie Kapital einsetzen. Die Kombination aus Hyperliquids niedriger Latenz und null Gasgebühren eröffnet Möglichkeiten, die auf anderen DEXs nicht realisierbar wären.

Bereit zum Handeln? Treten Sie Hyperliquid mit unserem Empfehlungslink bei und erhalten Sie Gebuhrenrabatte auf Ihre Trades.