{
  "schemaVersion": "1.0",
  "item": {
    "slug": "openbroker",
    "name": "Open-broker",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/ya7ya/openbroker",
    "canonicalUrl": "https://clawhub.ai/ya7ya/openbroker",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/openbroker",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=openbroker",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-30T16:55:25.780Z",
      "expiresAt": "2026-05-07T16:55:25.780Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
        "contentDisposition": "attachment; filename=\"network-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/openbroker"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/openbroker",
    "agentPageUrl": "https://openagent3.xyz/skills/openbroker/agent",
    "manifestUrl": "https://openagent3.xyz/skills/openbroker/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/openbroker/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Open Broker - Hyperliquid Trading CLI",
        "body": "Execute trading operations on Hyperliquid DEX with builder fee support."
      },
      {
        "title": "Installation",
        "body": "npm install -g openbroker"
      },
      {
        "title": "Quick Start",
        "body": "# 1. Setup (generates wallet, creates config, approves builder fee)\nopenbroker setup\n\n# 2. Fund your wallet with USDC on Arbitrum, then deposit at https://app.hyperliquid.xyz/\n\n# 3. Start trading\nopenbroker account\nopenbroker buy --coin ETH --size 0.1"
      },
      {
        "title": "Important: Finding Assets Before Trading",
        "body": "Always search before trading an unfamiliar asset. Hyperliquid has main perps (ETH, BTC, SOL...), HIP-3 perps (xyz:CL, xyz:GOLD, km:USOIL...), and spot markets. Use search to discover the correct ticker:\n\nopenbroker search --query GOLD              # Find all GOLD markets across all providers\nopenbroker search --query oil               # Find oil-related assets (CL, BRENTOIL, USOIL...)\nopenbroker search --query BTC --type perp   # BTC perps only\nopenbroker search --query NATGAS --type hip3  # HIP-3 only\n\nOr with the ob_search plugin tool: { \"query\": \"gold\" } or { \"query\": \"oil\", \"type\": \"hip3\" }\n\nHIP-3 assets use dex:COIN format — e.g., xyz:CL not just CL. If you get an error like \"No market data found\", search for the asset to find the correct prefixed ticker. Common HIP-3 dexes: xyz, flx, km, hyna, vntl, cash."
      },
      {
        "title": "Troubleshooting: CLI Fallback",
        "body": "If an ob_* plugin tool returns unexpected errors, empty results, or crashes, fall back to the equivalent CLI command via Bash. The CLI and plugin tools share the same core code, but the CLI has more mature error handling and output.\n\nPlugin ToolCLI Equivalentob_accountopenbroker account --jsonob_positionsopenbroker positions --jsonob_fundingopenbroker funding --json --include-hip3ob_marketsopenbroker markets --json --include-hip3ob_searchopenbroker search --query <QUERY>ob_buyopenbroker buy --coin <COIN> --size <SIZE>ob_sellopenbroker sell --coin <COIN> --size <SIZE>ob_limitopenbroker limit --coin <COIN> --side <SIDE> --size <SIZE> --price <PRICE>ob_tpslopenbroker tpsl --coin <COIN> --tp <PRICE> --sl <PRICE>ob_cancelopenbroker cancel --all or --coin <COIN>ob_fillsopenbroker fills --jsonob_ordersopenbroker orders --jsonob_funding_scanopenbroker funding-scan --jsonob_candlesopenbroker candles --coin <COIN> --jsonob_auto_runopenbroker auto run <script> [--dry]ob_auto_stop(stop via SIGINT when using CLI)ob_auto_listopenbroker auto list\n\nWhen to use CLI fallback:\n\nPlugin tool returns null, empty data, or throws an error\nYou need data the plugin tool doesn't expose (e.g., --verbose debug output)\nLong-running operations (strategies, TWAP) — the CLI handles timeouts and progress better\n\nAdd --dry to any trading CLI command to preview without executing. Add --json to info commands for structured output."
      },
      {
        "title": "Setup",
        "body": "openbroker setup              # One-command setup (wallet + config + builder approval)\nopenbroker approve-builder --check  # Check builder fee status (for troubleshooting)\n\nThe setup command offers three modes:\n\nGenerate fresh wallet (recommended for agents) — creates a dedicated trading wallet with builder fee auto-approved. No browser steps needed — just fund with USDC and start trading.\nImport existing key — use a private key you already have\nGenerate API wallet — creates a restricted wallet that can trade but cannot withdraw. Requires browser approval from a master wallet.\n\nFor options 1 and 2, setup saves config and approves the builder fee automatically.\nFor option 3 (API wallet), see the API Wallet Setup section below."
      },
      {
        "title": "Fresh Wallet Setup (Recommended for Agents)",
        "body": "The simplest setup for agents. A fresh wallet is generated, the builder fee is auto-approved, and the agent is ready to trade immediately after funding.\n\nFlow:\n\nRun openbroker setup and choose option 1 (\"Generate a fresh wallet\")\nThe CLI generates a wallet, saves the config, and approves the builder fee automatically\nFund the wallet by sending USDC from your Hyperliquid account to the agent's wallet address using the Send feature on https://app.hyperliquid.xyz/. Funding should be done on Hyperliquid L1 only.\nStart trading"
      },
      {
        "title": "API Wallet Setup (Alternative)",
        "body": "API wallets can place trades on behalf of a master account but cannot withdraw funds. Use this if you prefer to keep funds in your existing wallet and only delegate trading access.\n\nFlow:\n\nRun openbroker setup and choose option 3 (\"Generate API wallet\")\nThe CLI generates a keypair and prints an approval URL (e.g. https://openbroker.dev/approve?agent=0xABC...)\nThe agent owner opens the URL in a browser and connects their master wallet (MetaMask etc.)\nThe master wallet signs two transactions: ApproveAgent (authorizes the API wallet) and ApproveBuilderFee (approves the 1 bps fee)\nThe CLI detects the approval automatically and saves the config\n\nAfter setup, the config will contain:\n\nHYPERLIQUID_PRIVATE_KEY=0x...        # API wallet private key\nHYPERLIQUID_ACCOUNT_ADDRESS=0x...    # Master account address\nHYPERLIQUID_NETWORK=mainnet\n\nImportant for agents: When using an API wallet, pass the approval URL to the agent owner (the human who controls the master wallet). The owner must approve in a browser before the agent can trade. The CLI waits up to 10 minutes for the approval. If it times out, re-run openbroker setup."
      },
      {
        "title": "Account Info",
        "body": "openbroker account            # Balance, equity, margin\nopenbroker account --orders   # Include open orders\nopenbroker positions          # Open positions with PnL\nopenbroker positions --coin ETH  # Specific coin"
      },
      {
        "title": "Funding Rates",
        "body": "openbroker funding --top 20   # Top 20 by funding rate\nopenbroker funding --coin ETH # Specific coin"
      },
      {
        "title": "Markets",
        "body": "openbroker markets --top 30   # Top 30 main perps\nopenbroker markets --coin BTC # Specific coin"
      },
      {
        "title": "All Markets (Perps + Spot + HIP-3)",
        "body": "openbroker all-markets                 # Show all markets\nopenbroker all-markets --type perp     # Main perps only\nopenbroker all-markets --type hip3     # HIP-3 perps only\nopenbroker all-markets --type spot     # Spot markets only\nopenbroker all-markets --top 20        # Top 20 by volume"
      },
      {
        "title": "Search Markets (Find assets across providers)",
        "body": "openbroker search --query GOLD    # Find all GOLD markets\nopenbroker search --query BTC     # Find BTC across all providers\nopenbroker search --query ETH --type perp  # ETH perps only"
      },
      {
        "title": "Spot Markets",
        "body": "openbroker spot                   # Show all spot markets\nopenbroker spot --coin PURR       # Show PURR market info\nopenbroker spot --balances        # Show your spot balances\nopenbroker spot --top 20          # Top 20 by volume"
      },
      {
        "title": "Trade Fills",
        "body": "openbroker fills                          # Recent fills\nopenbroker fills --coin ETH               # ETH fills only\nopenbroker fills --coin BTC --side buy --top 50"
      },
      {
        "title": "Order History",
        "body": "openbroker orders                         # Recent orders (all statuses)\nopenbroker orders --open                  # Currently open orders only\nopenbroker orders --open --coin ETH       # Open orders for a specific coin\nopenbroker orders --coin ETH --status filled\nopenbroker orders --top 50"
      },
      {
        "title": "Order Status",
        "body": "openbroker order-status --oid 123456789   # Check specific order\nopenbroker order-status --oid 0x1234...   # By client order ID"
      },
      {
        "title": "Fee Schedule",
        "body": "openbroker fees                           # Fee tier, rates, and volume"
      },
      {
        "title": "Candle Data (OHLCV)",
        "body": "openbroker candles --coin ETH                           # 24 hourly candles\nopenbroker candles --coin BTC --interval 4h --bars 48   # 48 four-hour bars\nopenbroker candles --coin SOL --interval 1d --bars 30   # 30 daily bars"
      },
      {
        "title": "Funding History",
        "body": "openbroker funding-history --coin ETH              # Last 24h\nopenbroker funding-history --coin BTC --hours 168  # Last 7 days"
      },
      {
        "title": "Recent Trades (Tape)",
        "body": "openbroker trades --coin ETH              # Last 30 trades\nopenbroker trades --coin BTC --top 50     # Last 50 trades"
      },
      {
        "title": "Rate Limit",
        "body": "openbroker rate-limit                     # API usage and capacity"
      },
      {
        "title": "Funding Rate Scanner (Cross-Dex)",
        "body": "openbroker funding-scan                          # Scan all dexes, >25% threshold\nopenbroker funding-scan --threshold 50 --pairs   # Show opposing funding pairs\nopenbroker funding-scan --hip3-only --top 20     # HIP-3 only\nopenbroker funding-scan --watch --interval 120   # Re-scan every 2 minutes"
      },
      {
        "title": "HIP-3 Perp Trading",
        "body": "All trading commands support HIP-3 assets using dex:COIN syntax:\n\nopenbroker buy --coin xyz:CL --size 1              # Buy crude oil on xyz dex\nopenbroker sell --coin xyz:BRENTOIL --size 1        # Sell brent oil\nopenbroker limit --coin xyz:GOLD --side buy --size 0.1 --price 2500\nopenbroker funding-arb --coin xyz:CL --size 5000    # Funding arb on HIP-3"
      },
      {
        "title": "Market Orders (Quick)",
        "body": "openbroker buy --coin ETH --size 0.1\nopenbroker sell --coin BTC --size 0.01\nopenbroker buy --coin SOL --size 5 --slippage 100  # Custom slippage (bps)"
      },
      {
        "title": "Market Orders (Full)",
        "body": "openbroker market --coin ETH --side buy --size 0.1\nopenbroker market --coin BTC --side sell --size 0.01 --slippage 100"
      },
      {
        "title": "Limit Orders",
        "body": "openbroker limit --coin ETH --side buy --size 1 --price 3000\nopenbroker limit --coin SOL --side sell --size 10 --price 200 --tif ALO"
      },
      {
        "title": "Set TP/SL on Existing Position",
        "body": "# Set take profit at $40, stop loss at $30\nopenbroker tpsl --coin HYPE --tp 40 --sl 30\n\n# Set TP at +10% from entry, SL at entry (breakeven)\nopenbroker tpsl --coin HYPE --tp +10% --sl entry\n\n# Set only stop loss at -5% from entry\nopenbroker tpsl --coin ETH --sl -5%\n\n# Partial position TP/SL\nopenbroker tpsl --coin ETH --tp 4000 --sl 3500 --size 0.5"
      },
      {
        "title": "Trigger Orders (Standalone TP/SL)",
        "body": "# Take profit: sell when price rises to $40\nopenbroker trigger --coin HYPE --side sell --size 0.5 --trigger 40 --type tp\n\n# Stop loss: sell when price drops to $30\nopenbroker trigger --coin HYPE --side sell --size 0.5 --trigger 30 --type sl"
      },
      {
        "title": "Cancel Orders",
        "body": "openbroker cancel --all           # Cancel all orders\nopenbroker cancel --coin ETH      # Cancel ETH orders only\nopenbroker cancel --oid 123456    # Cancel specific order"
      },
      {
        "title": "TWAP (Time-Weighted Average Price)",
        "body": "# Execute 1 ETH buy over 1 hour (auto-calculates slices)\nopenbroker twap --coin ETH --side buy --size 1 --duration 3600\n\n# Custom intervals with randomization\nopenbroker twap --coin BTC --side sell --size 0.5 --duration 1800 --intervals 6 --randomize 20"
      },
      {
        "title": "Scale In/Out (Grid Orders)",
        "body": "# Place 5 buy orders ranging 2% below current price\nopenbroker scale --coin ETH --side buy --size 1 --levels 5 --range 2\n\n# Scale out with exponential distribution\nopenbroker scale --coin BTC --side sell --size 0.5 --levels 4 --range 3 --distribution exponential --reduce"
      },
      {
        "title": "Bracket Order (Entry + TP + SL)",
        "body": "# Long ETH with 3% take profit and 1.5% stop loss\nopenbroker bracket --coin ETH --side buy --size 0.5 --tp 3 --sl 1.5\n\n# Short with limit entry\nopenbroker bracket --coin BTC --side sell --size 0.1 --entry limit --price 100000 --tp 5 --sl 2"
      },
      {
        "title": "Chase Order (Follow Price)",
        "body": "# Chase buy with ALO orders until filled\nopenbroker chase --coin ETH --side buy --size 0.5 --timeout 300\n\n# Aggressive chase with tight offset\nopenbroker chase --coin SOL --side buy --size 10 --offset 2 --timeout 60"
      },
      {
        "title": "Funding Arbitrage",
        "body": "# Collect funding on ETH if rate > 25% annualized\nopenbroker funding-arb --coin ETH --size 5000 --min-funding 25\n\n# Run for 24 hours, check every 30 minutes\nopenbroker funding-arb --coin BTC --size 10000 --duration 24 --check 30 --dry"
      },
      {
        "title": "Grid Trading",
        "body": "# ETH grid from $3000-$4000 with 10 levels, 0.1 ETH per level\nopenbroker grid --coin ETH --lower 3000 --upper 4000 --grids 10 --size 0.1\n\n# Accumulation grid (buys only)\nopenbroker grid --coin BTC --lower 90000 --upper 100000 --grids 5 --size 0.01 --mode long"
      },
      {
        "title": "DCA (Dollar Cost Averaging)",
        "body": "# Buy $100 of ETH every hour for 24 hours\nopenbroker dca --coin ETH --amount 100 --interval 1h --count 24\n\n# Invest $5000 in BTC over 30 days with daily purchases\nopenbroker dca --coin BTC --total 5000 --interval 1d --count 30"
      },
      {
        "title": "Market Making Spread",
        "body": "# Market make ETH with 0.1 size, 10bps spread\nopenbroker mm-spread --coin ETH --size 0.1 --spread 10\n\n# Tighter spread with position limit\nopenbroker mm-spread --coin BTC --size 0.01 --spread 5 --max-position 0.1"
      },
      {
        "title": "Maker-Only MM (ALO orders)",
        "body": "# Market make using ALO (post-only) orders - guarantees maker rebates\nopenbroker mm-maker --coin HYPE --size 1 --offset 1\n\n# Wider offset for volatile assets\nopenbroker mm-maker --coin ETH --size 0.1 --offset 2 --max-position 0.5"
      },
      {
        "title": "Limit Orders vs Trigger Orders",
        "body": "Limit Orders (openbroker limit):\n\nExecute immediately if price is met\nRest on the order book until filled or cancelled\nA limit sell BELOW current price fills immediately (taker)\nNOT suitable for stop losses\n\nTrigger Orders (openbroker trigger, openbroker tpsl):\n\nStay dormant until trigger price is reached\nOnly activate when price hits the trigger level\nProper way to set stop losses and take profits\nWon't fill prematurely"
      },
      {
        "title": "When to Use Each",
        "body": "ScenarioCommandBuy at specific price below marketopenbroker limitSell at specific price above marketopenbroker limitStop loss (exit if price drops)openbroker trigger --type slTake profit (exit at target)openbroker trigger --type tpAdd TP/SL to existing positionopenbroker tpsl"
      },
      {
        "title": "Common Arguments",
        "body": "All commands support --dry for dry run (preview without executing).\n\nArgumentDescription--coinAsset symbol (ETH, BTC, SOL, HYPE, etc.)--sideOrder direction: buy or sell--sizeOrder size in base asset--priceLimit price--dryPreview without executing--helpShow command help"
      },
      {
        "title": "Order Arguments",
        "body": "ArgumentDescription--triggerTrigger price (for trigger orders)--typeTrigger type: tp or sl--slippageSlippage tolerance in bps (for market orders)--tifTime in force: GTC, IOC, ALO--reduceReduce-only order"
      },
      {
        "title": "TP/SL Price Formats",
        "body": "FormatExampleDescriptionAbsolute--tp 40Price of $40Percentage up--tp +10%10% above entryPercentage down--sl -5%5% below entryEntry price--sl entryBreakeven stop"
      },
      {
        "title": "Configuration",
        "body": "Config is loaded from (in priority order):\n\nEnvironment variables\n.env in current directory\n~/.openbroker/.env (global config)\n\nRun openbroker setup to create the global config interactively.\n\nVariableRequiredDescriptionHYPERLIQUID_PRIVATE_KEYYesWallet private key (0x...)HYPERLIQUID_NETWORKNomainnet (default) or testnetHYPERLIQUID_ACCOUNT_ADDRESSNoMaster account address (required for API wallets)\n\nThe builder fee (1 bps / 0.01%) is hardcoded and not configurable."
      },
      {
        "title": "OpenClaw Plugin (Optional)",
        "body": "This skill works standalone via Bash — every command above runs through the openbroker CLI. For enhanced features, the same openbroker npm package also ships as an OpenClaw plugin that you can enable alongside this skill."
      },
      {
        "title": "What the plugin adds",
        "body": "Structured agent tools (ob_account, ob_buy, ob_limit, etc.) — typed tool calls with proper input schemas instead of Bash strings. The agent gets structured JSON responses.\nBackground position watcher — polls your Hyperliquid account every 30s and sends webhook alerts when positions open/close, PnL moves significantly, or margin usage gets dangerous.\nAutomation tools (ob_auto_run, ob_auto_stop, ob_auto_list) — start, stop, and manage custom trading automations from within the agent.\nCLI commands — openclaw ob status and openclaw ob watch for inspecting the watcher."
      },
      {
        "title": "Enable the plugin",
        "body": "The plugin is bundled in the same openbroker npm package. To enable it in your OpenClaw config:\n\nplugins:\n  entries:\n    openbroker:\n      enabled: true\n      config:\n        hooksToken: \"your-hooks-secret\"   # Required for watcher alerts\n        watcher:\n          enabled: true\n          pollIntervalMs: 30000\n          pnlChangeThresholdPct: 5\n          marginUsageWarningPct: 80\n\nThe plugin reads wallet credentials from ~/.openbroker/.env (set up by openbroker setup), so you don't need to duplicate privateKey in the plugin config unless you want to override."
      },
      {
        "title": "Webhook setup for watcher alerts",
        "body": "For position alerts to reach the agent, enable hooks in your gateway config:\n\nhooks:\n  enabled: true\n  token: \"your-hooks-secret\"   # Must match hooksToken above\n\nWithout hooks, the watcher still runs and tracks state (accessible via ob_watcher_status), but it can't wake the agent."
      },
      {
        "title": "Using with or without the plugin",
        "body": "Skill only (no plugin): Use Bash commands (openbroker buy --coin ETH --size 0.1). No background monitoring.\nSkill + plugin: The agent prefers the ob_* tools when available (structured data), falls back to Bash for commands not covered by tools (strategies, scale). Background watcher sends alerts automatically."
      },
      {
        "title": "Trading Automations",
        "body": "Automations let you write custom event-driven trading logic as TypeScript scripts. Instead of using the rigid built-in strategies, write exactly the logic you need and OpenBroker handles the polling, event detection, and SDK access."
      },
      {
        "title": "How Automations Work",
        "body": "An automation is a .ts file that exports a default function. The function receives an AutomationAPI with the full Hyperliquid client, typed event subscriptions, persistent state, and a logger. The runtime polls Hyperliquid every 10s (configurable) and dispatches events when changes are detected."
      },
      {
        "title": "Writing an Automation",
        "body": "Create a .ts file in ~/.openbroker/automations/ (or any path):\n\n// ~/.openbroker/automations/funding-scalp.ts\nexport default function(api) {\n  const COIN = 'ETH';\n\n  api.on('funding_update', async ({ coin, annualized }) => {\n    if (coin !== COIN) return;\n\n    if (annualized > 0.5 && !api.state.get('isShort')) {\n      api.log.info('High positive funding — going short');\n      await api.client.marketOrder(COIN, false, 0.1);\n      api.state.set('isShort', true);\n    } else if (annualized < -0.1 && api.state.get('isShort')) {\n      api.log.info('Funding normalized — closing short');\n      await api.client.marketOrder(COIN, true, 0.1);\n      api.state.set('isShort', false);\n    }\n  });\n\n  api.onStop(async () => {\n    if (api.state.get('isShort')) {\n      api.log.warn('Closing short on shutdown');\n      await api.client.marketOrder('ETH', true, 0.1);\n      api.state.set('isShort', false);\n    }\n  });\n}"
      },
      {
        "title": "AutomationAPI Reference",
        "body": "Property / MethodDescriptionapi.clientFull HyperliquidClient — marketOrder(), limitOrder(), triggerOrder(), cancelAll(), getUserStateAll(), getAllMids(), updateLeverage(), and 35+ more methodsapi.on(event, handler)Subscribe to a market/account event (see Events below)api.every(ms, handler)Run a handler on a recurring interval (aligned to poll loop)api.onStart(handler)Called after all handlers are registered, before first pollapi.onStop(handler)Called on shutdown (SIGINT). Use for cleanup — close positions, cancel ordersapi.onError(handler)Called when a handler throws. Error is already logged — use for recovery logicapi.state.get(key)Get a persisted value (survives restarts, stored in ~/.openbroker/state/)api.state.set(key, value)Set a persisted valueapi.state.delete(key)Delete a persisted valueapi.state.clear()Clear all stateapi.publish(message, options?)Send a message to the OpenClaw agent via webhook. Triggers an agent turn — the agent receives the message and can notify the user, take action, etc. Returns true if delivered. Options: { name?, wakeMode?, deliver?, channel? }api.log.info/warn/error/debug(msg)Structured loggerapi.utilsroundPrice, roundSize, sleep, normalizeCoin, formatUsd, annualizeFundingRateapi.idAutomation ID (filename or --id flag)api.dryRuntrue if running with --dry (write methods are intercepted)"
      },
      {
        "title": "Events",
        "body": "EventPayloadWhentick{ timestamp, pollCount }Every poll cycle (default: 10s)price_change{ coin, oldPrice, newPrice, changePct }Mid price moved > 0.01% between pollsfunding_update{ coin, fundingRate, annualized, premium }Every poll for all assetsposition_opened{ coin, side, size, entryPrice }New position detectedposition_closed{ coin, previousSize, entryPrice }Position no longer presentposition_changed{ coin, oldSize, newSize, entryPrice }Position size changedpnl_threshold{ coin, unrealizedPnl, changePct, positionValue }PnL moved > 5% of position valuemargin_warning{ marginUsedPct, equity, marginUsed }Margin usage > 80%"
      },
      {
        "title": "Event Details — Choosing the Right Event",
        "body": "tick — The universal heartbeat\n\nFires every single poll cycle (default: 10s) regardless of market conditions. Use this when you need to check something on every poll — absolute price thresholds, custom conditions, periodic account checks. This is the most reliable event because it always fires.\n\nPayload: { timestamp: number, pollCount: number }\n\nWhen to use:\n\nChecking if a price is above/below an absolute threshold (e.g. \"alert me when ETH < $3000\")\nCustom conditions that don't fit other events (e.g. \"if I have no positions and funding is high, enter\")\nPeriodic tasks that need to run every poll (though api.every() is better for longer intervals)\n\nExample — absolute price alert:\n\napi.on('tick', async () => {\n  const mids = await api.client.getAllMids();\n  const price = parseFloat(mids['HYPE']);\n  if (price < 38 && !api.state.get('alerted')) {\n    api.state.set('alerted', true);\n    await api.publish(`HYPE dropped below $38 — now at $${price.toFixed(3)}`);\n  }\n});\n\nNote: tick does not include price data in its payload — you must fetch it yourself via api.client.getAllMids(). This is because tick fires before any other event processing. If you only care about price movements, use price_change instead.\n\nprice_change — Relative price movements\n\nFires when a coin's mid price moves ≥ 0.01% compared to the previous poll. This filters out rounding noise while catching virtually any real price movement. The comparison is between consecutive polls (not from a fixed baseline), so it detects incremental changes.\n\nPayload: { coin: string, oldPrice: number, newPrice: number, changePct: number }\n\nWhen to use:\n\nReacting to price movements (breakouts, momentum, mean reversion)\nMonitoring specific coins for volatility\nBuilding price-triggered entry/exit logic\n\nWhen NOT to use:\n\nChecking if price is above/below a fixed threshold — use tick instead, because price_change only fires on relative movement between polls. During slow drifts (e.g. price slowly declining $0.001/s), the change between any two 10s polls may be < 0.01%, so the event won't fire even though the price has crossed your threshold.\n\nExample — momentum detector:\n\napi.on('price_change', async ({ coin, changePct, newPrice }) => {\n  if (coin !== 'ETH') return;\n  if (changePct > 0.5) {\n    api.log.info(`ETH surging +${changePct.toFixed(2)}% — price $${newPrice}`);\n    // Enter long on strong upward momentum\n  }\n});\n\nfunding_update — Funding rate data\n\nFires every poll for every asset that has funding rate data. This is high-frequency — if there are 150 perp assets, this fires 150 times per poll. Filter by coin in your handler.\n\nPayload: { coin: string, fundingRate: number, annualized: number, premium: number }\n\nfundingRate — the raw hourly funding rate (e.g. 0.0001 = 0.01%/hr)\nannualized — annualized rate (fundingRate × 8760 × 100, as a percentage)\npremium — the premium component\n\nWhen to use:\n\nFunding rate arbitrage strategies\nMonitoring for extreme funding (entry/exit signals)\nScanning for highest/lowest funding across all assets\n\nExample — funding scalp:\n\napi.on('funding_update', async ({ coin, annualized }) => {\n  if (coin !== 'ETH') return;\n  if (annualized > 50 && !api.state.get('isShort')) {\n    api.log.info(`ETH funding at ${annualized.toFixed(1)}% annualized — shorting`);\n    await api.client.marketOrder('ETH', false, 0.1);\n    api.state.set('isShort', true);\n  }\n});\n\nposition_opened — New position detected\n\nFires when a position appears that wasn't present in the previous poll. Useful for tracking entries made by other systems or confirming your own orders filled.\n\nPayload: { coin: string, side: 'long' | 'short', size: number, entryPrice: number }\n\nWhen to use:\n\nSetting TP/SL on new positions automatically\nLogging/alerting when positions are opened (by you or another system)\nStarting position-specific monitoring\n\nExample — auto TP/SL on new positions:\n\napi.on('position_opened', async ({ coin, side, size, entryPrice }) => {\n  const tpPrice = side === 'long' ? entryPrice * 1.05 : entryPrice * 0.95;\n  const slPrice = side === 'long' ? entryPrice * 0.97 : entryPrice * 1.03;\n  await api.client.takeProfit(coin, side !== 'long', size, tpPrice);\n  await api.client.stopLoss(coin, side !== 'long', size, slPrice);\n  api.log.info(`Set TP at ${tpPrice} / SL at ${slPrice} for ${coin}`);\n});\n\nposition_closed — Position gone\n\nFires when a position that existed in the previous poll is no longer present. The position was either closed by you, liquidated, or filled by TP/SL.\n\nPayload: { coin: string, previousSize: number, entryPrice: number }\n\nWhen to use:\n\nLogging/alerting when positions close\nCleaning up related orders or state\nRe-entry logic after a position closes\n\nExample:\n\napi.on('position_closed', async ({ coin, previousSize, entryPrice }) => {\n  api.log.info(`${coin} position closed (was ${previousSize} @ ${entryPrice})`);\n  api.state.delete(`${coin}_tp`);\n  await api.publish(`Position closed: ${coin} (entry: $${entryPrice})`);\n});\n\nposition_changed — Size or direction changed\n\nFires when an existing position's size changes (partial close, add to position, or flip direction). Does NOT fire when a new position opens or an existing one fully closes — use position_opened and position_closed for those.\n\nPayload: { coin: string, oldSize: number, newSize: number, entryPrice: number }\n\noldSize/newSize are signed: positive = long, negative = short\n\nWhen to use:\n\nDetecting partial closes or position scaling\nAdjusting TP/SL when position size changes\nTracking DCA entries\n\nExample:\n\napi.on('position_changed', async ({ coin, oldSize, newSize }) => {\n  if (Math.abs(newSize) > Math.abs(oldSize)) {\n    api.log.info(`${coin} position increased: ${oldSize} → ${newSize}`);\n  } else {\n    api.log.info(`${coin} position reduced: ${oldSize} → ${newSize}`);\n  }\n});\n\npnl_threshold — Significant PnL movement\n\nFires when unrealized PnL changes by ≥ 5% of position value between consecutive polls. This is a large move detector — useful for risk management alerts rather than routine monitoring.\n\nPayload: { coin: string, unrealizedPnl: number, changePct: number, positionValue: number }\n\nchangePct — the PnL change as a percentage of total position value (not % of PnL itself)\n\nWhen to use:\n\nRisk alerts for large PnL swings\nAuto-close or reduce positions on sudden adverse moves\nEscalating alerts to the user via api.publish()\n\nExample:\n\napi.on('pnl_threshold', async ({ coin, unrealizedPnl, changePct }) => {\n  if (unrealizedPnl < 0) {\n    await api.publish(\n      `⚠️ ${coin} PnL dropped sharply: $${unrealizedPnl.toFixed(2)} (${changePct.toFixed(1)}% of position)`,\n      { name: 'pnl-alert' },\n    );\n  }\n});\n\nmargin_warning — High margin usage\n\nFires when margin usage exceeds 80% of equity. After the first trigger, it only fires again if margin usage increases by another 5 percentage points (prevents spam). Resets when margin drops back below 80%.\n\nPayload: { marginUsedPct: number, equity: number, marginUsed: number }\n\nWhen to use:\n\nAutomated risk reduction (close smallest position to free margin)\nAlerting the user before liquidation risk\nPausing new entries when margin is high\n\nExample:\n\napi.on('margin_warning', async ({ marginUsedPct, equity }) => {\n  await api.publish(\n    `🚨 Margin at ${marginUsedPct.toFixed(1)}% — equity: $${equity.toFixed(2)}. Consider reducing exposure.`,\n    { name: 'margin-alert' },\n  );\n});"
      },
      {
        "title": "Choosing the Right Event — Quick Guide",
        "body": "Use caseBest eventWhyAlert when price crosses a fixed leveltickFires every poll — no minimum change thresholdReact to price momentum/volatilityprice_changeProvides relative change data between pollsFunding rate strategyfunding_updateGives annualized rate directlyAuto TP/SL on new positionsposition_openedFires exactly when a new position appearsLog when positions closeposition_closedFires when position disappearsTrack position scalingposition_changedFires on size changes onlyRisk management — PnL spikespnl_thresholdOnly fires on large moves (≥5% of position value)Risk management — marginmargin_warningFires at 80%+ margin usagePeriodic task (DCA, rebalance)api.every(ms, fn)Better than tick for longer intervals"
      },
      {
        "title": "Client Methods Available",
        "body": "The api.client object exposes the full Hyperliquid SDK:\n\nTrading: marketOrder(coin, isBuy, size), limitOrder(coin, isBuy, size, price), triggerOrder(coin, isBuy, size, triggerPx, isMarket), takeProfit(coin, isBuy, size, triggerPx), stopLoss(coin, isBuy, size, triggerPx), cancel(coin, oid), cancelAll(coin?)\n\nMarket Data: getAllMids(), getMetaAndAssetCtxs(), getRecentTrades(coin), getCandleSnapshot(coin, interval), getFundingHistory(coin), getPredictedFundings()\n\nAccount: getUserStateAll(), getOpenOrders(), getUserFills(), getUserFunding(), getHistoricalOrders(), getUserFees(), getUserRateLimit(), getSpotBalances()\n\nLeverage: updateLeverage(coin, leverage, isIsolated?)"
      },
      {
        "title": "Example: Price Breakout",
        "body": "// ~/.openbroker/automations/breakout.ts\nexport default function(api) {\n  const COIN = 'ETH';\n  const BREAKOUT_PCT = 2;  // 2% move triggers entry\n  const SIZE = 0.5;\n  let basePrice = null;\n\n  api.onStart(async () => {\n    const mids = await api.client.getAllMids();\n    basePrice = parseFloat(mids[COIN]);\n    api.log.info(`Watching ${COIN} from $${basePrice} for ${BREAKOUT_PCT}% breakout`);\n  });\n\n  api.on('price_change', async ({ coin, newPrice }) => {\n    if (coin !== COIN || !basePrice) return;\n    const totalChange = ((newPrice - basePrice) / basePrice) * 100;\n\n    if (Math.abs(totalChange) >= BREAKOUT_PCT && !api.state.get('inPosition')) {\n      const side = totalChange > 0;  // true = long, false = short\n      api.log.info(`Breakout! ${totalChange.toFixed(2)}% — entering ${side ? 'long' : 'short'}`);\n      await api.client.marketOrder(COIN, side, SIZE);\n      api.state.set('inPosition', true);\n    }\n  });\n}"
      },
      {
        "title": "Example: Scheduled DCA",
        "body": "// ~/.openbroker/automations/hourly-dca.ts\nexport default function(api) {\n  const COIN = 'ETH';\n  const USD_PER_BUY = 100;\n\n  // Buy $100 of ETH every hour\n  api.every(60 * 60 * 1000, async () => {\n    const mids = await api.client.getAllMids();\n    const price = parseFloat(mids[COIN]);\n    const size = parseFloat(api.utils.roundSize(USD_PER_BUY / price, 4));\n    await api.client.marketOrder(COIN, true, size);\n    const count = (api.state.get('buyCount') || 0) + 1;\n    api.state.set('buyCount', count);\n    api.log.info(`DCA #${count}: bought ${size} ${COIN} at $${price}`);\n  });\n}"
      },
      {
        "title": "Example: Margin Guardian",
        "body": "// ~/.openbroker/automations/margin-guard.ts\nexport default function(api) {\n  api.on('margin_warning', async ({ marginUsedPct, equity }) => {\n    api.log.warn(`Margin at ${marginUsedPct.toFixed(1)}% — reducing positions`);\n\n    // Close the smallest position to free margin\n    const state = await api.client.getUserStateAll();\n    const positions = state.assetPositions\n      .filter(p => parseFloat(p.position.szi) !== 0)\n      .sort((a, b) => Math.abs(parseFloat(a.position.positionValue)) - Math.abs(parseFloat(b.position.positionValue)));\n\n    if (positions.length > 0) {\n      const pos = positions[0].position;\n      const size = Math.abs(parseFloat(pos.szi));\n      const isBuy = parseFloat(pos.szi) < 0; // Close short = buy, close long = sell\n      api.log.info(`Closing smallest position: ${pos.coin} (${pos.szi})`);\n      await api.client.marketOrder(pos.coin, isBuy, size);\n    }\n  });\n}"
      },
      {
        "title": "Publishing to the Agent (Webhooks)",
        "body": "Use api.publish() to send messages back to the OpenClaw agent. This triggers an agent turn — the agent receives the message and can notify the user via their preferred channel, take trading actions, or log the event.\n\n// Simple notification\nawait api.publish(`ETH broke above $4000 — current price: $${price}`);\n\n// With options\nawait api.publish(`Margin at ${pct}% — positions at risk`, {\n  name: 'margin-alert',           // appears in logs\n  wakeMode: 'now',                // 'now' (default) or 'next-heartbeat'\n  channel: 'slack',               // target channel (optional)\n});\n\napi.publish() returns true if delivered, false if webhooks are not configured (no hooks token). It requires OPENCLAW_HOOKS_TOKEN to be set (automatically configured when running as an OpenClaw plugin).\n\nExample: Price alert automation with publish\n\n// ~/.openbroker/automations/price-alert.ts\nexport default function(api) {\n  const COIN = 'ETH';\n  const THRESHOLD = 4000;\n\n  api.on('price_change', async ({ coin, newPrice, changePct }) => {\n    if (coin !== COIN) return;\n\n    const crossed = api.state.get<boolean>('crossed', false);\n    if (!crossed && newPrice >= THRESHOLD) {\n      api.state.set('crossed', true);\n      await api.publish(\n        `${COIN} crossed above $${THRESHOLD}! Price: $${newPrice.toFixed(2)} (+${changePct.toFixed(2)}%)`,\n      );\n    } else if (crossed && newPrice < THRESHOLD) {\n      api.state.set('crossed', false);\n    }\n  });\n}"
      },
      {
        "title": "Running Automations",
        "body": "CLI:\n\nopenbroker auto run my-strategy --dry       # Test without trading\nopenbroker auto run ./funding-scalp.ts      # Run from path\nopenbroker auto run my-strategy --poll 5000 # Poll every 5s\nopenbroker auto list                        # Show available scripts\nopenbroker auto status                      # Show running automations\n\nPlugin tools (for OpenClaw agents):\n\nob_auto_run — { \"script\": \"funding-scalp\", \"dry\": true } — start an automation\nob_auto_stop — { \"id\": \"funding-scalp\" } — stop a running automation\nob_auto_list — {} — list available and running automations\n\nOptions:\n\nFlagDescriptionDefault--dryIntercept write methods — no real tradesfalse--verboseShow debug outputfalse--id <name>Custom automation IDfilename--poll <ms>Poll interval in milliseconds10000\n\nGuidelines for agents writing automations:\n\nRisk & Safety (mandatory):\n\nAlways attach a liquidation monitoring automation to every open position. Subscribe to margin_warning and pnl_threshold events so the user is never blindsided by liquidation risk. If no margin/liquidation automation is already running, create one before placing trades.\nUse api.publish() to notify the user of important events — position opens/closes, TP/SL triggers, large PnL swings, margin warnings, errors, and any situation that requires human attention. Do NOT silently handle critical events.\nAlways register an api.onStop() handler to clean up — cancel open orders and close positions (or at minimum alert the user) on shutdown. Never leave orphaned orders or unmanaged positions.\nDo NOT use --dry unless the user explicitly asks for it. Automations should run live by default.\nNever place trades without validating that sufficient margin is available. Check account state before sizing orders.\nCap position sizes relative to account equity. Do not risk more than a reasonable percentage of equity on a single trade unless the user explicitly specifies the size.\nAlways set TP/SL on new positions — either within the automation or by confirming the user has them set. Unprotected positions are a liability.\n\nState & Reliability:\n\nUse api.state to track position state, entry prices, and flags across restarts. Never rely on in-memory variables alone — automations persist across gateway restarts and are automatically restarted.\nUse idempotency guards (api.state.get/set) to prevent duplicate orders. Events can fire multiple times for the same condition across polls — always check state before placing orders.\nThe runtime catches errors per handler — one failing handler won't crash others, but always handle expected errors (e.g. order rejection, insufficient margin) gracefully within handlers.\n\nCommunication:\n\nUse api.publish() to send alerts/events back to the OpenClaw agent — do NOT manually construct webhook requests.\nPublish on: position opened/closed, TP/SL triggered, PnL threshold exceeded, margin warning, automation errors, and any automated trade execution. The user should always know what the automation did and why.\nInclude actionable context in publish messages — coin, price, size, PnL, and what happened — so the user can make informed decisions without checking the terminal.\n\nGeneral:\n\nScripts are loaded from ~/.openbroker/automations/ by name, or from any absolute path.\nAll trading commands support HIP-3 assets (api.client.marketOrder('xyz:CL', true, 1)).\nAutomations persist across gateway restarts — they are automatically restarted when the gateway comes back up.\nPrefer api.every(ms, fn) over tick for periodic tasks with intervals longer than the poll cycle."
      },
      {
        "title": "Risk Warning",
        "body": "Always use --dry first to preview orders\nStart with small sizes on testnet (HYPERLIQUID_NETWORK=testnet)\nMonitor positions and liquidation prices\nUse --reduce for closing positions only"
      }
    ],
    "body": "Open Broker - Hyperliquid Trading CLI\n\nExecute trading operations on Hyperliquid DEX with builder fee support.\n\nInstallation\nnpm install -g openbroker\n\nQuick Start\n# 1. Setup (generates wallet, creates config, approves builder fee)\nopenbroker setup\n\n# 2. Fund your wallet with USDC on Arbitrum, then deposit at https://app.hyperliquid.xyz/\n\n# 3. Start trading\nopenbroker account\nopenbroker buy --coin ETH --size 0.1\n\nImportant: Finding Assets Before Trading\n\nAlways search before trading an unfamiliar asset. Hyperliquid has main perps (ETH, BTC, SOL...), HIP-3 perps (xyz:CL, xyz:GOLD, km:USOIL...), and spot markets. Use search to discover the correct ticker:\n\nopenbroker search --query GOLD              # Find all GOLD markets across all providers\nopenbroker search --query oil               # Find oil-related assets (CL, BRENTOIL, USOIL...)\nopenbroker search --query BTC --type perp   # BTC perps only\nopenbroker search --query NATGAS --type hip3  # HIP-3 only\n\n\nOr with the ob_search plugin tool: { \"query\": \"gold\" } or { \"query\": \"oil\", \"type\": \"hip3\" }\n\nHIP-3 assets use dex:COIN format — e.g., xyz:CL not just CL. If you get an error like \"No market data found\", search for the asset to find the correct prefixed ticker. Common HIP-3 dexes: xyz, flx, km, hyna, vntl, cash.\n\nTroubleshooting: CLI Fallback\n\nIf an ob_* plugin tool returns unexpected errors, empty results, or crashes, fall back to the equivalent CLI command via Bash. The CLI and plugin tools share the same core code, but the CLI has more mature error handling and output.\n\nPlugin Tool\tCLI Equivalent\nob_account\topenbroker account --json\nob_positions\topenbroker positions --json\nob_funding\topenbroker funding --json --include-hip3\nob_markets\topenbroker markets --json --include-hip3\nob_search\topenbroker search --query <QUERY>\nob_buy\topenbroker buy --coin <COIN> --size <SIZE>\nob_sell\topenbroker sell --coin <COIN> --size <SIZE>\nob_limit\topenbroker limit --coin <COIN> --side <SIDE> --size <SIZE> --price <PRICE>\nob_tpsl\topenbroker tpsl --coin <COIN> --tp <PRICE> --sl <PRICE>\nob_cancel\topenbroker cancel --all or --coin <COIN>\nob_fills\topenbroker fills --json\nob_orders\topenbroker orders --json\nob_funding_scan\topenbroker funding-scan --json\nob_candles\topenbroker candles --coin <COIN> --json\nob_auto_run\topenbroker auto run <script> [--dry]\nob_auto_stop\t(stop via SIGINT when using CLI)\nob_auto_list\topenbroker auto list\n\nWhen to use CLI fallback:\n\nPlugin tool returns null, empty data, or throws an error\nYou need data the plugin tool doesn't expose (e.g., --verbose debug output)\nLong-running operations (strategies, TWAP) — the CLI handles timeouts and progress better\n\nAdd --dry to any trading CLI command to preview without executing. Add --json to info commands for structured output.\n\nCommand Reference\nSetup\nopenbroker setup              # One-command setup (wallet + config + builder approval)\nopenbroker approve-builder --check  # Check builder fee status (for troubleshooting)\n\n\nThe setup command offers three modes:\n\nGenerate fresh wallet (recommended for agents) — creates a dedicated trading wallet with builder fee auto-approved. No browser steps needed — just fund with USDC and start trading.\nImport existing key — use a private key you already have\nGenerate API wallet — creates a restricted wallet that can trade but cannot withdraw. Requires browser approval from a master wallet.\n\nFor options 1 and 2, setup saves config and approves the builder fee automatically. For option 3 (API wallet), see the API Wallet Setup section below.\n\nFresh Wallet Setup (Recommended for Agents)\n\nThe simplest setup for agents. A fresh wallet is generated, the builder fee is auto-approved, and the agent is ready to trade immediately after funding.\n\nFlow:\n\nRun openbroker setup and choose option 1 (\"Generate a fresh wallet\")\nThe CLI generates a wallet, saves the config, and approves the builder fee automatically\nFund the wallet by sending USDC from your Hyperliquid account to the agent's wallet address using the Send feature on https://app.hyperliquid.xyz/. Funding should be done on Hyperliquid L1 only.\nStart trading\nAPI Wallet Setup (Alternative)\n\nAPI wallets can place trades on behalf of a master account but cannot withdraw funds. Use this if you prefer to keep funds in your existing wallet and only delegate trading access.\n\nFlow:\n\nRun openbroker setup and choose option 3 (\"Generate API wallet\")\nThe CLI generates a keypair and prints an approval URL (e.g. https://openbroker.dev/approve?agent=0xABC...)\nThe agent owner opens the URL in a browser and connects their master wallet (MetaMask etc.)\nThe master wallet signs two transactions: ApproveAgent (authorizes the API wallet) and ApproveBuilderFee (approves the 1 bps fee)\nThe CLI detects the approval automatically and saves the config\n\nAfter setup, the config will contain:\n\nHYPERLIQUID_PRIVATE_KEY=0x...        # API wallet private key\nHYPERLIQUID_ACCOUNT_ADDRESS=0x...    # Master account address\nHYPERLIQUID_NETWORK=mainnet\n\n\nImportant for agents: When using an API wallet, pass the approval URL to the agent owner (the human who controls the master wallet). The owner must approve in a browser before the agent can trade. The CLI waits up to 10 minutes for the approval. If it times out, re-run openbroker setup.\n\nAccount Info\nopenbroker account            # Balance, equity, margin\nopenbroker account --orders   # Include open orders\nopenbroker positions          # Open positions with PnL\nopenbroker positions --coin ETH  # Specific coin\n\nFunding Rates\nopenbroker funding --top 20   # Top 20 by funding rate\nopenbroker funding --coin ETH # Specific coin\n\nMarkets\nopenbroker markets --top 30   # Top 30 main perps\nopenbroker markets --coin BTC # Specific coin\n\nAll Markets (Perps + Spot + HIP-3)\nopenbroker all-markets                 # Show all markets\nopenbroker all-markets --type perp     # Main perps only\nopenbroker all-markets --type hip3     # HIP-3 perps only\nopenbroker all-markets --type spot     # Spot markets only\nopenbroker all-markets --top 20        # Top 20 by volume\n\nSearch Markets (Find assets across providers)\nopenbroker search --query GOLD    # Find all GOLD markets\nopenbroker search --query BTC     # Find BTC across all providers\nopenbroker search --query ETH --type perp  # ETH perps only\n\nSpot Markets\nopenbroker spot                   # Show all spot markets\nopenbroker spot --coin PURR       # Show PURR market info\nopenbroker spot --balances        # Show your spot balances\nopenbroker spot --top 20          # Top 20 by volume\n\nTrade Fills\nopenbroker fills                          # Recent fills\nopenbroker fills --coin ETH               # ETH fills only\nopenbroker fills --coin BTC --side buy --top 50\n\nOrder History\nopenbroker orders                         # Recent orders (all statuses)\nopenbroker orders --open                  # Currently open orders only\nopenbroker orders --open --coin ETH       # Open orders for a specific coin\nopenbroker orders --coin ETH --status filled\nopenbroker orders --top 50\n\nOrder Status\nopenbroker order-status --oid 123456789   # Check specific order\nopenbroker order-status --oid 0x1234...   # By client order ID\n\nFee Schedule\nopenbroker fees                           # Fee tier, rates, and volume\n\nCandle Data (OHLCV)\nopenbroker candles --coin ETH                           # 24 hourly candles\nopenbroker candles --coin BTC --interval 4h --bars 48   # 48 four-hour bars\nopenbroker candles --coin SOL --interval 1d --bars 30   # 30 daily bars\n\nFunding History\nopenbroker funding-history --coin ETH              # Last 24h\nopenbroker funding-history --coin BTC --hours 168  # Last 7 days\n\nRecent Trades (Tape)\nopenbroker trades --coin ETH              # Last 30 trades\nopenbroker trades --coin BTC --top 50     # Last 50 trades\n\nRate Limit\nopenbroker rate-limit                     # API usage and capacity\n\nFunding Rate Scanner (Cross-Dex)\nopenbroker funding-scan                          # Scan all dexes, >25% threshold\nopenbroker funding-scan --threshold 50 --pairs   # Show opposing funding pairs\nopenbroker funding-scan --hip3-only --top 20     # HIP-3 only\nopenbroker funding-scan --watch --interval 120   # Re-scan every 2 minutes\n\nTrading Commands\nHIP-3 Perp Trading\n\nAll trading commands support HIP-3 assets using dex:COIN syntax:\n\nopenbroker buy --coin xyz:CL --size 1              # Buy crude oil on xyz dex\nopenbroker sell --coin xyz:BRENTOIL --size 1        # Sell brent oil\nopenbroker limit --coin xyz:GOLD --side buy --size 0.1 --price 2500\nopenbroker funding-arb --coin xyz:CL --size 5000    # Funding arb on HIP-3\n\nMarket Orders (Quick)\nopenbroker buy --coin ETH --size 0.1\nopenbroker sell --coin BTC --size 0.01\nopenbroker buy --coin SOL --size 5 --slippage 100  # Custom slippage (bps)\n\nMarket Orders (Full)\nopenbroker market --coin ETH --side buy --size 0.1\nopenbroker market --coin BTC --side sell --size 0.01 --slippage 100\n\nLimit Orders\nopenbroker limit --coin ETH --side buy --size 1 --price 3000\nopenbroker limit --coin SOL --side sell --size 10 --price 200 --tif ALO\n\nSet TP/SL on Existing Position\n# Set take profit at $40, stop loss at $30\nopenbroker tpsl --coin HYPE --tp 40 --sl 30\n\n# Set TP at +10% from entry, SL at entry (breakeven)\nopenbroker tpsl --coin HYPE --tp +10% --sl entry\n\n# Set only stop loss at -5% from entry\nopenbroker tpsl --coin ETH --sl -5%\n\n# Partial position TP/SL\nopenbroker tpsl --coin ETH --tp 4000 --sl 3500 --size 0.5\n\nTrigger Orders (Standalone TP/SL)\n# Take profit: sell when price rises to $40\nopenbroker trigger --coin HYPE --side sell --size 0.5 --trigger 40 --type tp\n\n# Stop loss: sell when price drops to $30\nopenbroker trigger --coin HYPE --side sell --size 0.5 --trigger 30 --type sl\n\nCancel Orders\nopenbroker cancel --all           # Cancel all orders\nopenbroker cancel --coin ETH      # Cancel ETH orders only\nopenbroker cancel --oid 123456    # Cancel specific order\n\nAdvanced Execution\nTWAP (Time-Weighted Average Price)\n# Execute 1 ETH buy over 1 hour (auto-calculates slices)\nopenbroker twap --coin ETH --side buy --size 1 --duration 3600\n\n# Custom intervals with randomization\nopenbroker twap --coin BTC --side sell --size 0.5 --duration 1800 --intervals 6 --randomize 20\n\nScale In/Out (Grid Orders)\n# Place 5 buy orders ranging 2% below current price\nopenbroker scale --coin ETH --side buy --size 1 --levels 5 --range 2\n\n# Scale out with exponential distribution\nopenbroker scale --coin BTC --side sell --size 0.5 --levels 4 --range 3 --distribution exponential --reduce\n\nBracket Order (Entry + TP + SL)\n# Long ETH with 3% take profit and 1.5% stop loss\nopenbroker bracket --coin ETH --side buy --size 0.5 --tp 3 --sl 1.5\n\n# Short with limit entry\nopenbroker bracket --coin BTC --side sell --size 0.1 --entry limit --price 100000 --tp 5 --sl 2\n\nChase Order (Follow Price)\n# Chase buy with ALO orders until filled\nopenbroker chase --coin ETH --side buy --size 0.5 --timeout 300\n\n# Aggressive chase with tight offset\nopenbroker chase --coin SOL --side buy --size 10 --offset 2 --timeout 60\n\nTrading Strategies\nFunding Arbitrage\n# Collect funding on ETH if rate > 25% annualized\nopenbroker funding-arb --coin ETH --size 5000 --min-funding 25\n\n# Run for 24 hours, check every 30 minutes\nopenbroker funding-arb --coin BTC --size 10000 --duration 24 --check 30 --dry\n\nGrid Trading\n# ETH grid from $3000-$4000 with 10 levels, 0.1 ETH per level\nopenbroker grid --coin ETH --lower 3000 --upper 4000 --grids 10 --size 0.1\n\n# Accumulation grid (buys only)\nopenbroker grid --coin BTC --lower 90000 --upper 100000 --grids 5 --size 0.01 --mode long\n\nDCA (Dollar Cost Averaging)\n# Buy $100 of ETH every hour for 24 hours\nopenbroker dca --coin ETH --amount 100 --interval 1h --count 24\n\n# Invest $5000 in BTC over 30 days with daily purchases\nopenbroker dca --coin BTC --total 5000 --interval 1d --count 30\n\nMarket Making Spread\n# Market make ETH with 0.1 size, 10bps spread\nopenbroker mm-spread --coin ETH --size 0.1 --spread 10\n\n# Tighter spread with position limit\nopenbroker mm-spread --coin BTC --size 0.01 --spread 5 --max-position 0.1\n\nMaker-Only MM (ALO orders)\n# Market make using ALO (post-only) orders - guarantees maker rebates\nopenbroker mm-maker --coin HYPE --size 1 --offset 1\n\n# Wider offset for volatile assets\nopenbroker mm-maker --coin ETH --size 0.1 --offset 2 --max-position 0.5\n\nOrder Types\nLimit Orders vs Trigger Orders\n\nLimit Orders (openbroker limit):\n\nExecute immediately if price is met\nRest on the order book until filled or cancelled\nA limit sell BELOW current price fills immediately (taker)\nNOT suitable for stop losses\n\nTrigger Orders (openbroker trigger, openbroker tpsl):\n\nStay dormant until trigger price is reached\nOnly activate when price hits the trigger level\nProper way to set stop losses and take profits\nWon't fill prematurely\nWhen to Use Each\nScenario\tCommand\nBuy at specific price below market\topenbroker limit\nSell at specific price above market\topenbroker limit\nStop loss (exit if price drops)\topenbroker trigger --type sl\nTake profit (exit at target)\topenbroker trigger --type tp\nAdd TP/SL to existing position\topenbroker tpsl\nCommon Arguments\n\nAll commands support --dry for dry run (preview without executing).\n\nArgument\tDescription\n--coin\tAsset symbol (ETH, BTC, SOL, HYPE, etc.)\n--side\tOrder direction: buy or sell\n--size\tOrder size in base asset\n--price\tLimit price\n--dry\tPreview without executing\n--help\tShow command help\nOrder Arguments\nArgument\tDescription\n--trigger\tTrigger price (for trigger orders)\n--type\tTrigger type: tp or sl\n--slippage\tSlippage tolerance in bps (for market orders)\n--tif\tTime in force: GTC, IOC, ALO\n--reduce\tReduce-only order\nTP/SL Price Formats\nFormat\tExample\tDescription\nAbsolute\t--tp 40\tPrice of $40\nPercentage up\t--tp +10%\t10% above entry\nPercentage down\t--sl -5%\t5% below entry\nEntry price\t--sl entry\tBreakeven stop\nConfiguration\n\nConfig is loaded from (in priority order):\n\nEnvironment variables\n.env in current directory\n~/.openbroker/.env (global config)\n\nRun openbroker setup to create the global config interactively.\n\nVariable\tRequired\tDescription\nHYPERLIQUID_PRIVATE_KEY\tYes\tWallet private key (0x...)\nHYPERLIQUID_NETWORK\tNo\tmainnet (default) or testnet\nHYPERLIQUID_ACCOUNT_ADDRESS\tNo\tMaster account address (required for API wallets)\n\nThe builder fee (1 bps / 0.01%) is hardcoded and not configurable.\n\nOpenClaw Plugin (Optional)\n\nThis skill works standalone via Bash — every command above runs through the openbroker CLI. For enhanced features, the same openbroker npm package also ships as an OpenClaw plugin that you can enable alongside this skill.\n\nWhat the plugin adds\nStructured agent tools (ob_account, ob_buy, ob_limit, etc.) — typed tool calls with proper input schemas instead of Bash strings. The agent gets structured JSON responses.\nBackground position watcher — polls your Hyperliquid account every 30s and sends webhook alerts when positions open/close, PnL moves significantly, or margin usage gets dangerous.\nAutomation tools (ob_auto_run, ob_auto_stop, ob_auto_list) — start, stop, and manage custom trading automations from within the agent.\nCLI commands — openclaw ob status and openclaw ob watch for inspecting the watcher.\nEnable the plugin\n\nThe plugin is bundled in the same openbroker npm package. To enable it in your OpenClaw config:\n\nplugins:\n  entries:\n    openbroker:\n      enabled: true\n      config:\n        hooksToken: \"your-hooks-secret\"   # Required for watcher alerts\n        watcher:\n          enabled: true\n          pollIntervalMs: 30000\n          pnlChangeThresholdPct: 5\n          marginUsageWarningPct: 80\n\n\nThe plugin reads wallet credentials from ~/.openbroker/.env (set up by openbroker setup), so you don't need to duplicate privateKey in the plugin config unless you want to override.\n\nWebhook setup for watcher alerts\n\nFor position alerts to reach the agent, enable hooks in your gateway config:\n\nhooks:\n  enabled: true\n  token: \"your-hooks-secret\"   # Must match hooksToken above\n\n\nWithout hooks, the watcher still runs and tracks state (accessible via ob_watcher_status), but it can't wake the agent.\n\nUsing with or without the plugin\nSkill only (no plugin): Use Bash commands (openbroker buy --coin ETH --size 0.1). No background monitoring.\nSkill + plugin: The agent prefers the ob_* tools when available (structured data), falls back to Bash for commands not covered by tools (strategies, scale). Background watcher sends alerts automatically.\nTrading Automations\n\nAutomations let you write custom event-driven trading logic as TypeScript scripts. Instead of using the rigid built-in strategies, write exactly the logic you need and OpenBroker handles the polling, event detection, and SDK access.\n\nHow Automations Work\n\nAn automation is a .ts file that exports a default function. The function receives an AutomationAPI with the full Hyperliquid client, typed event subscriptions, persistent state, and a logger. The runtime polls Hyperliquid every 10s (configurable) and dispatches events when changes are detected.\n\nWriting an Automation\n\nCreate a .ts file in ~/.openbroker/automations/ (or any path):\n\n// ~/.openbroker/automations/funding-scalp.ts\nexport default function(api) {\n  const COIN = 'ETH';\n\n  api.on('funding_update', async ({ coin, annualized }) => {\n    if (coin !== COIN) return;\n\n    if (annualized > 0.5 && !api.state.get('isShort')) {\n      api.log.info('High positive funding — going short');\n      await api.client.marketOrder(COIN, false, 0.1);\n      api.state.set('isShort', true);\n    } else if (annualized < -0.1 && api.state.get('isShort')) {\n      api.log.info('Funding normalized — closing short');\n      await api.client.marketOrder(COIN, true, 0.1);\n      api.state.set('isShort', false);\n    }\n  });\n\n  api.onStop(async () => {\n    if (api.state.get('isShort')) {\n      api.log.warn('Closing short on shutdown');\n      await api.client.marketOrder('ETH', true, 0.1);\n      api.state.set('isShort', false);\n    }\n  });\n}\n\nAutomationAPI Reference\nProperty / Method\tDescription\napi.client\tFull HyperliquidClient — marketOrder(), limitOrder(), triggerOrder(), cancelAll(), getUserStateAll(), getAllMids(), updateLeverage(), and 35+ more methods\napi.on(event, handler)\tSubscribe to a market/account event (see Events below)\napi.every(ms, handler)\tRun a handler on a recurring interval (aligned to poll loop)\napi.onStart(handler)\tCalled after all handlers are registered, before first poll\napi.onStop(handler)\tCalled on shutdown (SIGINT). Use for cleanup — close positions, cancel orders\napi.onError(handler)\tCalled when a handler throws. Error is already logged — use for recovery logic\napi.state.get(key)\tGet a persisted value (survives restarts, stored in ~/.openbroker/state/)\napi.state.set(key, value)\tSet a persisted value\napi.state.delete(key)\tDelete a persisted value\napi.state.clear()\tClear all state\napi.publish(message, options?)\tSend a message to the OpenClaw agent via webhook. Triggers an agent turn — the agent receives the message and can notify the user, take action, etc. Returns true if delivered. Options: { name?, wakeMode?, deliver?, channel? }\napi.log.info/warn/error/debug(msg)\tStructured logger\napi.utils\troundPrice, roundSize, sleep, normalizeCoin, formatUsd, annualizeFundingRate\napi.id\tAutomation ID (filename or --id flag)\napi.dryRun\ttrue if running with --dry (write methods are intercepted)\nEvents\nEvent\tPayload\tWhen\ntick\t{ timestamp, pollCount }\tEvery poll cycle (default: 10s)\nprice_change\t{ coin, oldPrice, newPrice, changePct }\tMid price moved > 0.01% between polls\nfunding_update\t{ coin, fundingRate, annualized, premium }\tEvery poll for all assets\nposition_opened\t{ coin, side, size, entryPrice }\tNew position detected\nposition_closed\t{ coin, previousSize, entryPrice }\tPosition no longer present\nposition_changed\t{ coin, oldSize, newSize, entryPrice }\tPosition size changed\npnl_threshold\t{ coin, unrealizedPnl, changePct, positionValue }\tPnL moved > 5% of position value\nmargin_warning\t{ marginUsedPct, equity, marginUsed }\tMargin usage > 80%\nEvent Details — Choosing the Right Event\ntick — The universal heartbeat\n\nFires every single poll cycle (default: 10s) regardless of market conditions. Use this when you need to check something on every poll — absolute price thresholds, custom conditions, periodic account checks. This is the most reliable event because it always fires.\n\nPayload: { timestamp: number, pollCount: number }\n\nWhen to use:\n\nChecking if a price is above/below an absolute threshold (e.g. \"alert me when ETH < $3000\")\nCustom conditions that don't fit other events (e.g. \"if I have no positions and funding is high, enter\")\nPeriodic tasks that need to run every poll (though api.every() is better for longer intervals)\n\nExample — absolute price alert:\n\napi.on('tick', async () => {\n  const mids = await api.client.getAllMids();\n  const price = parseFloat(mids['HYPE']);\n  if (price < 38 && !api.state.get('alerted')) {\n    api.state.set('alerted', true);\n    await api.publish(`HYPE dropped below $38 — now at $${price.toFixed(3)}`);\n  }\n});\n\n\nNote: tick does not include price data in its payload — you must fetch it yourself via api.client.getAllMids(). This is because tick fires before any other event processing. If you only care about price movements, use price_change instead.\n\nprice_change — Relative price movements\n\nFires when a coin's mid price moves ≥ 0.01% compared to the previous poll. This filters out rounding noise while catching virtually any real price movement. The comparison is between consecutive polls (not from a fixed baseline), so it detects incremental changes.\n\nPayload: { coin: string, oldPrice: number, newPrice: number, changePct: number }\n\nWhen to use:\n\nReacting to price movements (breakouts, momentum, mean reversion)\nMonitoring specific coins for volatility\nBuilding price-triggered entry/exit logic\n\nWhen NOT to use:\n\nChecking if price is above/below a fixed threshold — use tick instead, because price_change only fires on relative movement between polls. During slow drifts (e.g. price slowly declining $0.001/s), the change between any two 10s polls may be < 0.01%, so the event won't fire even though the price has crossed your threshold.\n\nExample — momentum detector:\n\napi.on('price_change', async ({ coin, changePct, newPrice }) => {\n  if (coin !== 'ETH') return;\n  if (changePct > 0.5) {\n    api.log.info(`ETH surging +${changePct.toFixed(2)}% — price $${newPrice}`);\n    // Enter long on strong upward momentum\n  }\n});\n\nfunding_update — Funding rate data\n\nFires every poll for every asset that has funding rate data. This is high-frequency — if there are 150 perp assets, this fires 150 times per poll. Filter by coin in your handler.\n\nPayload: { coin: string, fundingRate: number, annualized: number, premium: number }\n\nfundingRate — the raw hourly funding rate (e.g. 0.0001 = 0.01%/hr)\nannualized — annualized rate (fundingRate × 8760 × 100, as a percentage)\npremium — the premium component\n\nWhen to use:\n\nFunding rate arbitrage strategies\nMonitoring for extreme funding (entry/exit signals)\nScanning for highest/lowest funding across all assets\n\nExample — funding scalp:\n\napi.on('funding_update', async ({ coin, annualized }) => {\n  if (coin !== 'ETH') return;\n  if (annualized > 50 && !api.state.get('isShort')) {\n    api.log.info(`ETH funding at ${annualized.toFixed(1)}% annualized — shorting`);\n    await api.client.marketOrder('ETH', false, 0.1);\n    api.state.set('isShort', true);\n  }\n});\n\nposition_opened — New position detected\n\nFires when a position appears that wasn't present in the previous poll. Useful for tracking entries made by other systems or confirming your own orders filled.\n\nPayload: { coin: string, side: 'long' | 'short', size: number, entryPrice: number }\n\nWhen to use:\n\nSetting TP/SL on new positions automatically\nLogging/alerting when positions are opened (by you or another system)\nStarting position-specific monitoring\n\nExample — auto TP/SL on new positions:\n\napi.on('position_opened', async ({ coin, side, size, entryPrice }) => {\n  const tpPrice = side === 'long' ? entryPrice * 1.05 : entryPrice * 0.95;\n  const slPrice = side === 'long' ? entryPrice * 0.97 : entryPrice * 1.03;\n  await api.client.takeProfit(coin, side !== 'long', size, tpPrice);\n  await api.client.stopLoss(coin, side !== 'long', size, slPrice);\n  api.log.info(`Set TP at ${tpPrice} / SL at ${slPrice} for ${coin}`);\n});\n\nposition_closed — Position gone\n\nFires when a position that existed in the previous poll is no longer present. The position was either closed by you, liquidated, or filled by TP/SL.\n\nPayload: { coin: string, previousSize: number, entryPrice: number }\n\nWhen to use:\n\nLogging/alerting when positions close\nCleaning up related orders or state\nRe-entry logic after a position closes\n\nExample:\n\napi.on('position_closed', async ({ coin, previousSize, entryPrice }) => {\n  api.log.info(`${coin} position closed (was ${previousSize} @ ${entryPrice})`);\n  api.state.delete(`${coin}_tp`);\n  await api.publish(`Position closed: ${coin} (entry: $${entryPrice})`);\n});\n\nposition_changed — Size or direction changed\n\nFires when an existing position's size changes (partial close, add to position, or flip direction). Does NOT fire when a new position opens or an existing one fully closes — use position_opened and position_closed for those.\n\nPayload: { coin: string, oldSize: number, newSize: number, entryPrice: number }\n\noldSize/newSize are signed: positive = long, negative = short\n\nWhen to use:\n\nDetecting partial closes or position scaling\nAdjusting TP/SL when position size changes\nTracking DCA entries\n\nExample:\n\napi.on('position_changed', async ({ coin, oldSize, newSize }) => {\n  if (Math.abs(newSize) > Math.abs(oldSize)) {\n    api.log.info(`${coin} position increased: ${oldSize} → ${newSize}`);\n  } else {\n    api.log.info(`${coin} position reduced: ${oldSize} → ${newSize}`);\n  }\n});\n\npnl_threshold — Significant PnL movement\n\nFires when unrealized PnL changes by ≥ 5% of position value between consecutive polls. This is a large move detector — useful for risk management alerts rather than routine monitoring.\n\nPayload: { coin: string, unrealizedPnl: number, changePct: number, positionValue: number }\n\nchangePct — the PnL change as a percentage of total position value (not % of PnL itself)\n\nWhen to use:\n\nRisk alerts for large PnL swings\nAuto-close or reduce positions on sudden adverse moves\nEscalating alerts to the user via api.publish()\n\nExample:\n\napi.on('pnl_threshold', async ({ coin, unrealizedPnl, changePct }) => {\n  if (unrealizedPnl < 0) {\n    await api.publish(\n      `⚠️ ${coin} PnL dropped sharply: $${unrealizedPnl.toFixed(2)} (${changePct.toFixed(1)}% of position)`,\n      { name: 'pnl-alert' },\n    );\n  }\n});\n\nmargin_warning — High margin usage\n\nFires when margin usage exceeds 80% of equity. After the first trigger, it only fires again if margin usage increases by another 5 percentage points (prevents spam). Resets when margin drops back below 80%.\n\nPayload: { marginUsedPct: number, equity: number, marginUsed: number }\n\nWhen to use:\n\nAutomated risk reduction (close smallest position to free margin)\nAlerting the user before liquidation risk\nPausing new entries when margin is high\n\nExample:\n\napi.on('margin_warning', async ({ marginUsedPct, equity }) => {\n  await api.publish(\n    `🚨 Margin at ${marginUsedPct.toFixed(1)}% — equity: $${equity.toFixed(2)}. Consider reducing exposure.`,\n    { name: 'margin-alert' },\n  );\n});\n\nChoosing the Right Event — Quick Guide\nUse case\tBest event\tWhy\nAlert when price crosses a fixed level\ttick\tFires every poll — no minimum change threshold\nReact to price momentum/volatility\tprice_change\tProvides relative change data between polls\nFunding rate strategy\tfunding_update\tGives annualized rate directly\nAuto TP/SL on new positions\tposition_opened\tFires exactly when a new position appears\nLog when positions close\tposition_closed\tFires when position disappears\nTrack position scaling\tposition_changed\tFires on size changes only\nRisk management — PnL spikes\tpnl_threshold\tOnly fires on large moves (≥5% of position value)\nRisk management — margin\tmargin_warning\tFires at 80%+ margin usage\nPeriodic task (DCA, rebalance)\tapi.every(ms, fn)\tBetter than tick for longer intervals\nClient Methods Available\n\nThe api.client object exposes the full Hyperliquid SDK:\n\nTrading: marketOrder(coin, isBuy, size), limitOrder(coin, isBuy, size, price), triggerOrder(coin, isBuy, size, triggerPx, isMarket), takeProfit(coin, isBuy, size, triggerPx), stopLoss(coin, isBuy, size, triggerPx), cancel(coin, oid), cancelAll(coin?)\n\nMarket Data: getAllMids(), getMetaAndAssetCtxs(), getRecentTrades(coin), getCandleSnapshot(coin, interval), getFundingHistory(coin), getPredictedFundings()\n\nAccount: getUserStateAll(), getOpenOrders(), getUserFills(), getUserFunding(), getHistoricalOrders(), getUserFees(), getUserRateLimit(), getSpotBalances()\n\nLeverage: updateLeverage(coin, leverage, isIsolated?)\n\nExample: Price Breakout\n// ~/.openbroker/automations/breakout.ts\nexport default function(api) {\n  const COIN = 'ETH';\n  const BREAKOUT_PCT = 2;  // 2% move triggers entry\n  const SIZE = 0.5;\n  let basePrice = null;\n\n  api.onStart(async () => {\n    const mids = await api.client.getAllMids();\n    basePrice = parseFloat(mids[COIN]);\n    api.log.info(`Watching ${COIN} from $${basePrice} for ${BREAKOUT_PCT}% breakout`);\n  });\n\n  api.on('price_change', async ({ coin, newPrice }) => {\n    if (coin !== COIN || !basePrice) return;\n    const totalChange = ((newPrice - basePrice) / basePrice) * 100;\n\n    if (Math.abs(totalChange) >= BREAKOUT_PCT && !api.state.get('inPosition')) {\n      const side = totalChange > 0;  // true = long, false = short\n      api.log.info(`Breakout! ${totalChange.toFixed(2)}% — entering ${side ? 'long' : 'short'}`);\n      await api.client.marketOrder(COIN, side, SIZE);\n      api.state.set('inPosition', true);\n    }\n  });\n}\n\nExample: Scheduled DCA\n// ~/.openbroker/automations/hourly-dca.ts\nexport default function(api) {\n  const COIN = 'ETH';\n  const USD_PER_BUY = 100;\n\n  // Buy $100 of ETH every hour\n  api.every(60 * 60 * 1000, async () => {\n    const mids = await api.client.getAllMids();\n    const price = parseFloat(mids[COIN]);\n    const size = parseFloat(api.utils.roundSize(USD_PER_BUY / price, 4));\n    await api.client.marketOrder(COIN, true, size);\n    const count = (api.state.get('buyCount') || 0) + 1;\n    api.state.set('buyCount', count);\n    api.log.info(`DCA #${count}: bought ${size} ${COIN} at $${price}`);\n  });\n}\n\nExample: Margin Guardian\n// ~/.openbroker/automations/margin-guard.ts\nexport default function(api) {\n  api.on('margin_warning', async ({ marginUsedPct, equity }) => {\n    api.log.warn(`Margin at ${marginUsedPct.toFixed(1)}% — reducing positions`);\n\n    // Close the smallest position to free margin\n    const state = await api.client.getUserStateAll();\n    const positions = state.assetPositions\n      .filter(p => parseFloat(p.position.szi) !== 0)\n      .sort((a, b) => Math.abs(parseFloat(a.position.positionValue)) - Math.abs(parseFloat(b.position.positionValue)));\n\n    if (positions.length > 0) {\n      const pos = positions[0].position;\n      const size = Math.abs(parseFloat(pos.szi));\n      const isBuy = parseFloat(pos.szi) < 0; // Close short = buy, close long = sell\n      api.log.info(`Closing smallest position: ${pos.coin} (${pos.szi})`);\n      await api.client.marketOrder(pos.coin, isBuy, size);\n    }\n  });\n}\n\nPublishing to the Agent (Webhooks)\n\nUse api.publish() to send messages back to the OpenClaw agent. This triggers an agent turn — the agent receives the message and can notify the user via their preferred channel, take trading actions, or log the event.\n\n// Simple notification\nawait api.publish(`ETH broke above $4000 — current price: $${price}`);\n\n// With options\nawait api.publish(`Margin at ${pct}% — positions at risk`, {\n  name: 'margin-alert',           // appears in logs\n  wakeMode: 'now',                // 'now' (default) or 'next-heartbeat'\n  channel: 'slack',               // target channel (optional)\n});\n\n\napi.publish() returns true if delivered, false if webhooks are not configured (no hooks token). It requires OPENCLAW_HOOKS_TOKEN to be set (automatically configured when running as an OpenClaw plugin).\n\nExample: Price alert automation with publish\n\n// ~/.openbroker/automations/price-alert.ts\nexport default function(api) {\n  const COIN = 'ETH';\n  const THRESHOLD = 4000;\n\n  api.on('price_change', async ({ coin, newPrice, changePct }) => {\n    if (coin !== COIN) return;\n\n    const crossed = api.state.get<boolean>('crossed', false);\n    if (!crossed && newPrice >= THRESHOLD) {\n      api.state.set('crossed', true);\n      await api.publish(\n        `${COIN} crossed above $${THRESHOLD}! Price: $${newPrice.toFixed(2)} (+${changePct.toFixed(2)}%)`,\n      );\n    } else if (crossed && newPrice < THRESHOLD) {\n      api.state.set('crossed', false);\n    }\n  });\n}\n\nRunning Automations\n\nCLI:\n\nopenbroker auto run my-strategy --dry       # Test without trading\nopenbroker auto run ./funding-scalp.ts      # Run from path\nopenbroker auto run my-strategy --poll 5000 # Poll every 5s\nopenbroker auto list                        # Show available scripts\nopenbroker auto status                      # Show running automations\n\n\nPlugin tools (for OpenClaw agents):\n\nob_auto_run — { \"script\": \"funding-scalp\", \"dry\": true } — start an automation\nob_auto_stop — { \"id\": \"funding-scalp\" } — stop a running automation\nob_auto_list — {} — list available and running automations\n\nOptions:\n\nFlag\tDescription\tDefault\n--dry\tIntercept write methods — no real trades\tfalse\n--verbose\tShow debug output\tfalse\n--id <name>\tCustom automation ID\tfilename\n--poll <ms>\tPoll interval in milliseconds\t10000\n\nGuidelines for agents writing automations:\n\nRisk & Safety (mandatory):\n\nAlways attach a liquidation monitoring automation to every open position. Subscribe to margin_warning and pnl_threshold events so the user is never blindsided by liquidation risk. If no margin/liquidation automation is already running, create one before placing trades.\nUse api.publish() to notify the user of important events — position opens/closes, TP/SL triggers, large PnL swings, margin warnings, errors, and any situation that requires human attention. Do NOT silently handle critical events.\nAlways register an api.onStop() handler to clean up — cancel open orders and close positions (or at minimum alert the user) on shutdown. Never leave orphaned orders or unmanaged positions.\nDo NOT use --dry unless the user explicitly asks for it. Automations should run live by default.\nNever place trades without validating that sufficient margin is available. Check account state before sizing orders.\nCap position sizes relative to account equity. Do not risk more than a reasonable percentage of equity on a single trade unless the user explicitly specifies the size.\nAlways set TP/SL on new positions — either within the automation or by confirming the user has them set. Unprotected positions are a liability.\n\nState & Reliability:\n\nUse api.state to track position state, entry prices, and flags across restarts. Never rely on in-memory variables alone — automations persist across gateway restarts and are automatically restarted.\nUse idempotency guards (api.state.get/set) to prevent duplicate orders. Events can fire multiple times for the same condition across polls — always check state before placing orders.\nThe runtime catches errors per handler — one failing handler won't crash others, but always handle expected errors (e.g. order rejection, insufficient margin) gracefully within handlers.\n\nCommunication:\n\nUse api.publish() to send alerts/events back to the OpenClaw agent — do NOT manually construct webhook requests.\nPublish on: position opened/closed, TP/SL triggered, PnL threshold exceeded, margin warning, automation errors, and any automated trade execution. The user should always know what the automation did and why.\nInclude actionable context in publish messages — coin, price, size, PnL, and what happened — so the user can make informed decisions without checking the terminal.\n\nGeneral:\n\nScripts are loaded from ~/.openbroker/automations/ by name, or from any absolute path.\nAll trading commands support HIP-3 assets (api.client.marketOrder('xyz:CL', true, 1)).\nAutomations persist across gateway restarts — they are automatically restarted when the gateway comes back up.\nPrefer api.every(ms, fn) over tick for periodic tasks with intervals longer than the poll cycle.\nRisk Warning\nAlways use --dry first to preview orders\nStart with small sizes on testnet (HYPERLIQUID_NETWORK=testnet)\nMonitor positions and liquidation prices\nUse --reduce for closing positions only"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/ya7ya/openbroker",
    "publisherUrl": "https://clawhub.ai/ya7ya/openbroker",
    "owner": "ya7ya",
    "version": "1.0.67",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/openbroker",
    "downloadUrl": "https://openagent3.xyz/downloads/openbroker",
    "agentUrl": "https://openagent3.xyz/skills/openbroker/agent",
    "manifestUrl": "https://openagent3.xyz/skills/openbroker/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/openbroker/agent.md"
  }
}