{"skill":{"slug":"superiortrade","displayName":"Superior Trade","summary":"Backtest and deploy trading strategies on Superior Trade's managed cloud.","description":"---\r\nname: Superior Trade\r\nversion: 4.4.6\r\nupdated: 2026-05-18\r\ndescription: \"Backtest and deploy trading strategies on Superior Trade's managed cloud.\"\r\nhomepage: https://account.superior.trade\r\nsource: https://github.com/Superior-Trade\r\nprimaryEnv: SUPERIOR_TRADE_API_KEY\r\nauth:\r\n  type: api_key\r\n  env: SUPERIOR_TRADE_API_KEY\r\n  header: x-api-key\r\n  scope: \"Read-write the user's own backtests and deployments. Can start live trading deployments that execute real trades with the user's platform-managed trading wallet. Cannot withdraw funds, export private keys, or access other users' data.\"\r\nenv:\r\n  - name: SUPERIOR_TRADE_API_KEY\r\n    description: \"Superior Trade API key (x-api-key header). Obtained at https://account.superior.trade. Can create/manage backtests and deployments including live trading. Cannot withdraw funds, export private keys, or access other users' data. Users do not need their own Hyperliquid wallet.\"\r\n    required: true\r\n    type: api_key\r\nexternalEndpoints:\r\n  - url: https://api.superior.trade\r\n    purpose: \"All backtesting and deployment operations\"\r\n  - url: https://api.hyperliquid.xyz/info\r\n    purpose: \"Read-only public queries. Balance checks send the user's public wallet address (not a secret — visible on-chain). Pair validation sends no user data. No authentication or secrets are sent to this endpoint.\"\r\n---\r\n\r\n# Superior Trade API\r\n\r\nAPI client skill for backtesting and deploying trading strategies on Superior Trade's managed cloud.\r\n\r\n**Base URL:** `https://api.superior.trade`  \r\n**Auth:** `x-api-key` header on all protected endpoints  \r\n**Docs:** `GET /docs` (Swagger UI), `GET /openapi.json` (OpenAPI spec)\r\n\r\n## Setup\r\n\r\n### Getting an API Key\r\n\r\n> **IMPORTANT:** The correct URL is **https://account.superior.trade** — NOT `app.superior.trade`. Never send users to `app.superior.trade`.\r\n\r\nUse `SUPERIOR_TRADE_API_KEY` from the environment or credential manager.\r\n\r\nWhen a user needs to get their API key:\r\n\r\n1. Go to https://account.superior.trade\r\n2. Sign up (email or wallet)\r\n3. Complete onboarding — a trading wallet is created for you and shown in your account\r\n4. Deposit USDC to your wallet address (on Arbitrum)\r\n5. Create an API key (`st_live_...`) from your account settings\r\n6. Add it as `SUPERIOR_TRADE_API_KEY` in your agent's environment/credential settings\r\n\r\nIf the `SUPERIOR_TRADE_API_KEY` env var is already set, use it directly in the `x-api-key` header without prompting the user.\r\n\r\n### Public Endpoints (no auth)\r\n\r\n| Method | Path                          | Description                              |\r\n| ------ | ----------------------------- | ---------------------------------------- |\r\n| GET    | `/health`                     | `{ \"status\": \"ok\", \"timestamp\": \"...\" }` |\r\n| GET    | `/docs`                       | Swagger UI                               |\r\n| GET    | `/openapi.json`               | OpenAPI 3.0 spec                         |\r\n| GET    | `/llms.txt`                   | LLM-optimized API docs                   |\r\n| GET    | `/.well-known/ai-plugin.json` | AI plugin manifest                       |\r\n\r\n## Reference Library\r\n\r\nThese pages live alongside this skill in the same repo. Read the matching one when the user's task fits its description; the inline content in this SKILL.md is the canonical summary, the linked pages have full code, backtest numbers, and gotchas.\r\n\r\n### Strategy templates (Hyperliquid Freqtrade)\r\n\r\n- [DCA · Weekly buy](https://github.com/Superior-Trade/superior-skills/blob/main/strategies/dca-weekly.md) — scheduled buys via `adjust_trade_position` (works on calendar trigger, not price)\r\n- [Grid trading](https://github.com/Superior-Trade/superior-skills/blob/main/strategies/grid-trading.md) — profit-laddered position adjustment + partial take-profits\r\n- [Funding rate arbitrage](https://github.com/Superior-Trade/superior-skills/blob/main/strategies/funding-rate-arbitrage.md) — capture funding when shorts are paying longs (the most profitable template in our audit)\r\n- [Funding squeeze](https://github.com/Superior-Trade/superior-skills/blob/main/strategies/funding-squeeze.md) — long when funding is deeply negative AND price is rising; ride the squeeze instead of waiting for carry mean-reversion\r\n- [Basis arbitrage (directional)](https://github.com/Superior-Trade/superior-skills/blob/main/strategies/basis-arb.md) — long perp when spot–perp basis flips negative with funding negative (directional read; not a hedged arb)\r\n- [Breakout](https://github.com/Superior-Trade/superior-skills/blob/main/strategies/breakout.md) — Donchian-style breakout with trailing stop (regime-sensitive)\r\n- [Mean reversion](https://github.com/Superior-Trade/superior-skills/blob/main/strategies/mean-reversion.md) — 2.5σ Bollinger fade with ADX regime filter\r\n- [Scalping](https://github.com/Superior-Trade/superior-skills/blob/main/strategies/scalping.md) — fast in/out on RSI thrust + volume spike (structural template; tune before deploying)\r\n\r\n### Exchange-specific guides\r\n\r\n- [Aerodrome / Base](https://github.com/Superior-Trade/superior-skills/blob/main/exchanges/aerodrome.md) — spot AMM swap execution on Base; no order book, no leverage, wallet-balance-driven\r\n\r\n### Optimizations\r\n\r\n- [Backtesting best practices](https://github.com/Superior-Trade/superior-skills/blob/main/optimizations/backtesting.md) — window selection, trade-count thresholds, exit-reason mix, parameter sweeps, walk-forward, zero-trade escalation, compute-cost estimation\r\n- [Fees optimization](https://github.com/Superior-Trade/superior-skills/blob/main/optimizations/fees-optimizations.md) — Freqtrade × Hyperliquid order types, entry/exit pricing, maker vs taker, builder code fee, edge-to-fee budgeting\r\n\r\n## Safety\r\n\r\n### Security & Permissions\r\n\r\nThis skill requires exactly **one credential**: an `x-api-key` header value. The only secret the agent uses is `SUPERIOR_TRADE_API_KEY` from the environment.\r\n\r\n**Security rules (non-negotiable):**\r\n\r\n1. **NEVER** ask users for private keys, seed phrases, or wallet credentials\r\n2. **NEVER** include private keys in API requests (the API rejects them)\r\n3. **NEVER** log, store, or display private keys or seed phrases\r\n4. **NEVER** tell users to deposit funds to the agent wallet address\r\n5. **NEVER** fabricate wallet balances, API responses, or trade results\r\n6. **NEVER** start a live deployment without explicit user confirmation\r\n7. **Prefer user-friendly language** over internal technical names when speaking conversationally. Say \"strategy\", \"the bot\", or \"the trading engine\" instead of referencing internal class names or infrastructure details. This is a UX preference — if the user asks about the underlying technology, answer honestly (the platform uses Freqtrade for strategy execution on Hyperliquid).\r\n8. **NEVER** send users to `app.superior.trade` — the correct URL is `https://account.superior.trade`\r\n\r\n> **Key scope notice:** The API key can create and start live trading deployments that execute real trades using the user's platform-managed trading wallet. It cannot withdraw funds, export private keys, or move money. Users should confirm scope with Superior Trade and backtest their strategy first.\r\n\r\n| Can do                                                                           | Cannot do                                               |\r\n| -------------------------------------------------------------------------------- | ------------------------------------------------------- |\r\n| Create, list, delete backtests                                                   | Access other users' data                                |\r\n| Create, start, stop, delete deployments (including live trading with real funds) | Withdraw funds from any wallet                          |\r\n| Trigger server-side credential resolution (no user secrets collected)            | Export or view private keys                             |\r\n| View deployment logs, status, wallet metadata                                    | Transfer or bridge funds (user does this independently) |\r\n\r\n### Live Deployment Confirmation\r\n\r\nBefore any **live deployment**, the agent MUST present this summary and wait for explicit confirmation:\r\n\r\n```\r\nDeployment Summary:\r\n• Strategy: [name]\r\n• Exchange: hyperliquid\r\n• Trading mode: [spot/futures]\r\n• Pairs: [list]\r\n• Stake amount: [amount] USDC per trade\r\n• Max open trades: [n]\r\n• Stoploss: [percentage]\r\n• Margin mode: [cross/isolated] (futures only)\r\n\r\n⚠️ This will trade with REAL funds. Proceed? (yes/no)\r\n```\r\n\r\nDo NOT start a live deployment without an explicit affirmative response.\r\n\r\n## Platform Model\r\n\r\n### Wallet Architecture (CRITICAL)\r\n\r\nSuperior Trade uses Hyperliquid's native **agent wallet** pattern. Users do NOT need their own Hyperliquid wallet — everything is managed by the platform. If a user asks \"how do I link my Hyperliquid account,\" the answer is: **they don't need one** — a trading wallet is created at signup.\r\n\r\n1. **Main wallet** — a platform-managed trading wallet created for each user at signup. Holds the funds on Hyperliquid. Users deposit USDC to this address (shown at https://account.superior.trade).\r\n2. **Agent wallet** — a platform-managed signing key authorized via Hyperliquid's `approveAgent`. Signs trades against the main wallet's balance.\r\n\r\n**Key facts:**\r\n\r\n- The agent wallet does NOT need its own funds — $0 balance is normal and expected\r\n- Each user has one agent wallet; all deployments share it\r\n- The credentials endpoint returns `wallet_type: \"agent_wallet\"` for auto-resolved wallets\r\n- Always check the **main wallet's** balance, not the agent wallet's\r\n- The API has no transfer/fund-routing endpoint — you cannot move funds via the API\r\n- **NEVER tell users to deposit to the agent wallet address**\r\n\r\n### Funding and Balance Checks\r\n\r\nThe agent cannot move or bridge funds — the user handles this independently outside the skill:\r\n\r\n1. The user deposits USDC to their platform wallet address (shown at https://account.superior.trade)\r\n2. The agent wallet signs trades against this balance — no internal transfers needed\r\n\r\nAlways check the **main wallet** (platform-managed trading wallet), NOT the agent wallet.\r\n\r\n**Balance query for master account (single deployment):**\r\n\r\n```\r\nPOST https://api.hyperliquid.xyz/info\r\n{\"type\":\"clearinghouseState\",\"user\":\"<MAIN_WALLET_ADDRESS>\"}\r\n{\"type\":\"spotClearinghouseState\",\"user\":\"<MAIN_WALLET_ADDRESS>\"}\r\n```\r\n\r\n**Balance query for master account (multi-strategy with sub-accounts):**\r\n\r\nWhen the master account has sub-accounts, its total balance is the sum of its own perp + spot balances PLUS all sub-account balances. Query both:\r\n\r\n```\r\nPOST https://api.hyperliquid.xyz/info\r\n{\"type\":\"subAccounts2\",\"user\":\"<MAIN_WALLET_ADDRESS>\"}\r\n```\r\n\r\nSub-account balances are included in the master account's total — funds allocated to sub-accounts are not available for master deployments. Always query `subAccounts2` first when the user has sub-accounts, then sum across all sub-account `spotState.balances` and `dexToClearinghouseState` entries to get the true total balance.\r\n\r\nThe agent wallet having $0 is expected — it trades against the main wallet's balance.\r\n\r\n### Sub-Accounts for Multi-Strategy Trading\r\n\r\nUsers with **≥ $100,000 USD in lifetime trading volume** on Hyperliquid can create sub-accounts to run multiple independent strategies simultaneously, each with its own isolated balance and positions.\r\n\r\n**Key facts:**\r\n\r\n- Sub-accounts inherit the master account's collateral (USDC, USDE, USDT0, USDH)\r\n- Each sub-account can have its own deployment with isolated margin/positions\r\n- Maximum 10 sub-accounts per master account\r\n- Sub-accounts use **unified account mode** — spot and perps share a single balance\r\n\r\n**Sub-account query** (read-only):\r\n\r\n```\r\nPOST https://api.hyperliquid.xyz/info\r\n{\"type\":\"subAccounts2\",\"user\":\"<MAIN_WALLET_ADDRESS>\"}\r\n```\r\n\r\nReturns each sub-account's name, address, `abstraction` mode (\"unifiedAccount\" or legacy), spot balances, and perps state (`dexToClearinghouseState`). Always verify the sub-account has `abstraction: \"unifiedAccount\"` — legacy sub-accounts cannot be used with unified margin strategies.\r\n\r\n**Balance composition for a sub-account:**\r\n\r\n- **Perps account value:** from `dexToClearinghouseState[0][1].marginSummary.accountValue`\r\n- **Perps withdrawable:** from `dexToClearinghouseState[0][1].withdrawable`\r\n- **Spot USDC:** from `spotState.balances` where `coin === \"USDC\"`\r\n\r\nThe sub-account's total balance = perps account value + spot USDC (in unified mode these merge).\r\n\r\n### Hyperliquid Authorize-and-Send API\r\n\r\n`POST https://api.superior.trade/v2/authorize-and-send/hyperliquid`\r\n\r\nA unified endpoint for Hyperliquid operations. All requests use `{\"type\": \"...\", ...}` body. Requires `x-api-key` header.\r\n\r\n**Supported operation types:**\r\n\r\n| Operation | Description |\r\n| --------- | ----------- |\r\n| `createSubAccount` | Create a new sub-account |\r\n| `subAccountTransfer` | Transfer between main and sub-account |\r\n| `sendAsset` | Move assets (main→sub, sub→main, or sub→sub) |\r\n| `userSetAbstraction` | Set account mode (unified/legacy) |\r\n| `subAccountModify` | Modify sub-account settings |\r\n\r\n**Create sub-account:**\r\n```json\r\n{\"type\":\"createSubAccount\",\"user\":\"<MAIN_WALLET_ADDRESS>\",\"name\":\"My Strategy\"}\r\n```\r\n\r\n**Sub-account transfer (main → sub):**\r\n```json\r\n{\"type\":\"subAccountTransfer\",\"from\":\"<MAIN_WALLET_ADDRESS>\",\"to\":\"<SUB_ACCOUNT_ADDRESS>\",\"token\":\"USDC\",\"amount\":1000}\r\n```\r\n\r\n**Sub-account transfer (sub → main):**\r\n```json\r\n{\"type\":\"subAccountTransfer\",\"from\":\"<SUB_ACCOUNT_ADDRESS>\",\"to\":\"<MAIN_WALLET_ADDRESS>\",\"token\":\"USDC\",\"amount\":500}\r\n```\r\n\r\n**Transfer via sendAsset (main → sub):**\r\n```json\r\n{\"type\":\"sendAsset\",\"destination\":\"<SUB_ACCOUNT_ADDRESS>\",\"sourceDex\":\"spot\",\"destinationDex\":\"spot\",\"token\":\"USDC\",\"amount\":1000}\r\n```\r\n\r\n**Transfer via sendAsset (sub → main):**\r\n```json\r\n{\"type\":\"sendAsset\",\"fromSubAccount\":\"<SUB_ACCOUNT_ADDRESS>\",\"destination\":\"<MASTER_WALLET_ADDRESS>\",\"sourceDex\":\"spot\",\"destinationDex\":\"spot\",\"token\":\"USDC\",\"amount\":500}\r\n```\r\n\r\n**Set unified account mode on a sub-account:**\r\n```json\r\n{\"type\":\"userSetAbstraction\",\"user\":\"<SUB_ACCOUNT_ADDRESS>\",\"abstraction\":\"unifiedAccount\"}\r\n```\r\n\r\nWhen creating a sub-account via the API, unified mode is set automatically after creation by calling `userSetAbstraction` with `abstraction: \"unifiedAccount\"`.\r\n\r\n**Modify sub-account:**\r\n```json\r\n{\"type\":\"subAccountModify\",\"user\":\"<SUB_ACCOUNT_ADDRESS>\",\"action\":\"disable\"}\r\n```\r\n\r\n### Hyperliquid Credentials\r\n\r\nCredentials are managed automatically. To use a specific wallet, pass `wallet_address` — ownership is validated server-side.\r\n\r\n## Exchange and Pair Rules\r\n\r\n### Supported Exchanges\r\n\r\n| Exchange    | Stake Currencies                       | Trading Modes |\r\n| ----------- | -------------------------------------- | ------------- |\r\n| Hyperliquid | USDC (also USDT0, USDH, USDE via HIP3) | spot, futures |\r\n\r\n### Hyperliquid Notes\r\n\r\n**Pair format by trading mode** (CCXT convention):\r\n\r\n- **Spot**: `BTC/USDC`\r\n- **Futures/Perp**: `BTC/USDC:USDC`\r\n\r\n**Spot limitations:** No stoploss on exchange (bot handles internally), no market orders (simulated via limit with up to 5% slippage).\r\n\r\n**Futures:** Margin modes `\"cross\"` and `\"isolated\"`. Stoploss on exchange via `stop-loss-limit` orders. No market orders (same simulation).\r\n\r\n**Data availability:** Hyperliquid API provides ~5000 historic candles per pair. Superior Trade pre-downloads data; availability starts from ~November 2025.\r\n\r\n**Hyperliquid is a DEX** — uses wallet-based signing, not API key/secret. Wallet credentials are managed automatically by the platform.\r\n\r\n### HIP3 — Tokenized Real-World Assets\r\n\r\nHIP3 assets (stocks, commodities, indices) are perpetual futures.\r\n\r\n> **CRITICAL: HIP3 uses a HYPHEN, not a colon. This is the #1 format mistake.** Wrong: `XYZ:AAPL/USDC:USDC`. Correct: `XYZ-AAPL/USDC:USDC`.\r\n\r\n**Pair format:** `PROTOCOL-TICKER/QUOTE:SETTLE` — the separator between protocol and ticker is always **`-`** (hyphen).\r\n\r\n| Protocol | Dex name | Asset Types                               | Stake Currency | Examples                                   |\r\n| -------- | -------- | ----------------------------------------- | -------------- | ------------------------------------------ |\r\n| `XYZ-`   | `xyz`    | US/KR stocks, metals, currencies, indices | USDC           | `XYZ-AAPL/USDC:USDC`, `XYZ-GOLD/USDC:USDC` |\r\n| `CASH-`  | `cash`   | Stocks, commodities                       | USDT0          | `CASH-GOLD/USDT0:USDT0`                    |\r\n| `FLX-`   | `flx`    | Commodities, metals, crypto               | USDH           | `FLX-GOLD/USDH:USDH`                       |\r\n| `KM-`    | `km`     | Stocks, indices, bonds                    | USDH           | `KM-GOOGL/USDH:USDH`                       |\r\n| `HYNA-`  | `hyna`   | Leveraged crypto, metals                  | USDE           | `HYNA-SOL/USDE:USDE`                       |\r\n| `VNTL-`  | `vntl`   | Sector indices, pre-IPO                   | USDH           | `VNTL-SPACEX/USDH:USDH`                    |\r\n\r\n**XYZ tickers (USDC):** AAPL, ALUMINIUM, AMD, AMZN, BABA, BRENTOIL, CL, COIN, COPPER, COST, CRCL, CRWV, DKNG, DXY, EUR, EWJ, EWY, GME, GOLD, GOOGL, HIMS, HOOD, HYUNDAI, INTC, JP225, JPY, KIOXIA, KR200, LLY, META, MSFT, MSTR, MU, NATGAS, NFLX, NVDA, ORCL, PALLADIUM, PLATINUM, PLTR, RIVN, SILVER, SKHX, SMSN, SNDK, SOFTBANK, SP500, TSLA, TSM, URANIUM, URNM, USAR, VIX, XYZ100\r\n\r\n**Data:** XYZ from ~November 2025, KM/CASH/FLX from ~February 2026. Timeframes: 1m, 3m, 5m, 15m, 30m, 1h (also 2h, 4h, 8h, 12h, 1d, 3d, 1w for some). Funding rate data at 1h.\r\n\r\n**Trading rules:** HIP3 assets are futures-only — always use `trading_mode: \"futures\"` and `margin_mode: \"isolated\"`. XYZ pairs use `stake_currency: \"USDC\"`. Stock-based assets may have reduced liquidity outside US market hours.\r\n\r\n### Pair Discovery\r\n\r\n- **Standard perps:** `{\"type\":\"meta\"}` — check `universe[].name`\r\n- **HIP3 pairs:** `{\"type\":\"meta\", \"dex\":\"xyz\"}` (or `\"cash\"`, `\"km\"`, etc.) — HIP3 pairs are NOT in the default meta call\r\n- **List all dexes:** `{\"type\":\"perpDexs\"}`\r\n- **Name conversion:** API returns `xyz:AAPL` → CCXT format `XYZ-AAPL/USDC:USDC` (uppercase prefix, colon→hyphen)\r\n\r\n### Unified vs Legacy Account Mode\r\n\r\nHyperliquid accounts may run in **unified mode** (single balance) or **legacy mode** (separate spot/perps balances). Do NOT assume which mode the user has.\r\n\r\n- If perps shows $0 but spot shows funds, ask about unified mode before suggesting the user move funds themselves.\r\n- In unified mode, spot USDC is automatically available as perps collateral.\r\n\r\n## Agent Operating Rules\r\n\r\n- **Verification-first:** Every factual claim about balance, wallet status, or deployment health MUST be backed by an API call in the current turn. NEVER assume → report → verify later.\r\n- **Anti-hallucination:** If you can't call the API, say \"I haven't checked yet.\" Every number must come from a real response.\r\n- **Conversational:** Make API calls directly and present results conversationally. Show raw payloads only on request.\r\n- **Backtesting:** Build config + code from user intent → create → start → poll → present results — all automatically.\r\n- **Deployment:** Create → store credentials → run checklist → show summary → get confirmation → start.\r\n- **Proactive:** Ask for missing info conversationally, one concern at a time. Always ask user to run a backtest before first live deployment.\r\n\r\nCheck Hyperliquid balances with BOTH endpoints:\r\n\r\n- **Perps:** `POST https://api.hyperliquid.xyz/info` → `{\"type\":\"clearinghouseState\",\"user\":\"0x...\"}`\r\n- **Spot:** `POST https://api.hyperliquid.xyz/info` → `{\"type\":\"spotClearinghouseState\",\"user\":\"0x...\"}`\r\n\r\n### Repeated Failures\r\n\r\nIf the agent fails the same task 3+ times (e.g. strategy code keeps crashing, backtest keeps failing), stop and:\r\n\r\n1. Summarize what was tried and what failed\r\n2. Pivot in two stages before giving up:\r\n   - **First — param space.** If you have not yet run a parameter sweep on this strategy/pair, run one (see Backtest Workflow → Parameter Sweeps). Most \"this idea doesn't work\" verdicts are really \"this single config didn't work\" — sweeping the key parameter often surfaces a viable variant in one batch.\r\n   - **Second — pair space.** Only after a full sweep also fails, suggest a different pair, timeframe, or strategy family (e.g. mean-reversion instead of momentum).\r\n3. If the issue appears to be model capability (complex multi-indicator strategy), suggest switching to a more capable model for strategy generation\r\n\r\n## Workflows\r\n\r\n### Backtest Workflow\r\n\r\n1. Build config + strategy code from user requirements\r\n2. `POST /v2/backtesting` — create with config, code, and timerange (`{ \"start\": \"YYYY-MM-DD\", \"end\": \"YYYY-MM-DD\" }`). If the dates are invalid or omitted, the server picks a suitable duration based on the timeframe.\r\n3. `PUT /v2/backtesting/{id}/status` with `{\"action\": \"start\"}`\r\n4. Poll `GET /v2/backtesting/{id}/status` every 10s until `completed` or `failed` (1–10 min)\r\n5. `GET /v2/backtesting/{id}` — fetch full results; download `resultUrl` for detailed JSON\r\n6. Present summary: total trades, win rate, profit, drawdown, Sharpe ratio\r\n7. If failed, check `GET /v2/backtesting/{id}/logs`\r\n8. To cancel: `DELETE /v2/backtesting/{id}`\r\n\r\n#### Backtest Wallet and Stake Sizing\r\n\r\nBacktests are simulations. Do **not** size a backtest from the user's live wallet by default; use simulated capital to evaluate the strategy. Only mirror the user's current wallet if they explicitly ask for a live-wallet simulation.\r\n\r\n- `dry_run_wallet` is the total simulated wallet inventory by asset. It is an object/map, not a scalar. Examples: `{ \"USDC\": 1000 }`, `{ \"USDC\": 100, \"BTC\": 0.1 }`.\r\n- `stake_amount` is the amount the backtest/bot may allocate per trade slot. A numeric value is fixed stake per entry slot; `\"unlimited\"` divides the simulated wallet across `max_open_trades` slots.\r\n- If using fixed stake, set `dry_run_wallet` to the total simulated balances so PnL is measured against the correct capital base. Example: a $50 USDC simulation with $45 usable per trade uses `stake_amount: 45` and `dry_run_wallet: { \"USDC\": 50 }`.\r\n- For standard perps, keep fixed `stake_amount` at or below ~90% of `USDC / max_open_trades`; for HIP-3 assets, use ~70% because fees and isolated-margin buffers are higher.\r\n- Never combine `stake_amount: \"unlimited\"` with `max_open_trades: -1`. When stake is unlimited, `max_open_trades` must be a finite positive integer so the wallet can be divided across slots.\r\n- For DCA/grid/scaling strategies that use `position_adjustment_enable` and `adjust_trade_position`, `stake_amount` may be fixed or `\"unlimited\"`. If using `\"unlimited\"`, you must control the initial entry size in `custom_stake_amount`; otherwise the first entry can consume all available capital. In either mode, `dry_run_wallet` must cover the maximum laddered exposure, not just the first entry.\r\n\r\n#### Parameter Sweeps (recommended for first-pass backtests)\r\n\r\nFor the **first** backtest of any new idea on a given pair, do not submit a single config. Submit a **3-variant sweep** that varies ONE parameter, run all 3 in parallel, then compare horizontally.\r\n\r\n**Why:** building a config is the expensive cognitive step; a backtest pod is cheap. A single result tells you whether one point worked; three neighboring points tell you whether the *region* works and which direction to iterate.\r\n\r\n**How to fan out:**\r\n\r\n1. Issue all 3 `POST /v2/backtesting` calls in parallel (different config for each variant; same code unless the variant is a code-level change).\r\n2. Issue all 3 `PUT /v2/backtesting/{id}/status` start calls in parallel.\r\n3. Poll all 3 `GET /v2/backtesting/{id}/status` endpoints in parallel each cycle.\r\n4. Fetch all 3 `GET /v2/backtesting/{id}` results in parallel once status is `completed`.\r\n\r\nEach backtest runs in its own isolated pod, so parallel execution does not slow any single run.\r\n\r\n**What to vary (pick ONE axis per sweep):**\r\n\r\n| Strategy family | Parameter to vary | Three variants |\r\n|---|---|---|\r\n| Momentum / EMA cross | EMA periods | 5/10/20, 8/13/21, 12/26/50 |\r\n| Trend-following | ATR stop multiplier | 2.0, 3.0, 4.0 |\r\n| Mean-reversion (RSI) | Oversold threshold | <25, <30, <35 |\r\n| Bollinger Bands | Std-dev width | 1.5, 2.0, 2.5 |\r\n| Breakout | Lookback window | 20, 50, 100 candles |\r\n\r\n**When NOT to sweep:**\r\n\r\n- The user pinned specific parameter values (\"backtest with EMA 8/21 only\").\r\n- Walk-forward validation on a second pair after a confirmed setup — that should be a single config (sweeping there is parameter overfitting).\r\n- The user is iterating on a known winner (\"now try the same config on ETH\").\r\n\r\n#### Result Interpretation\r\n\r\nAfter status = `completed`, download the `resultUrl` JSON. Present these key metrics:\r\n\r\n- **Total trades** — completed round-trips\r\n- **Win rate** — percentage of profitable trades\r\n- **Total profit %** — net profit as percentage of starting balance\r\n- **Max drawdown** — worst peak-to-trough decline\r\n- **Sharpe ratio** — risk-adjusted return (>1.0 good, >2.0 excellent)\r\n- **Average trade duration** — how long positions are held\r\n\r\n**Before suggesting deployment**, always run a backtest first. If the backtest produced **zero trades** over a timerange that should have generated signals (e.g. weeks on a 5m timeframe), do not offer deployment — the strategy or pair likely has an issue. If PnL is **negative**, note the timerange may be unsuitable but don't dismiss the strategy outright. If PnL is **positive**, present results without overpromising — strong backtest fit can indicate overfitting. Stay neutral and let the user decide.\r\n\r\n#### Sweep Result Comparison\r\n\r\nFor 3-variant sweeps, present results as a single table (Variant | Config | PnL% | Trades | Sharpe | Max DD), then read the shape:\r\n\r\n- **All 3 profitable** → pick the **best Sharpe** (not best PnL — small-sample PnL rewards luck). The parameter region is robust; proceed to walk-forward or deployment.\r\n- **1–2 profitable** → pick the winner, but flag that the parameter is sensitive. Suggest either (a) walk-forward on a second pair as an independent check, or (b) one tighter sweep around the winner.\r\n- **All 3 unprofitable / < 10 trades** → the idea doesn't work on this pair. Move to pair-space (different pair, timeframe, or strategy family). Do not sweep again on the same pair.\r\n- **Monotonic edge** (e.g. PnL strictly improves 2.0 → 3.0 → 4.0) → the best variant sits at the edge of the grid. Run ONE more variant past it (e.g. 5.0) — don't run another full 3-grid; just extend by one.\r\n\r\n**Zero-trade rule for sweeps:** zeros in 1–2 variants of a sweep are *informative* (the parameter was too tight), not a failure. Only treat the sweep as failed when ALL 3 variants return zero trades.\r\n\r\n### Deployment Workflow\r\n\r\n1. `POST /v2/deployment` with config, code, name\r\n2. **Ask the user: live or dry-run?**\r\n   - **Live:** `POST /v2/deployment/{id}/credentials` with `{ \"exchange\": \"hyperliquid\", \"wallet_address\": \"0x...\", \"subaccount_address\": \"0x...\" }` — `wallet_address` and `subaccount_address` are optional; server assigns wallet automatically if omitted\r\n   - **Dry-run:** Skip the credentials step — the deployment runs in simulation mode (no real funds)\r\n3. Run the pre-deployment checklist\r\n4. Show the deployment confirmation summary and wait for explicit user confirmation\r\n5. `PUT /v2/deployment/{id}/status` → `{\"action\": \"start\"}`\r\n6. Monitor: `GET /v2/deployment/{id}/status`, `GET /v2/deployment/{id}/logs`\r\n7. Stop: `PUT /v2/deployment/{id}/status` → `{\"action\": \"stop\"}`\r\n\r\n### Pre-Deployment Checklist (MANDATORY)\r\n\r\nBefore `PUT /v2/deployment/{id}/status` → `{\"action\":\"start\"}`:\r\n\r\n**For live deployments (credentials stored):**\r\n\r\n1. **Credentials stored** — `GET /v2/deployment/{id}` → `credentials_status: \"stored\"`. If not, call `POST /v2/deployment/{id}/credentials`.\r\n2. **Identify wallets** — `GET /v2/deployment/{id}/credentials` → note `wallet_address` (agent wallet) and `agent_wallet_address`.\r\n3. **Funds available** — Check the **main wallet** (platform-managed trading wallet), NOT the agent wallet. Agent wallet having $0 is normal. Query `clearinghouseState` + `spotClearinghouseState` for single deployments. If the master account has sub-accounts, also query `subAccounts2` and sum total balance across master + all sub-accounts — funds allocated to sub-accounts are not available to the master. **Then verify `stake_amount × max_open_trades` fits within the available balance.** The exchange reserves a small fee buffer (~1%), so set `stake_amount` to no more than ~95% of `balance / max_open_trades` to avoid silent trade rejections.\r\n4. **No existing positions/orders** — Check `clearinghouseState` for open positions on the main wallet. If positions or orders exist, show the user details (pair, side, size, PnL) and ask them to close before deploying — leftover positions can block new entries or cause unexpected margin usage.\r\n\r\n**For dry-run deployments (no credentials):** Skip steps 1–4, the deployment runs in simulation mode without real funds.\r\n\r\n5. **Pair is tradeable** — `POST https://api.hyperliquid.xyz/info` → `{\"type\":\"meta\"}` for standard perps, or `{\"type\":\"meta\", \"dex\":\"xyz\"}` (or the relevant dex name) for HIP3 pairs. Verify the coin name exists in the `universe` array.\r\n\r\nDo NOT skip any step or assume it passed without the API call.\r\n\r\n## API Reference\r\n\r\n### Backtesting\r\n\r\n#### POST `/v2/backtesting` — Create Backtest\r\n\r\n```json\r\n// Request\r\n{ \"config\": {}, \"code\": \"string (Python strategy)\", \"timerange\": { \"start\": \"YYYY-MM-DD\", \"end\": \"YYYY-MM-DD\" } }\r\n\r\n// Response (201)\r\n{ \"id\": \"string\", \"status\": \"pending\", \"message\": \"Backtest created. Call PUT /:id/status with action \\\"start\\\" to begin.\" }\r\n```\r\n\r\n`timerange` specifies the historical period to backtest against. Dates are validated against available data — the server returns `invalid_timerange` if the requested period is outside what's available. If invalid dates are provided, the server falls back to a dynamic range based on the timeframe.\r\n\r\n#### PUT `/v2/backtesting/{id}/status` — Start Backtest\r\n\r\n```json\r\n// Request — only \"start\" is supported; to cancel, use DELETE\r\n{ \"action\": \"start\" }\r\n\r\n// Response (200)\r\n{ \"id\": \"string\", \"status\": \"running\", \"previous_status\": \"pending\", \"job_name\": \"backtest-01kjvze9\" }\r\n```\r\n\r\n#### GET `/v2/backtesting/{id}/status` — Poll Status\r\n\r\nResponse: `{ \"id\": \"string\", \"status\": \"pending | running | completed | failed\", \"results\": null }`. `results` is `null` while running — use `resultUrl` from full details for complete results.\r\n\r\n#### GET `/v2/backtesting/{id}` — Full Details\r\n\r\n```json\r\n{\r\n  \"id\": \"string\",\r\n  \"config\": {},\r\n  \"code\": \"string\",\r\n  \"status\": \"pending | running | completed | failed\",\r\n  \"results\": null,\r\n  \"resultUrl\": \"https://storage.googleapis.com/... (signed URL, valid 7 days)\",\r\n  \"started_at\": \"ISO8601\",\r\n  \"completed_at\": \"ISO8601\",\r\n  \"job_name\": \"string\",\r\n  \"created_at\": \"ISO8601\",\r\n  \"updated_at\": \"ISO8601\"\r\n}\r\n```\r\n\r\n#### DELETE `/v2/backtesting/{id}`\r\n\r\nCancels if running and deletes. Response: `{ \"message\": \"Backtest deleted\" }`\r\n\r\n### Deployment\r\n\r\n#### POST `/v2/deployment` — Create Deployment\r\n\r\n```json\r\n// Request\r\n{ \"config\": {}, \"code\": \"string (Python strategy)\", \"name\": \"string\" }\r\n\r\n// Response (201)\r\n{ \"id\": \"string\", \"config\": {}, \"code\": \"string\", \"name\": \"My Strategy\", \"replicas\": 1, \"status\": \"pending\", \"deployment_name\": \"deploy-01kjvx94\", \"created_at\": \"ISO8601\" }\r\n```\r\n\r\n#### PUT `/v2/deployment/{id}/status` — Start or Stop\r\n\r\n```json\r\n// Request\r\n{ \"action\": \"start\" | \"stop\" }\r\n\r\n// Response (200)\r\n{ \"id\": \"string\", \"status\": \"running | stopped\", \"previous_status\": \"string\" }\r\n```\r\n\r\n**On stop:** The platform automatically cancels all open orders and closes all positions on Hyperliquid before stopping the pod.\r\n\r\n#### GET `/v2/deployment/{id}` — Full Details\r\n\r\n```json\r\n{\r\n  \"id\": \"string\",\r\n  \"config\": {},\r\n  \"code\": \"string\",\r\n  \"name\": \"string\",\r\n  \"replicas\": 1,\r\n  \"status\": \"pending | running | stopped\",\r\n  \"pods\": [{ \"name\": \"string\", \"status\": \"Running\", \"restarts\": 0 }],\r\n  \"credentials_status\": \"stored | missing\",\r\n  \"exchange\": \"hyperliquid\",\r\n  \"subaccount_address\": \"0x... | undefined\",\r\n  \"deployment_name\": \"string\",\r\n  \"namespace\": \"string\",\r\n  \"created_at\": \"ISO8601\",\r\n  \"updated_at\": \"ISO8601\"\r\n}\r\n```\r\n\r\n#### GET `/v2/deployment/{id}/status` — Live Status\r\n\r\nResponse: `{ \"id\": \"string\", \"status\": \"string\", \"replicas\": 1, \"available_replicas\": 1, \"pods\": null }`\r\n\r\n#### POST `/v2/deployment/{id}/credentials` — Store Credentials\r\n\r\n`exchange` required. `wallet_address` optional. `private_key` is **NOT accepted**.\r\n\r\n```json\r\n// Request\r\n{ \"exchange\": \"hyperliquid\", \"wallet_address\": \"0x... (optional)\", \"subaccount_address\": \"0x... (optional)\" }\r\n\r\n// Response (200)\r\n{\r\n  \"id\": \"string\", \"credentials_status\": \"stored\", \"exchange\": \"hyperliquid\",\r\n  \"wallet_address\": \"0x...\", \"wallet_source\": \"main_trading_wallet | provided\",\r\n  \"agent_wallet_address\": \"0x... | undefined\",\r\n  \"subaccount_address\": \"0x... | undefined\", \"updated_at\": \"ISO8601\"\r\n}\r\n```\r\n\r\n**IMPORTANT:** `wallet_address` in the response is the wallet that signs trades. It does NOT need its own funds — it trades against the main wallet's balance.\r\n\r\n**Errors:** `400 invalid_request` (private_key sent), `400 invalid_wallet_address`, `400 duplicate_wallet_address`, `400 unsupported_exchange`, `400 no_wallet_available`, `403 wallet_not_owned`, `500 server_misconfigured`\r\n\r\n**Idempotent:** Once credentials are stored, calling again returns existing credentials unchanged — it will NOT update or overwrite. To change wallets, delete and recreate the deployment.\r\n\r\n**Credential update procedure:** (1) Stop the deployment → (2) Delete the deployment → (3) Create a new deployment with same config/code → (4) Store new credentials.\r\n\r\n**One-wallet-per-deployment rule:** Each deployment uses one wallet and runs as an isolated container. For multiple strategies on the same wallet, use multiple deployments pointing to the same wallet address.\r\n\r\n### Portfolio Exit\r\n\r\n#### POST `/v2/portfolio/hyperliquid/exit` — Close Positions and Repatriate Funds\r\n\r\nCloses ALL open positions and repatriates all funds from a sub-account back to the main wallet in a single call. Use this to cleanly exit a sub-account deployment and return funds to the master account.\r\n\r\n**Requires:** `subaccount_address` in request body.\r\n\r\n```json\r\n// Request\r\n{ \"subaccount_address\": \"0x...\" }\r\n\r\n// Response (200)\r\n{ \"message\": \"Exit successful\", \"positions_closed\": 2, \"orders_cancelled\": 0 }\r\n\r\n// Response (400) — invalid subaccount\r\n{ \"error\": \"invalid_request\", \"message\": \"...\" }\r\n```\r\n\r\nThis endpoint:\r\n1. Cancels all open orders on the sub-account\r\n2. Closes all open positions at market price\r\n3. Transfers all remaining funds (USDC, USDE, USDT0, USDH) back to the main wallet\r\n\r\nUse this instead of manually closing positions and transferring funds — it's a single atomic operation.\r\n\r\n#### GET `/v2/deployment/{id}/credentials` — Credential Info\r\n\r\nDoes NOT return private keys. Response: `{ \"id\", \"credentials_status\": \"stored | missing\", \"exchange\", \"wallet_address\", \"wallet_source\": \"main_trading_wallet | provided\", \"wallet_type\": \"main_wallet | agent_wallet\", \"agent_wallet_address\", \"subaccount_address\" }`. If missing: `{ \"credentials_status\": \"missing\" }`.\r\n\r\n#### POST `/v2/deployment/{id}/exit` — Exit All Positions\r\n\r\nCloses all open orders and liquidates all open positions. Deployment must be **stopped** first.\r\n\r\n**Before calling this endpoint**, check `clearinghouseState` for the wallet's open positions. Show the user each position's pair, side, size, and unrealized PnL, then ask for explicit confirmation — this action is irreversible and closes at market price.\r\n\r\n```json\r\n// Response (200)\r\n{ \"id\": \"string\", \"status\": \"string\", \"orders_cancelled\": 3, \"positions_closed\": 2 }\r\n\r\n// Response (400) — deployment still running or credentials missing\r\n{ \"error\": \"invalid_request\", \"message\": \"...\" }\r\n```\r\n\r\n#### DELETE `/v2/deployment/{id}`\r\n\r\nCloses all positions and orders on Hyperliquid before deleting. Response: `{ \"message\": \"Deployment deleted\" }`. Deleting stopped deployments may return 500 — safe to ignore.\r\n\r\n### Shared API Notes\r\n\r\n#### Logs — GET `/v2/backtesting/{id}/logs` and `/v2/deployment/{id}/logs`\r\n\r\nQuery: `pageSize` (default 100), `pageToken`. Response: `{ \"items\": [{ \"timestamp\": \"ISO8601\", \"message\": \"string\", \"severity\": \"string\" }], \"nextCursor\": \"string | null\" }`\r\n\r\n#### Paginated Lists\r\n\r\nBoth `GET /v2/backtesting` and `GET /v2/deployment` return `{ \"items\": [], \"nextCursor\": \"string | null\" }`. Pass `cursor` query param to paginate.\r\n\r\n#### Error Responses\r\n\r\n```json\r\n// 401 — Missing/invalid API key\r\n{ \"message\": \"No API key found in request\", \"request_id\": \"string\" }\r\n\r\n// 400 — Validation error\r\n{ \"error\": \"validation_failed\", \"message\": \"Invalid request\", \"details\": [{ \"path\": \"field\", \"message\": \"...\" }] }\r\n\r\n// 404 — Not found\r\n{ \"error\": \"not_found\", \"message\": \"Backtest not found\" }\r\n```\r\n\r\n## Config and Strategy Authoring\r\n\r\n### Config Reference\r\n\r\nThe config object is a Freqtrade trading bot configuration. Do not include `api_server` (platform-managed). To run in **dry-run/paper mode**, skip the credentials step — a deployment without credentials trades in simulation. Do not set `dry_run` manually in config.\r\n\r\n#### Futures Config (recommended)\r\n\r\n```json\r\n{\r\n  \"exchange\": { \"name\": \"hyperliquid\", \"pair_whitelist\": [\"BTC/USDC:USDC\"] },\r\n  \"stake_currency\": \"USDC\",\r\n  \"stake_amount\": 100,\r\n  \"dry_run_wallet\": { \"USDC\": 1000 },\r\n  \"timeframe\": \"5m\",\r\n  \"max_open_trades\": 3,\r\n  \"minimal_roi\": { \"0\": 100.0 },\r\n  \"stoploss\": -0.1,\r\n  \"trading_mode\": \"futures\",\r\n  \"margin_mode\": \"cross\",\r\n  \"entry_pricing\": { \"price_side\": \"same\", \"price_last_balance\": 0.0 },\r\n  \"exit_pricing\": { \"price_side\": \"same\", \"price_last_balance\": 0.0 },\r\n  \"pairlists\": [{ \"method\": \"StaticPairList\" }]\r\n}\r\n```\r\n\r\n#### Spot Config\r\n\r\nSame as futures but omit `trading_mode` and `margin_mode`. Pairs use `BTC/USDC` format (no `:USDC` suffix). Stoploss on exchange not supported for spot.\r\n\r\n#### HIP3 Config Example\r\n\r\n```json\r\n{\r\n  \"exchange\": {\r\n    \"name\": \"hyperliquid\",\r\n    \"pair_whitelist\": [\"XYZ-AAPL/USDC:USDC\"]\r\n  },\r\n  \"stake_currency\": \"USDC\",\r\n  \"stake_amount\": 100,\r\n  \"dry_run_wallet\": { \"USDC\": 1000 },\r\n  \"timeframe\": \"15m\",\r\n  \"max_open_trades\": 3,\r\n  \"minimal_roi\": { \"0\": 100.0 },\r\n  \"stoploss\": -0.05,\r\n  \"trading_mode\": \"futures\",\r\n  \"margin_mode\": \"isolated\",\r\n  \"entry_pricing\": { \"price_side\": \"same\", \"price_last_balance\": 0.0 },\r\n  \"exit_pricing\": { \"price_side\": \"same\", \"price_last_balance\": 0.0 },\r\n  \"pairlists\": [{ \"method\": \"StaticPairList\" }]\r\n}\r\n```\r\n\r\n#### Additional Config Fields\r\n\r\nOther common config fields include `trailing_stop` (boolean), `trailing_stop_positive` (number), `entry_pricing.price_side` / `exit_pricing.price_side` (`\"ask\"`, `\"bid\"`, `\"same\"`, `\"other\"`), and `pairlists` (`StaticPairList`, `VolumePairList`, etc.). Use `\"same\"` as the default pricing side. `\"other\"` crosses the spread for faster fills and is mainly appropriate when intentionally modeling market-order-style execution.\r\n\r\n### Strategy Code Template\r\n\r\nThe `code` field must be valid Python with a strategy class. Class name must end with `Strategy` in PascalCase. Use `import talib.abstract as ta` for indicators.\r\n\r\n```python\r\nfrom freqtrade.strategy import IStrategy\r\nimport pandas as pd\r\nimport talib.abstract as ta\r\n\r\n\r\nclass MyCustomStrategy(IStrategy):\r\n    minimal_roi = {\"0\": 0.10, \"30\": 0.05, \"120\": 0.02}\r\n    stoploss = -0.10\r\n    trailing_stop = False\r\n    timeframe = '5m'\r\n    process_only_new_candles = True\r\n    startup_candle_count = 20\r\n\r\n    def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:\r\n        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)\r\n        dataframe['sma_20'] = ta.SMA(dataframe, timeperiod=20)\r\n        return dataframe\r\n\r\n    def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:\r\n        dataframe.loc[\r\n            (dataframe['rsi'] < 30) & (dataframe['close'] > dataframe['sma_20']),\r\n            'enter_long'\r\n        ] = 1\r\n        return dataframe\r\n\r\n    def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:\r\n        dataframe.loc[(dataframe['rsi'] > 70), 'exit_long'] = 1\r\n        return dataframe\r\n```\r\n\r\n**Requirements:** Must use standard imports/inheritance (see template), `import talib.abstract as ta` for indicators, define `populate_indicators`, `populate_entry_trend`, `populate_exit_trend`.\r\n\r\n### Multi-Output TA-Lib Functions (CRITICAL)\r\n\r\nSome TA-Lib functions return **multiple columns**. Assigning directly to one column causes a runtime crash.\r\n\r\n| Function                    | Returns                                |\r\n| --------------------------- | -------------------------------------- |\r\n| `ta.BBANDS`                 | `upperband`, `middleband`, `lowerband` |\r\n| `ta.MACD`                   | `macd`, `macdsignal`, `macdhist`       |\r\n| `ta.STOCH`                  | `slowk`, `slowd`                       |\r\n| `ta.STOCHF` / `ta.STOCHRSI` | `fastk`, `fastd`                       |\r\n| `ta.AROON`                  | `aroondown`, `aroonup`                 |\r\n| `ta.HT_PHASOR`              | `inphase`, `quadrature`                |\r\n| `ta.MAMA`                   | `mama`, `fama`                         |\r\n| `ta.MINMAXINDEX`            | `minidx`, `maxidx`                     |\r\n\r\n```python\r\n# WRONG — runtime crash\r\ndataframe[\"bb_upper\"] = ta.BBANDS(dataframe, timeperiod=20)\r\n\r\n# CORRECT\r\nbb = ta.BBANDS(dataframe, timeperiod=20)\r\ndataframe[\"bb_upper\"] = bb[\"upperband\"]\r\ndataframe[\"bb_middle\"] = bb[\"middleband\"]\r\ndataframe[\"bb_lower\"] = bb[\"lowerband\"]\r\n\r\nmacd = ta.MACD(dataframe)\r\ndataframe[\"macd\"] = macd[\"macd\"]\r\ndataframe[\"macd_signal\"] = macd[\"macdsignal\"]\r\ndataframe[\"macd_hist\"] = macd[\"macdhist\"]\r\n\r\nstoch = ta.STOCH(dataframe)\r\ndataframe[\"slowk\"] = stoch[\"slowk\"]\r\ndataframe[\"slowd\"] = stoch[\"slowd\"]\r\n```\r\n\r\nSingle-output functions (RSI, SMA, EMA, ATR, ADX) return a Series and can be assigned directly.\r\n\r\n### Multi-Entry Strategies — DCA, Grid, Scaling-In\r\n\r\nThe engine enforces **one open trade per pair**. A second `enter_long = 1` while a position is open is silently rejected. Anything that wants to \"buy more of the same thing\" — DCA, scaling-in, grid laddering, weekly buys — must use `adjust_trade_position`, not repeated entry signals.\r\n\r\nConfig and strategy code must be set together. If using dynamic stake, keep `max_open_trades` finite and divide the initial entry in `custom_stake_amount` so later adjustment orders have wallet room.\r\n\r\n```python\r\nclass MyStrategy(IStrategy):\r\n    position_adjustment_enable = True    # required for adjust_trade_position to fire\r\n    max_entry_position_adjustment = 5    # cap on additional entries (-1 = unlimited)\r\n    max_dca_multiplier = 6.0             # initial size × (1 + planned adds)\r\n\r\n    def custom_stake_amount(self, pair, current_time, current_rate, proposed_stake,\r\n                            min_stake, max_stake, leverage, entry_tag, side, **kwargs):\r\n        # MANDATORY: divide initial entry so room remains for future adds.\r\n        return proposed_stake / self.max_dca_multiplier\r\n```\r\n\r\nFixed `stake_amount` is also valid with position adjustment, but the wallet must still have enough free balance for the planned additional entries. With `\"unlimited\"` stake, `custom_stake_amount` is mandatory to avoid allocating the whole wallet to the initial order.\r\n\r\n`adjust_trade_position` is called very frequently while a trade is open: in dry-run/live it runs every bot loop (about every 5 seconds by default), while backtesting runs it once per candle (`timeframe` or `timeframe_detail`). Return positive = add stake, negative = partial close, `None` = do nothing. Keep the logic strict and always check the last filled order / open orders so the bot cannot re-enter repeatedly while one condition remains true.\r\n\r\n**Pattern A — Profit-driven DCA (averaging down):**\r\n\r\n```python\r\ndef adjust_trade_position(self, trade, current_time, current_rate, current_profit,\r\n                          min_stake, max_stake, *args, **kwargs):\r\n    if trade.has_open_orders:\r\n        return None\r\n    n_entries = trade.nr_of_successful_entries\r\n    if n_entries <= self.max_entry_position_adjustment and current_profit <= -0.025 * n_entries:\r\n        first_stake = trade.select_filled_orders(trade.entry_side)[0].stake_amount_filled\r\n        return (first_stake, f\"dca_buy_{n_entries}\")\r\n    return None\r\n```\r\n\r\n**Pattern B — Schedule-driven DCA (weekly / daily fixed-time buys).** Gate on `current_time.weekday()` / `.hour`. **Critical**: include a same-day guard, otherwise the initial entry's Monday and `adjust_trade_position`'s Monday collide and double-buy:\r\n\r\n```python\r\ndef adjust_trade_position(self, trade, current_time, current_rate, current_profit,\r\n                          min_stake, max_stake, *args, **kwargs):\r\n    if trade.has_open_orders:\r\n        return None\r\n    if current_time.weekday() != 0:  # Monday only\r\n        return None\r\n    filled = trade.select_filled_orders(trade.entry_side)\r\n    if filled and filled[-1].order_filled_utc.date() == current_time.date():\r\n        return None  # same-day guard\r\n    first_stake = filled[0].stake_amount_filled\r\n    return (first_stake, \"weekly_dca\")\r\n```\r\n\r\n**Pattern C — Grid / range fade with laddered buys + partial profits:**\r\n\r\n```python\r\ndef adjust_trade_position(self, trade, current_time, current_rate, current_profit,\r\n                          min_stake, max_stake, *args, **kwargs):\r\n    if trade.has_open_orders:\r\n        return None\r\n    n_entries = trade.nr_of_successful_entries\r\n    n_exits = trade.nr_of_successful_exits\r\n    # Ladder buys at every -1% drawdown, up to 5 rungs\r\n    if n_entries <= 5 and current_profit <= -0.01 * n_entries:\r\n        first = trade.select_filled_orders(trade.entry_side)[0].stake_amount_filled\r\n        return (first, f\"grid_buy_{n_entries}\")\r\n    # Partial profit-takes at every +1.5% above avg, up to 3\r\n    if n_exits < 3 and current_profit >= 0.015 * (n_exits + 1):\r\n        return (-(trade.stake_amount / 4.0), f\"grid_tp_{n_exits}\")\r\n    return None\r\n```\r\n\r\nA true 20-rung grid (multiple simultaneous orders at distinct price levels) is NOT supported by Freqtrade. Pattern C is the closest faithful approximation — describe it as \"laddered range fade\" not \"20-level grid.\"\r\n\r\n**Hyperliquid minimum: $10 per order.** Engine inflates by stoploss reserve (up to 1.5x) — always use `min_stake` as a floor.\r\n\r\n`max_open_trades` limits total concurrent trades across all pairs, not entries per pair.\r\n\r\n### Funding Rate (Futures Only)\r\n\r\nFor \"harvest negative funding\" / \"long when shorts pay longs\" / any funding-aware strategy, the historical funding rate is **automatically downloaded** for backtest. Do not poll Hyperliquid's REST API from inside the strategy. Hyperliquid pays funding hourly. The example below assumes the strategy timeframe is `1h` or faster; do not merge a faster funding timeframe into a slower strategy timeframe without first resampling/alignment:\r\n\r\n```python\r\nfrom freqtrade.strategy import merge_informative_pair\r\n\r\n\r\ndef populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:\r\n    funding_tf = \"1h\"\r\n    funding = self.dp.get_pair_dataframe(\r\n        pair=metadata[\"pair\"],\r\n        timeframe=funding_tf,\r\n        candle_type=\"funding_rate\",\r\n    )\r\n    if not funding.empty and \"open\" in funding.columns:\r\n        funding = funding[[\"date\", \"open\"]].rename(columns={\"open\": \"funding_rate\"})\r\n        dataframe = merge_informative_pair(\r\n            dataframe,\r\n            funding,\r\n            self.timeframe,\r\n            funding_tf,\r\n            ffill=True,\r\n        )\r\n        dataframe[\"funding_rate\"] = dataframe[f\"funding_rate_{funding_tf}\"].fillna(0.0)\r\n        dataframe[\"funding_apr\"] = dataframe[\"funding_rate\"] * 24 * 365\r\n    else:\r\n        dataframe[\"funding_rate\"] = 0.0\r\n        dataframe[\"funding_apr\"] = 0.0\r\n    return dataframe\r\n```\r\n\r\nAvailable only for futures pairs (`BTC/USDC:USDC`), not spot.\r\n\r\n### Required Config Fields\r\n\r\nThe schema validator rejects payloads that omit any of these — **even when the strategy class declares its own equivalent**:\r\n\r\n- `entry_pricing` and `exit_pricing` — both required. Safe default: `{\"price_side\": \"same\", \"price_last_balance\": 0.0}`.\r\n- `minimal_roi` — required at the config level. Use `{\"0\": 100.0}` to effectively disable config-level ROI and let the strategy's own exit logic run.\r\n- `dry_run_wallet` — must contain enough `stake_currency` balance for the configured `stake_amount` and `max_open_trades`, **plus ~50% buffer** to cover fees, funding payments, and slippage. For `stake_amount: 1000` and `max_open_trades: 1`, use at least `{ \"USDC\": 1500 }`. For futures multi-pair setups, scale up by `max_open_trades`. Tighter buffers (≤10%) cause silent signal rejection mid-run. For DCA / grid strategies that ladder up to `max_dca_multiplier × initial`, set `dry_run_wallet ≈ stake_amount × 10`. See the \"Backtest Wallet and Stake Sizing\" section above for the full sizing rationale.\r\n\r\n### Choosing a `minimal_roi` shape\r\n\r\nThe class-level `minimal_roi = {\"0\": 100.0}` pattern fully disables ROI take-profit.\r\nUse it ONLY when your strategy has a signal-driven exit (`populate_exit_trend`) that\r\nfires on most bars where the trade should close — typically trend-follow strategies\r\nwith structural exits like \"break of N-bar high\" or trailing stops.\r\n\r\nFor mean-reversion, scalp, range, and any strategy where wins are small (under ~3%),\r\nuse an explicit ROI ladder:\r\n\r\n```python\r\nminimal_roi = {\r\n    \"0\":    0.025,   # take 2.5% immediately if available\r\n    \"240\":  0.015,   # 1.5% after 4 hours (relevant for 1h+ timeframes)\r\n    \"720\":  0.005,   # 0.5% after 12 hours\r\n    \"1440\": 0,       # breakeven after 24 hours — close any open position\r\n}\r\n```\r\n\r\nThe keys are **minutes since trade open**. Tiers decay so stale trades close at breakeven\r\nrather than sitting forever. Without an ROI ladder, mean-reversion strategies give back\r\nwins waiting for a signal exit that may never come.\r\n\r\nSee `optimizations/dsl-exit-engine.md` for full Phase 0 / Phase 1 / Phase 2 guidance.\r\n\r\n### `stake_amount: \"unlimited\"` Warning\r\n\r\n`\"unlimited\"` bypasses minimum-order validation. The bot starts but **silently executes zero trades** if balance is insufficient — no error, just heartbeats. For simple single-entry strategies, prefer explicit numeric `stake_amount` with small balances (<$50). For strategies using `position_adjustment_enable` and `adjust_trade_position`, fixed stake is valid if enough wallet balance remains for planned adds; if `stake_amount` is `\"unlimited\"`, use `custom_stake_amount` to divide the first entry so there is room for later adds.\r\n\r\nDo **not** set both `stake_amount: \"unlimited\"` and `max_open_trades: -1`. Use a finite positive `max_open_trades` instead. For single-pair DCA/grid/scaling strategies, use `max_open_trades: 1`; repeated same-pair entries come from `adjust_trade_position`, not extra open-trade slots.\r\n\r\n| Stoploss | Effective minimum |\r\n| -------- | ----------------- |\r\n| -0.5%    | ~$10.55           |\r\n| -5%      | ~$11.05           |\r\n| -10%     | ~$11.67           |\r\n| -30%     | ~$15.00           |\r\n\r\n## Operations and Troubleshooting\r\n\r\n### Reporting DCA Trades\r\n\r\nFor DCA strategies: distinguish trades from orders (\"X trades, Y buy orders, Z sell orders\"), show per-order detail for at least the first trade, flag minimum order rejections or dust positions. Always download `resultUrl` for full order-level data. Skip breakdown for non-DCA strategies.\r\n\r\n### Log Interpretation\r\n\r\n- **Heartbeat messages are normal** — the bot sends periodic heartbeats to confirm it's alive\r\n- **\"Analyzing candle\"** — bot is checking strategy conditions on the latest candle\r\n- **\"Buying\"/\"Selling\"** — trade execution\r\n- **Rate limit warnings** — reduce API calls, consider stopping if persistent\r\n- **Websocket disconnection (\"Couldn't reuse watch…falling back to REST api\")** — normal and expected. The bot automatically reconnects via REST API. Trading is **not** affected. Do not treat this as an error or suggest redeployment.\r\n\r\n### Diagnosing Zero-Trade Deployments\r\n\r\nCheck in order:\r\n\r\n1. **Main wallet balance** — agent wallet $0 is normal; check the platform-managed main wallet\r\n2. **`stake_amount`** — for simple single-entry strategies, if `\"unlimited\"` with a small balance, redeploy with an explicit numeric amount slightly below balance. For `position_adjustment_enable` / `adjust_trade_position` strategies, either use fixed stake with enough wallet room for planned adds, or keep `stake_amount: \"unlimited\"` and reduce `custom_stake_amount`, ladder count, or total planned exposure.\r\n3. **Credentials** — verify `credentials_status: \"stored\"` and `WALLET_ADDRESS` in startup logs\r\n4. **Strategy conditions** — check if entry conditions are met on recent candles\r\n5. **Logs** — check for rate limits, exchange rejections, pair errors\r\n6. **Pair validity** — verify pair is active on Hyperliquid\r\n\r\n### Rate Limit Mitigation\r\n\r\nHyperliquid enforces rate limits. Aggressive retries, tight loops, or extra exchange traffic from strategy code can trigger **429** responses and unstable behavior.\r\n\r\n**Prevention:**\r\n\r\n- Set `process_only_new_candles = True` so the bot does not reprocess every candle unnecessarily\r\n- Prefer candle-close pricing for exits where it fits the strategy (fewer edge-case order updates)\r\n- Do not add **custom polling** of Hyperliquid’s API (or other heavy network work) inside hot strategy paths — it stacks on top of normal bot traffic\r\n\r\n**If you see rate limits or 429s in logs:**\r\n\r\n- Avoid rapid stop/start cycles; that often worsens retries against the limit\r\n- After the deployment stops, wait several minutes before starting again; if the issue persists, simplify the strategy or reduce anything that drives extra exchange requests\r\n\r\n### Orphan Position Handling\r\n\r\nWhen a bot crashes, it may leave open positions that lock up margin. Strategy code pattern:\r\n\r\n- In `bot_loop_start()`, check for positions not in the bot's trade database\r\n- Close orphans with a limit order before entering fresh\r\n- Use a flag (`_orphan_closed`) to run cleanup exactly once per lifecycle\r\n\r\n### Backtest `limit_exceeded` Error\r\n\r\nIf you get a `limit_exceeded` error when creating a backtest, the user has hit the concurrent backtest limit. Delete completed/failed backtests first: `DELETE /v2/backtesting/{id}`\r\n\r\n### Timezone Reminder\r\n\r\nAll API timestamps are in **UTC (ISO8601)**. Convert to the user's local timezone when presenting times conversationally. If timezone is unknown, show both UTC and ask.\r\n","tags":{"latest":"4.4.6"},"stats":{"comments":0,"downloads":738,"installsAllTime":0,"installsCurrent":0,"stars":0,"versions":16},"createdAt":1774376429099,"updatedAt":1779098114784},"latestVersion":{"version":"4.4.6","createdAt":1779098099786,"changelog":"Restore display name to 'Superior Trade'. Content identical to 4.4.5 (validated strategies + regime-overlay + dsl-exit-engine + minimal_roi ladder guidance).","license":"MIT-0"},"metadata":{"setup":[{"key":"SUPERIOR_TRADE_API_KEY","required":true}],"os":null,"systems":null},"owner":{"handle":"superior-ai","userId":"s176a46hwrqn38f05j90yrnww583h5w0","displayName":"Superior-AI","image":"https://avatars.githubusercontent.com/u/266557195?v=4"},"moderation":{"isSuspicious":false,"isMalwareBlocked":false,"verdict":"clean","reasonCodes":["review.llm_review"],"summary":"Review: review.llm_review","engineVersion":"v2.4.24","updatedAt":1780090834146}}