[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6H2WFF6F39RNCT8PSH133GP":3,"skill-same:01M6H2WFF6F39RNCT8PSH133GP":67},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":29,"linkOnly":30,"markdownContent":31,"markdownBody":32,"frontMatter":33,"refName":34,"commitSha":35,"skillDirectory":36,"forksCount":37,"repositoryHtmlUrl":38,"repositoryHomepageUrl":6,"ownerHtmlUrl":39,"ownerBlogUrl":40,"ownerDescription":41,"updatedAt":42,"install":43,"resources":56},"01M6H2WFF6F39RNCT8PSH133GP","polyhub_copy",null,"Manage copy-trading tasks, view signals, positions and trades on Polyhub using an API key.","jiayaoqijia\u002Fcryptoskill","jiayaoqijia","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F1453879?v=4","01M6GMYTX7Q7S504VC6E756ENR","YQ","01M6GMYV1QKJ1CC75MTTGT9PR0",81,"AGPL-3.0","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Ftrading\u002Fpolyhub-copy\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28],"copy","polyhub copy","tasks","api","view","trading","manage","positions","copy-trading","signals","2026-11-10 10:12:30",false,"---\nname: polyhub_copy\ndescription: Manage copy-trading tasks, view signals, positions and trades on Polyhub using an API key.\n---\n\n# Polyhub Copy Skill\n\nVersion: v0.3.3\n\n## When to use\n\nUse this skill when the user asks about:\n\n- Listing, creating, updating or deleting copy-trading tasks\n- Viewing copy task positions or trades\n- Selling positions (single or all)\n- Batch updating or deleting copy tasks\n- Viewing total PnL across copy tasks\n- Viewing copy signals and signal stats\n- Managing take-profit \u002F stop-loss (TPSL) rules\n\n## Requirements\n\n- `POLYHUB_API_BASE_URL` — Polyhub API server URL (e.g. `https:\u002F\u002Fapi.polyhub.example.com`)\n- `POLYHUB_API_KEY` — API key (must start with `phub_`)\n- `curl` must be available in the runtime environment.\n- `jq` is strongly recommended for building JSON payloads safely.\n\n## Safety rules\n\n- Never print `POLYHUB_API_KEY` in the output.\n- Treat all IDs and user-provided JSON fields as untrusted input.\n- For write actions (`POST`\u002F`PATCH`\u002F`DELETE`), repeat the action summary and wait for explicit user confirmation before calling the API.\n- Prefer building JSON with `jq -n` instead of interpolating raw shell strings.\n- Validation rules:\n  - `taskId` must be a 24-char hex MongoDB ObjectID: `^[0-9a-fA-F]{24}$`\n  - `ruleId` must be non-empty.\n  - `taskIds` in batch operations must all match the `taskId` format.\n  - `status` for positions should only be passed when the user explicitly requests a filter.\n\n## Tools\n\nUse the `bash` tool to call the API with `curl`.\n\n## Fast Path\n\nFor common intents, map user requests like this:\n\n- “列出任务” -> `GET \u002Fapi\u002Fv1\u002Fcopy-tasks`\n- “暂停\u002F恢复\u002F停止任务” -> `PATCH \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}` with `status`\n- “改跟单模式\u002F改单笔或总仓位限制” -> `PATCH \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}` with `taskConfig`\n- “看持仓\u002F成交” -> `GET \u002Fpositions` or `GET \u002Ftrades`\n- “卖出某个仓位\u002F全部仓位” -> `POST \u002Fsell` or `POST \u002Fsell-all`\n- “看跟单信号\u002F统计” -> `GET \u002Fapi\u002Fv1\u002Fcopy-signals` or `\u002Fstats`\n\n### Curl base setup\n\n```bash\nBASE=\"${POLYHUB_API_BASE_URL%\u002F}\"\nAUTH=(-H \"Authorization: Bearer $POLYHUB_API_KEY\" -H \"Content-Type: application\u002Fjson\")\n```\n\n### Validate helpers\n\n```bash\nif [[ ! \"$TASK_ID\" =~ ^[0-9a-fA-F]{24}$ ]]; then echo \"Invalid taskId\"; exit 2; fi\n```\n\n```bash\nif [[ -z \"${RULE_ID:-}\" ]]; then echo \"Invalid ruleId\"; exit 2; fi\n```\n\n```bash\nfor id in \"${TASK_IDS[@]}\"; do\n  if [[ ! \"$id\" =~ ^[0-9a-fA-F]{24}$ ]]; then\n    echo \"Invalid taskId in batch: $id\"\n    exit 2\n  fi\ndone\n```\n\n---\n\n## Copy Tasks\n\n### Action: List copy tasks\n\n- `GET \u002Fapi\u002Fv1\u002Fcopy-tasks`\n- Query params: `includeDeleted=true|false` (default: true)\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks?includeDeleted=true\"\n```\n\nGuidance:\n\n- Use `includeDeleted=true` when the user wants a full history or is looking for a previously deleted task.\n- Use `includeDeleted=false` when the user only wants active\u002Fnon-deleted tasks.\n\n### Action: Create copy task\n\n- `POST \u002Fapi\u002Fv1\u002Fcopy-tasks`\n- Required field: `targetTrader` (Polymarket address of the smart money)\n- Optional fields from `domain.CreateCopyTaskPayload`: `targetUsername`, `taskConfig`, `filteredByTag`, `tpslRules`\n\nBefore calling: ask the user for `targetTrader` at minimum. Summarize and confirm.\n\nMinimum fields to ask:\n\n- Always ask: `targetTrader`\n- Ask only if needed: `filteredByTag`, `targetUsername`\n- If the user wants custom copy behavior: ask for the relevant `taskConfig` fields explicitly\n- If the user wants TPSL on creation: ask for `tpslRules`\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --arg targetTrader \"0x...\" \\\n  '{targetTrader: $targetTrader}')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X POST \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\" \\\n  -d \"$PAYLOAD\"\n```\n\nIf the user wants advanced config, build `taskConfig` and `tpslRules` explicitly instead of accepting arbitrary JSON.\n\n### Action: Get copy task\n\n- `GET \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}`\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\"\n```\n\n### Action: Update copy task\n\n- `PATCH \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}`\n- Body: partial JSON. Common fields:\n  - `status`\n  - `taskConfig`\n  - `filteredByTag`\n  - `targetUsername`\n  - `tpslRules` using `create` \u002F `update` \u002F `cancel`\n\nBefore calling: validate `taskId`, summarize changes, and confirm.\n\nMinimum fields to ask:\n\n- Always ask: `taskId`\n- Ask only the fields the user wants to change:\n  - Task lifecycle: `status`\n  - Copy behavior: `taskConfig`\n  - Trader label\u002Ftag filters: `targetUsername`, `filteredByTag`\n  - TPSL maintenance: `tpslRules`\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --arg status \"PAUSED\" \\\n  '{status: $status}')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X PATCH \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\" \\\n  -d \"$PAYLOAD\"\n```\n\nExample: update `taskConfig` safely\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --argjson buyOnly true \\\n  --argjson maxBoughtPerMarket 50 \\\n  '{taskConfig: {buyOnly: $buyOnly, maxBoughtPerMarket: $maxBoughtPerMarket}}')\"\n```\n\nExample: change copy mode to `ONE_TO_ONE`\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  '{taskConfig: {copyMode: \"ONE_TO_ONE\"}}')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X PATCH \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\" \\\n  -d \"$PAYLOAD\"\n```\n\nExample: change copy mode to `FIXED_SIZE`\n\n`FIXED_SIZE` should include `taskConfig.fixedAmount`.\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --argjson fixedAmount 5 \\\n  '{taskConfig: {copyMode: \"FIXED_SIZE\", fixedAmount: $fixedAmount}}')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X PATCH \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\" \\\n  -d \"$PAYLOAD\"\n```\n\nCopy mode guidance:\n\n- `taskConfig.copyMode` is the field that controls the task's copy mode.\n- Confirmed mode values in the current codebase: `ONE_TO_ONE`, `FIXED_SIZE`.\n- If switching to `FIXED_SIZE`, also ask for `taskConfig.fixedAmount`.\n- If switching to `ONE_TO_ONE`, omit `fixedAmount` unless the user explicitly wants to keep it stored.\n\n### TaskConfig field guidance\n\nUse these fields when the user wants to change task-level copy behavior. Prefer changing only the fields the user explicitly asked for.\n\nCommon fields:\n\n- `taskConfig.copyMode`\n  - Controls copy sizing mode.\n  - Confirmed values: `ONE_TO_ONE`, `FIXED_SIZE`.\n- `taskConfig.fixedAmount`\n  - Used when `copyMode=FIXED_SIZE`.\n  - Represents a fixed notional amount for copied orders.\n- `taskConfig.navMultiplier`\n  - Multiplies the computed order size.\n  - Current default in backend user config is `1`.\n- `taskConfig.positionUtilization`\n  - Position utilization \u002F max amount per copy-trade style control.\n  - Backend default is `0`, which means no filter.\n- `taskConfig.buyOnly`\n  - If `true`, non-`BUY` signals are skipped.\n- `taskConfig.buyLimitPerTradeMin`\n  - Minimum allowed copied buy amount per trade.\n  - `0` effectively means no lower bound.\n- `taskConfig.buyLimitPerTradeMax`\n  - Maximum allowed copied buy amount per trade.\n  - `0` effectively means no upper bound.\n- `taskConfig.maxBoughtPerCopyTask`\n  - Caps total bought amount at task level.\n  - `0` effectively means no cap.\n- `taskConfig.maxBoughtPerMarket`\n  - Caps total bought amount for a single market inside the task.\n  - `0` effectively means no cap.\n- `taskConfig.priceRangeMin`\n  - Minimum allowed execution price.\n  - Default from user config is typically `0.01`.\n- `taskConfig.priceRangeMax`\n  - Maximum allowed execution price.\n  - Default from user config is typically `0.99`.\n- `taskConfig.minLiquidity`\n  - Minimum market liquidity filter.\n  - `0` effectively means no filter.\n- `taskConfig.minFillSize`\n  - Minimum fill shares filter.\n  - `0` effectively means no filter.\n- `taskConfig.maxPriceDeviation`\n  - Maximum allowed price deviation percentage.\n- `taskConfig.expiryHours`\n  - Order expiry configuration for copied orders.\n  - Backend default from user config is typically `0`.\n- `taskConfig.convictionLevel`\n  - Conviction-based filter level.\n  - Confirmed values: `OFF`, `LOOSE`, `STANDARD`, `STRICT`.\n  - Backend default is `STANDARD`.\n\nRecommended clarification rules before updating:\n\n- If the user says “改成固定金额跟单”, ask for `fixedAmount`.\n- If the user says “放大\u002F缩小仓位”, clarify whether they mean `navMultiplier` or `fixedAmount`.\n- If the user says “限制单笔金额”, clarify whether they mean `buyLimitPerTradeMin`, `buyLimitPerTradeMax`, or both.\n- If the user says “限制总仓位”, clarify whether they mean `maxBoughtPerCopyTask` or `maxBoughtPerMarket`.\n- If the user says “限制价格区间”, ask for both `priceRangeMin` and `priceRangeMax`.\n- If the user says “调严格一点\u002F调宽松一点”, clarify whether they mean `convictionLevel`.\n- If the user says “恢复跟单\u002F暂停跟单\u002F停止任务”, clarify whether they mean task `status` or a `taskConfig` change.\n\nExample: update `navMultiplier`\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --argjson navMultiplier 1.5 \\\n  '{taskConfig: {navMultiplier: $navMultiplier}}')\"\n```\n\nExample: enable buy-only mode\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --argjson buyOnly true \\\n  '{taskConfig: {buyOnly: $buyOnly}}')\"\n```\n\nExample: limit per-trade buy amount\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --argjson min 2 \\\n  --argjson max 10 \\\n  '{taskConfig: {buyLimitPerTradeMin: $min, buyLimitPerTradeMax: $max}}')\"\n```\n\nExample: limit total bought amount\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --argjson maxBoughtPerCopyTask 100 \\\n  --argjson maxBoughtPerMarket 25 \\\n  '{taskConfig: {maxBoughtPerCopyTask: $maxBoughtPerCopyTask, maxBoughtPerMarket: $maxBoughtPerMarket}}')\"\n```\n\nExample: restrict execution price range\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --argjson min 0.1 \\\n  --argjson max 0.9 \\\n  '{taskConfig: {priceRangeMin: $min, priceRangeMax: $max}}')\"\n```\n\nExample: combine multiple taskConfig changes\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --argjson buyOnly true \\\n  --argjson navMultiplier 1.2 \\\n  --argjson maxBoughtPerMarket 20 \\\n  '{\n    taskConfig: {\n      buyOnly: $buyOnly,\n      navMultiplier: $navMultiplier,\n      maxBoughtPerMarket: $maxBoughtPerMarket\n    }\n  }')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X PATCH \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\" \\\n  -d \"$PAYLOAD\"\n```\n\nExample: update `convictionLevel`\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --arg convictionLevel \"STRICT\" \\\n  '{taskConfig: {convictionLevel: $convictionLevel}}')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X PATCH \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\" \\\n  -d \"$PAYLOAD\"\n```\n\nConviction level guidance:\n\n- `OFF`: disable conviction filter.\n- `LOOSE`: lower threshold, more signals can pass.\n- `STANDARD`: default mode.\n- `STRICT`: higher threshold, fewer signals can pass.\n- If the user gives an unknown value, normalize to one of the four explicit options before calling the API.\n\nExample: update `taskConfig` and `status` together\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --arg status \"RUNNING\" \\\n  --argjson buyOnly true \\\n  '{\n    status: $status,\n    taskConfig: {\n      buyOnly: $buyOnly\n    }\n  }')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X PATCH \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\" \\\n  -d \"$PAYLOAD\"\n```\n\nExample: update TPSL rules safely\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --arg ruleId \"$RULE_ID\" \\\n  --argjson takeProfitPct 20 \\\n  '{tpslRules: {update: [{id: $ruleId, takeProfitPct: $takeProfitPct}]}}')\"\n```\n\nExample: update task status\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --arg status \"PAUSED\" \\\n  '{status: $status}')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X PATCH \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\" \\\n  -d \"$PAYLOAD\"\n```\n\nStatus guidance:\n\n- Valid task `status` values for update are: `RUNNING`, `PAUSED`, `STOPPED`.\n- Use `PAUSED` when the user wants to temporarily stop following new trades.\n- Use `RUNNING` when the user wants to resume an active task.\n- Use `STOPPED` only when the user explicitly wants the task stopped rather than just paused.\n- Do not use `DELETED` in update payloads; deletion should use `DELETE \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}`.\n- Prefer uppercase status values in payloads.\n\n### Action: Delete copy task\n\n- `DELETE \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}`\n\nBefore calling: validate `taskId` and confirm.\n\nMinimum fields to ask:\n\n- Always ask: `taskId`\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X DELETE \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\"\n```\n\n### Action: Get total PnL\n\n- `GET \u002Fapi\u002Fv1\u002Fcopy-tasks\u002Ftotal-pnl`\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002Ftotal-pnl\"\n```\n\n---\n\n## Positions & Trades\n\n### Action: List positions\n\n- `GET \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}\u002Fpositions`\n- Query params: `status` (optional)\n  - Confirmed values in current code: `active`, `closed`\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\u002Fpositions?status=active\"\n```\n\nGuidance:\n\n- `active` returns positions with remaining amount above the close threshold.\n- `closed` returns positions whose remaining amount is effectively zero.\n- If `status` is omitted or unknown, the backend currently returns all positions.\n- Prefer `active` \u002F `closed` rather than `open` \u002F `closed`.\n\n### Action: List trades\n\n- `GET \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}\u002Ftrades`\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\u002Ftrades\"\n```\n\n### Action: Sell position\n\n- `POST \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}\u002Fsell`\n- Required field: `marketId` (preferred) or `conditionId`\n- Optional field: `amount` (partial sell; omit to sell full position)\n\nBefore calling: validate `taskId`, summarize (which market, amount), and confirm.\n\nMinimum fields to ask:\n\n- Always ask: `taskId`\n- Always ask one of: `marketId` or `conditionId`\n- Ask `amount` only when the user wants a partial sell\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --arg marketId \"...\" \\\n  --argjson amount 10 \\\n  '{marketId: $marketId, amount: $amount}')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X POST \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\u002Fsell\" \\\n  -d \"$PAYLOAD\"\n```\n\n### Action: Sell all positions\n\n- `POST \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}\u002Fsell-all`\n\nBefore calling: validate `taskId` and confirm — this sells ALL positions for the task.\n\nMinimum fields to ask:\n\n- Always ask: `taskId`\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X POST \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\u002Fsell-all\"\n```\n\n---\n\n## Batch Operations\n\n### Action: Batch update tasks\n\n- `POST \u002Fapi\u002Fv1\u002Fcopy-tasks\u002Fbatch-update`\n- Required: `taskIds` (array of task IDs)\n- Optional: `status` (string), `taskConfig` (object)\n\nBefore calling: summarize which tasks and what changes, and confirm.\n\nMinimum fields to ask:\n\n- Always ask: `taskIds`\n- Ask at least one of: `status`, `taskConfig`\n\n```bash\nTASK_IDS=(\"64f0c7e7b8e4f8c1a1b2c3d4\" \"64f0c7e7b8e4f8c1a1b2c3d5\")\nPAYLOAD=\"$(jq -n \\\n  --arg status \"PAUSED\" \\\n  --argjson taskIds \"$(printf '%s\\n' \"${TASK_IDS[@]}\" | jq -R . | jq -s .)\" \\\n  '{taskIds: $taskIds, status: $status}')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X POST \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002Fbatch-update\" \\\n  -d \"$PAYLOAD\"\n```\n\nExample: batch update `taskConfig.copyMode`\n\n```bash\nTASK_IDS=(\"64f0c7e7b8e4f8c1a1b2c3d4\" \"64f0c7e7b8e4f8c1a1b2c3d5\")\nPAYLOAD=\"$(jq -n \\\n  --argjson taskIds \"$(printf '%s\\n' \"${TASK_IDS[@]}\" | jq -R . | jq -s .)\" \\\n  '{\n    taskIds: $taskIds,\n    taskConfig: {\n      copyMode: \"ONE_TO_ONE\"\n    }\n  }')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X POST \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002Fbatch-update\" \\\n  -d \"$PAYLOAD\"\n```\n\nBatch update guidance:\n\n- `status` uses the same allowed values as single-task update: `RUNNING`, `PAUSED`, `STOPPED`.\n- `taskConfig` replaces the task config object sent in the batch request, so only send fields you intentionally want to set.\n- If neither `status` nor `taskConfig` is provided, the backend currently just returns the selected tasks.\n- Use batch update only when the same change should apply to all listed tasks.\n\n### Action: Batch delete tasks\n\n- `POST \u002Fapi\u002Fv1\u002Fcopy-tasks\u002Fbatch-delete`\n- Required: `taskIds` (array of task IDs)\n\nBefore calling: confirm deletion.\n\nMinimum fields to ask:\n\n- Always ask: `taskIds`\n\n```bash\nTASK_IDS=(\"64f0c7e7b8e4f8c1a1b2c3d4\" \"64f0c7e7b8e4f8c1a1b2c3d5\")\nPAYLOAD=\"$(jq -n \\\n  --argjson taskIds \"$(printf '%s\\n' \"${TASK_IDS[@]}\" | jq -R . | jq -s .)\" \\\n  '{taskIds: $taskIds}')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X POST \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002Fbatch-delete\" \\\n  -d \"$PAYLOAD\"\n```\n\n---\n\n## Copy Signals\n\n### Action: List copy signals\n\n- `GET \u002Fapi\u002Fv1\u002Fcopy-signals`\n- Query params:\n  - `limit` (int, default 50)\n  - `cursor` (int, offset for pagination)\n  - `since` (RFC3339 timestamp)\n  - `sinceCreatedAt` (RFC3339 timestamp)\n  - `action` (one of: `COPIED`, `SKIPPED`, `FAILED`, `RECEIVED`)\n  - `trader` (address filter)\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \"$BASE\u002Fapi\u002Fv1\u002Fcopy-signals?limit=20&action=COPIED\"\n```\n\nPrefer composing the query from user intent. Only pass filters the user asked for.\n\nValidation:\n\n- `limit` must be a positive integer.\n- `cursor` must be a non-negative integer.\n- `since` and `sinceCreatedAt` must be RFC3339 or RFC3339Nano timestamps.\n- Valid `action` values are: `COPIED`, `SKIPPED`, `FAILED`, `RECEIVED`.\n\nAction guidance:\n\n- `RECEIVED`: the signal was ingested.\n- `COPIED`: the copy order was placed successfully.\n- `SKIPPED`: the signal was intentionally not copied because checks or limits blocked it.\n- `FAILED`: the system attempted processing but failed.\n\nExample: fetch signals since a specific time\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \\\n  \"$BASE\u002Fapi\u002Fv1\u002Fcopy-signals?since=2026-03-01T00:00:00Z&limit=50\"\n```\n\nExample: fetch next page using cursor\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \\\n  \"$BASE\u002Fapi\u002Fv1\u002Fcopy-signals?cursor=50&limit=50\"\n```\n\n### Action: Stream copy signals\n\n- `GET \u002Fapi\u002Fv1\u002Fcopy-signals\u002Fstream`\n- Response type: Server-Sent Events (SSE)\n\n```bash\ncurl -sS -N \"${AUTH[@]}\" \"$BASE\u002Fapi\u002Fv1\u002Fcopy-signals\u002Fstream\"\n```\n\nStream guidance:\n\n- Use this only when the user explicitly wants real-time signal updates.\n- Expect events such as `ready` and `copy_signal`.\n- Keep the connection open; this is not a one-shot request.\n\n### Action: Get signal stats\n\n- `GET \u002Fapi\u002Fv1\u002Fcopy-signals\u002Fstats`\n\nReturns signal counts grouped by action and by trader.\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \"$BASE\u002Fapi\u002Fv1\u002Fcopy-signals\u002Fstats\"\n```\n\n---\n\n## TPSL Rules (Take-Profit \u002F Stop-Loss)\n\n### Action: Get TPSL rule\n\n- `GET \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}\u002Ftpsl-rules\u002F{ruleId}`\n\nMinimum fields to ask:\n\n- Always ask: `taskId`, `ruleId`\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\u002Ftpsl-rules\u002F$RULE_ID\"\n```\n\n### Action: Simulate TPSL rule\n\n- `POST \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}\u002Ftpsl-rules\u002F{ruleId}\u002Fsimulate`\n\nMinimum fields to ask:\n\n- Always ask: `taskId`, `ruleId`\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X POST \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\u002Ftpsl-rules\u002F$RULE_ID\u002Fsimulate\"\n```\n\n### TPSL inline payload guidance\n\nWhen creating a task, `tpslRules` items may include:\n\n- `sourceOrderId`, `sourceType`\n- Optional entry info: `conditionId`, `tokenId`, `assetId`, `entryPrice`, `entrySize`, `side`\n- Optional risk config: `takeProfitPct`, `takeProfitProb`, `stopLossPct`, `limitPriceOffset`, `orderTimeout`, `fallbackToMarket`\n\nWhen updating a task, `tpslRules` should be wrapped as:\n\n- `create`: array of new inline rules\n- `update`: array of `{id, ...patchFields}`\n- `cancel`: array of `ruleId`\n\nExample: create a task with one TPSL rule\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --arg targetTrader \"0x...\" \\\n  --arg sourceOrderId \"order_123\" \\\n  --arg sourceType \"copy_trade\" \\\n  --argjson takeProfitPct 20 \\\n  --argjson stopLossPct 10 \\\n  '{\n    targetTrader: $targetTrader,\n    tpslRules: [\n      {\n        sourceOrderId: $sourceOrderId,\n        sourceType: $sourceType,\n        takeProfitPct: $takeProfitPct,\n        stopLossPct: $stopLossPct\n      }\n    ]\n  }')\"\n```\n\n---\n\n## Error handling\n\n- `401`: API key missing\u002Finvalid\u002Fexpired\u002Fdisabled. Ask user to check or regenerate key.\n- `404`: Task or resource not found. Ask user to verify `taskId`.\n- `409`: Task already exists (duplicate `targetTrader`).\n- `422`: Copy task limit exceeded.\n- `400`: Invalid payload or invalid query param such as `includeDeleted`.\n- `5xx`: Server error. Retry once with backoff; if still failing, report response body.\n","# Polyhub Copy Skill\n\nVersion: v0.3.3\n\n## When to use\n\nUse this skill when the user asks about:\n\n- Listing, creating, updating or deleting copy-trading tasks\n- Viewing copy task positions or trades\n- Selling positions (single or all)\n- Batch updating or deleting copy tasks\n- Viewing total PnL across copy tasks\n- Viewing copy signals and signal stats\n- Managing take-profit \u002F stop-loss (TPSL) rules\n\n## Requirements\n\n- `POLYHUB_API_BASE_URL` — Polyhub API server URL (e.g. `https:\u002F\u002Fapi.polyhub.example.com`)\n- `POLYHUB_API_KEY` — API key (must start with `phub_`)\n- `curl` must be available in the runtime environment.\n- `jq` is strongly recommended for building JSON payloads safely.\n\n## Safety rules\n\n- Never print `POLYHUB_API_KEY` in the output.\n- Treat all IDs and user-provided JSON fields as untrusted input.\n- For write actions (`POST`\u002F`PATCH`\u002F`DELETE`), repeat the action summary and wait for explicit user confirmation before calling the API.\n- Prefer building JSON with `jq -n` instead of interpolating raw shell strings.\n- Validation rules:\n  - `taskId` must be a 24-char hex MongoDB ObjectID: `^[0-9a-fA-F]{24}$`\n  - `ruleId` must be non-empty.\n  - `taskIds` in batch operations must all match the `taskId` format.\n  - `status` for positions should only be passed when the user explicitly requests a filter.\n\n## Tools\n\nUse the `bash` tool to call the API with `curl`.\n\n## Fast Path\n\nFor common intents, map user requests like this:\n\n- “列出任务” -> `GET \u002Fapi\u002Fv1\u002Fcopy-tasks`\n- “暂停\u002F恢复\u002F停止任务” -> `PATCH \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}` with `status`\n- “改跟单模式\u002F改单笔或总仓位限制” -> `PATCH \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}` with `taskConfig`\n- “看持仓\u002F成交” -> `GET \u002Fpositions` or `GET \u002Ftrades`\n- “卖出某个仓位\u002F全部仓位” -> `POST \u002Fsell` or `POST \u002Fsell-all`\n- “看跟单信号\u002F统计” -> `GET \u002Fapi\u002Fv1\u002Fcopy-signals` or `\u002Fstats`\n\n### Curl base setup\n\n```bash\nBASE=\"${POLYHUB_API_BASE_URL%\u002F}\"\nAUTH=(-H \"Authorization: Bearer $POLYHUB_API_KEY\" -H \"Content-Type: application\u002Fjson\")\n```\n\n### Validate helpers\n\n```bash\nif [[ ! \"$TASK_ID\" =~ ^[0-9a-fA-F]{24}$ ]]; then echo \"Invalid taskId\"; exit 2; fi\n```\n\n```bash\nif [[ -z \"${RULE_ID:-}\" ]]; then echo \"Invalid ruleId\"; exit 2; fi\n```\n\n```bash\nfor id in \"${TASK_IDS[@]}\"; do\n  if [[ ! \"$id\" =~ ^[0-9a-fA-F]{24}$ ]]; then\n    echo \"Invalid taskId in batch: $id\"\n    exit 2\n  fi\ndone\n```\n\n---\n\n## Copy Tasks\n\n### Action: List copy tasks\n\n- `GET \u002Fapi\u002Fv1\u002Fcopy-tasks`\n- Query params: `includeDeleted=true|false` (default: true)\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks?includeDeleted=true\"\n```\n\nGuidance:\n\n- Use `includeDeleted=true` when the user wants a full history or is looking for a previously deleted task.\n- Use `includeDeleted=false` when the user only wants active\u002Fnon-deleted tasks.\n\n### Action: Create copy task\n\n- `POST \u002Fapi\u002Fv1\u002Fcopy-tasks`\n- Required field: `targetTrader` (Polymarket address of the smart money)\n- Optional fields from `domain.CreateCopyTaskPayload`: `targetUsername`, `taskConfig`, `filteredByTag`, `tpslRules`\n\nBefore calling: ask the user for `targetTrader` at minimum. Summarize and confirm.\n\nMinimum fields to ask:\n\n- Always ask: `targetTrader`\n- Ask only if needed: `filteredByTag`, `targetUsername`\n- If the user wants custom copy behavior: ask for the relevant `taskConfig` fields explicitly\n- If the user wants TPSL on creation: ask for `tpslRules`\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --arg targetTrader \"0x...\" \\\n  '{targetTrader: $targetTrader}')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X POST \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\" \\\n  -d \"$PAYLOAD\"\n```\n\nIf the user wants advanced config, build `taskConfig` and `tpslRules` explicitly instead of accepting arbitrary JSON.\n\n### Action: Get copy task\n\n- `GET \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}`\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\"\n```\n\n### Action: Update copy task\n\n- `PATCH \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}`\n- Body: partial JSON. Common fields:\n  - `status`\n  - `taskConfig`\n  - `filteredByTag`\n  - `targetUsername`\n  - `tpslRules` using `create` \u002F `update` \u002F `cancel`\n\nBefore calling: validate `taskId`, summarize changes, and confirm.\n\nMinimum fields to ask:\n\n- Always ask: `taskId`\n- Ask only the fields the user wants to change:\n  - Task lifecycle: `status`\n  - Copy behavior: `taskConfig`\n  - Trader label\u002Ftag filters: `targetUsername`, `filteredByTag`\n  - TPSL maintenance: `tpslRules`\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --arg status \"PAUSED\" \\\n  '{status: $status}')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X PATCH \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\" \\\n  -d \"$PAYLOAD\"\n```\n\nExample: update `taskConfig` safely\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --argjson buyOnly true \\\n  --argjson maxBoughtPerMarket 50 \\\n  '{taskConfig: {buyOnly: $buyOnly, maxBoughtPerMarket: $maxBoughtPerMarket}}')\"\n```\n\nExample: change copy mode to `ONE_TO_ONE`\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  '{taskConfig: {copyMode: \"ONE_TO_ONE\"}}')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X PATCH \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\" \\\n  -d \"$PAYLOAD\"\n```\n\nExample: change copy mode to `FIXED_SIZE`\n\n`FIXED_SIZE` should include `taskConfig.fixedAmount`.\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --argjson fixedAmount 5 \\\n  '{taskConfig: {copyMode: \"FIXED_SIZE\", fixedAmount: $fixedAmount}}')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X PATCH \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\" \\\n  -d \"$PAYLOAD\"\n```\n\nCopy mode guidance:\n\n- `taskConfig.copyMode` is the field that controls the task's copy mode.\n- Confirmed mode values in the current codebase: `ONE_TO_ONE`, `FIXED_SIZE`.\n- If switching to `FIXED_SIZE`, also ask for `taskConfig.fixedAmount`.\n- If switching to `ONE_TO_ONE`, omit `fixedAmount` unless the user explicitly wants to keep it stored.\n\n### TaskConfig field guidance\n\nUse these fields when the user wants to change task-level copy behavior. Prefer changing only the fields the user explicitly asked for.\n\nCommon fields:\n\n- `taskConfig.copyMode`\n  - Controls copy sizing mode.\n  - Confirmed values: `ONE_TO_ONE`, `FIXED_SIZE`.\n- `taskConfig.fixedAmount`\n  - Used when `copyMode=FIXED_SIZE`.\n  - Represents a fixed notional amount for copied orders.\n- `taskConfig.navMultiplier`\n  - Multiplies the computed order size.\n  - Current default in backend user config is `1`.\n- `taskConfig.positionUtilization`\n  - Position utilization \u002F max amount per copy-trade style control.\n  - Backend default is `0`, which means no filter.\n- `taskConfig.buyOnly`\n  - If `true`, non-`BUY` signals are skipped.\n- `taskConfig.buyLimitPerTradeMin`\n  - Minimum allowed copied buy amount per trade.\n  - `0` effectively means no lower bound.\n- `taskConfig.buyLimitPerTradeMax`\n  - Maximum allowed copied buy amount per trade.\n  - `0` effectively means no upper bound.\n- `taskConfig.maxBoughtPerCopyTask`\n  - Caps total bought amount at task level.\n  - `0` effectively means no cap.\n- `taskConfig.maxBoughtPerMarket`\n  - Caps total bought amount for a single market inside the task.\n  - `0` effectively means no cap.\n- `taskConfig.priceRangeMin`\n  - Minimum allowed execution price.\n  - Default from user config is typically `0.01`.\n- `taskConfig.priceRangeMax`\n  - Maximum allowed execution price.\n  - Default from user config is typically `0.99`.\n- `taskConfig.minLiquidity`\n  - Minimum market liquidity filter.\n  - `0` effectively means no filter.\n- `taskConfig.minFillSize`\n  - Minimum fill shares filter.\n  - `0` effectively means no filter.\n- `taskConfig.maxPriceDeviation`\n  - Maximum allowed price deviation percentage.\n- `taskConfig.expiryHours`\n  - Order expiry configuration for copied orders.\n  - Backend default from user config is typically `0`.\n- `taskConfig.convictionLevel`\n  - Conviction-based filter level.\n  - Confirmed values: `OFF`, `LOOSE`, `STANDARD`, `STRICT`.\n  - Backend default is `STANDARD`.\n\nRecommended clarification rules before updating:\n\n- If the user says “改成固定金额跟单”, ask for `fixedAmount`.\n- If the user says “放大\u002F缩小仓位”, clarify whether they mean `navMultiplier` or `fixedAmount`.\n- If the user says “限制单笔金额”, clarify whether they mean `buyLimitPerTradeMin`, `buyLimitPerTradeMax`, or both.\n- If the user says “限制总仓位”, clarify whether they mean `maxBoughtPerCopyTask` or `maxBoughtPerMarket`.\n- If the user says “限制价格区间”, ask for both `priceRangeMin` and `priceRangeMax`.\n- If the user says “调严格一点\u002F调宽松一点”, clarify whether they mean `convictionLevel`.\n- If the user says “恢复跟单\u002F暂停跟单\u002F停止任务”, clarify whether they mean task `status` or a `taskConfig` change.\n\nExample: update `navMultiplier`\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --argjson navMultiplier 1.5 \\\n  '{taskConfig: {navMultiplier: $navMultiplier}}')\"\n```\n\nExample: enable buy-only mode\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --argjson buyOnly true \\\n  '{taskConfig: {buyOnly: $buyOnly}}')\"\n```\n\nExample: limit per-trade buy amount\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --argjson min 2 \\\n  --argjson max 10 \\\n  '{taskConfig: {buyLimitPerTradeMin: $min, buyLimitPerTradeMax: $max}}')\"\n```\n\nExample: limit total bought amount\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --argjson maxBoughtPerCopyTask 100 \\\n  --argjson maxBoughtPerMarket 25 \\\n  '{taskConfig: {maxBoughtPerCopyTask: $maxBoughtPerCopyTask, maxBoughtPerMarket: $maxBoughtPerMarket}}')\"\n```\n\nExample: restrict execution price range\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --argjson min 0.1 \\\n  --argjson max 0.9 \\\n  '{taskConfig: {priceRangeMin: $min, priceRangeMax: $max}}')\"\n```\n\nExample: combine multiple taskConfig changes\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --argjson buyOnly true \\\n  --argjson navMultiplier 1.2 \\\n  --argjson maxBoughtPerMarket 20 \\\n  '{\n    taskConfig: {\n      buyOnly: $buyOnly,\n      navMultiplier: $navMultiplier,\n      maxBoughtPerMarket: $maxBoughtPerMarket\n    }\n  }')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X PATCH \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\" \\\n  -d \"$PAYLOAD\"\n```\n\nExample: update `convictionLevel`\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --arg convictionLevel \"STRICT\" \\\n  '{taskConfig: {convictionLevel: $convictionLevel}}')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X PATCH \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\" \\\n  -d \"$PAYLOAD\"\n```\n\nConviction level guidance:\n\n- `OFF`: disable conviction filter.\n- `LOOSE`: lower threshold, more signals can pass.\n- `STANDARD`: default mode.\n- `STRICT`: higher threshold, fewer signals can pass.\n- If the user gives an unknown value, normalize to one of the four explicit options before calling the API.\n\nExample: update `taskConfig` and `status` together\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --arg status \"RUNNING\" \\\n  --argjson buyOnly true \\\n  '{\n    status: $status,\n    taskConfig: {\n      buyOnly: $buyOnly\n    }\n  }')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X PATCH \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\" \\\n  -d \"$PAYLOAD\"\n```\n\nExample: update TPSL rules safely\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --arg ruleId \"$RULE_ID\" \\\n  --argjson takeProfitPct 20 \\\n  '{tpslRules: {update: [{id: $ruleId, takeProfitPct: $takeProfitPct}]}}')\"\n```\n\nExample: update task status\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --arg status \"PAUSED\" \\\n  '{status: $status}')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X PATCH \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\" \\\n  -d \"$PAYLOAD\"\n```\n\nStatus guidance:\n\n- Valid task `status` values for update are: `RUNNING`, `PAUSED`, `STOPPED`.\n- Use `PAUSED` when the user wants to temporarily stop following new trades.\n- Use `RUNNING` when the user wants to resume an active task.\n- Use `STOPPED` only when the user explicitly wants the task stopped rather than just paused.\n- Do not use `DELETED` in update payloads; deletion should use `DELETE \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}`.\n- Prefer uppercase status values in payloads.\n\n### Action: Delete copy task\n\n- `DELETE \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}`\n\nBefore calling: validate `taskId` and confirm.\n\nMinimum fields to ask:\n\n- Always ask: `taskId`\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X DELETE \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\"\n```\n\n### Action: Get total PnL\n\n- `GET \u002Fapi\u002Fv1\u002Fcopy-tasks\u002Ftotal-pnl`\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002Ftotal-pnl\"\n```\n\n---\n\n## Positions & Trades\n\n### Action: List positions\n\n- `GET \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}\u002Fpositions`\n- Query params: `status` (optional)\n  - Confirmed values in current code: `active`, `closed`\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\u002Fpositions?status=active\"\n```\n\nGuidance:\n\n- `active` returns positions with remaining amount above the close threshold.\n- `closed` returns positions whose remaining amount is effectively zero.\n- If `status` is omitted or unknown, the backend currently returns all positions.\n- Prefer `active` \u002F `closed` rather than `open` \u002F `closed`.\n\n### Action: List trades\n\n- `GET \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}\u002Ftrades`\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\u002Ftrades\"\n```\n\n### Action: Sell position\n\n- `POST \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}\u002Fsell`\n- Required field: `marketId` (preferred) or `conditionId`\n- Optional field: `amount` (partial sell; omit to sell full position)\n\nBefore calling: validate `taskId`, summarize (which market, amount), and confirm.\n\nMinimum fields to ask:\n\n- Always ask: `taskId`\n- Always ask one of: `marketId` or `conditionId`\n- Ask `amount` only when the user wants a partial sell\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --arg marketId \"...\" \\\n  --argjson amount 10 \\\n  '{marketId: $marketId, amount: $amount}')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X POST \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\u002Fsell\" \\\n  -d \"$PAYLOAD\"\n```\n\n### Action: Sell all positions\n\n- `POST \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}\u002Fsell-all`\n\nBefore calling: validate `taskId` and confirm — this sells ALL positions for the task.\n\nMinimum fields to ask:\n\n- Always ask: `taskId`\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X POST \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\u002Fsell-all\"\n```\n\n---\n\n## Batch Operations\n\n### Action: Batch update tasks\n\n- `POST \u002Fapi\u002Fv1\u002Fcopy-tasks\u002Fbatch-update`\n- Required: `taskIds` (array of task IDs)\n- Optional: `status` (string), `taskConfig` (object)\n\nBefore calling: summarize which tasks and what changes, and confirm.\n\nMinimum fields to ask:\n\n- Always ask: `taskIds`\n- Ask at least one of: `status`, `taskConfig`\n\n```bash\nTASK_IDS=(\"64f0c7e7b8e4f8c1a1b2c3d4\" \"64f0c7e7b8e4f8c1a1b2c3d5\")\nPAYLOAD=\"$(jq -n \\\n  --arg status \"PAUSED\" \\\n  --argjson taskIds \"$(printf '%s\\n' \"${TASK_IDS[@]}\" | jq -R . | jq -s .)\" \\\n  '{taskIds: $taskIds, status: $status}')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X POST \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002Fbatch-update\" \\\n  -d \"$PAYLOAD\"\n```\n\nExample: batch update `taskConfig.copyMode`\n\n```bash\nTASK_IDS=(\"64f0c7e7b8e4f8c1a1b2c3d4\" \"64f0c7e7b8e4f8c1a1b2c3d5\")\nPAYLOAD=\"$(jq -n \\\n  --argjson taskIds \"$(printf '%s\\n' \"${TASK_IDS[@]}\" | jq -R . | jq -s .)\" \\\n  '{\n    taskIds: $taskIds,\n    taskConfig: {\n      copyMode: \"ONE_TO_ONE\"\n    }\n  }')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X POST \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002Fbatch-update\" \\\n  -d \"$PAYLOAD\"\n```\n\nBatch update guidance:\n\n- `status` uses the same allowed values as single-task update: `RUNNING`, `PAUSED`, `STOPPED`.\n- `taskConfig` replaces the task config object sent in the batch request, so only send fields you intentionally want to set.\n- If neither `status` nor `taskConfig` is provided, the backend currently just returns the selected tasks.\n- Use batch update only when the same change should apply to all listed tasks.\n\n### Action: Batch delete tasks\n\n- `POST \u002Fapi\u002Fv1\u002Fcopy-tasks\u002Fbatch-delete`\n- Required: `taskIds` (array of task IDs)\n\nBefore calling: confirm deletion.\n\nMinimum fields to ask:\n\n- Always ask: `taskIds`\n\n```bash\nTASK_IDS=(\"64f0c7e7b8e4f8c1a1b2c3d4\" \"64f0c7e7b8e4f8c1a1b2c3d5\")\nPAYLOAD=\"$(jq -n \\\n  --argjson taskIds \"$(printf '%s\\n' \"${TASK_IDS[@]}\" | jq -R . | jq -s .)\" \\\n  '{taskIds: $taskIds}')\"\n\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X POST \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002Fbatch-delete\" \\\n  -d \"$PAYLOAD\"\n```\n\n---\n\n## Copy Signals\n\n### Action: List copy signals\n\n- `GET \u002Fapi\u002Fv1\u002Fcopy-signals`\n- Query params:\n  - `limit` (int, default 50)\n  - `cursor` (int, offset for pagination)\n  - `since` (RFC3339 timestamp)\n  - `sinceCreatedAt` (RFC3339 timestamp)\n  - `action` (one of: `COPIED`, `SKIPPED`, `FAILED`, `RECEIVED`)\n  - `trader` (address filter)\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \"$BASE\u002Fapi\u002Fv1\u002Fcopy-signals?limit=20&action=COPIED\"\n```\n\nPrefer composing the query from user intent. Only pass filters the user asked for.\n\nValidation:\n\n- `limit` must be a positive integer.\n- `cursor` must be a non-negative integer.\n- `since` and `sinceCreatedAt` must be RFC3339 or RFC3339Nano timestamps.\n- Valid `action` values are: `COPIED`, `SKIPPED`, `FAILED`, `RECEIVED`.\n\nAction guidance:\n\n- `RECEIVED`: the signal was ingested.\n- `COPIED`: the copy order was placed successfully.\n- `SKIPPED`: the signal was intentionally not copied because checks or limits blocked it.\n- `FAILED`: the system attempted processing but failed.\n\nExample: fetch signals since a specific time\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \\\n  \"$BASE\u002Fapi\u002Fv1\u002Fcopy-signals?since=2026-03-01T00:00:00Z&limit=50\"\n```\n\nExample: fetch next page using cursor\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \\\n  \"$BASE\u002Fapi\u002Fv1\u002Fcopy-signals?cursor=50&limit=50\"\n```\n\n### Action: Stream copy signals\n\n- `GET \u002Fapi\u002Fv1\u002Fcopy-signals\u002Fstream`\n- Response type: Server-Sent Events (SSE)\n\n```bash\ncurl -sS -N \"${AUTH[@]}\" \"$BASE\u002Fapi\u002Fv1\u002Fcopy-signals\u002Fstream\"\n```\n\nStream guidance:\n\n- Use this only when the user explicitly wants real-time signal updates.\n- Expect events such as `ready` and `copy_signal`.\n- Keep the connection open; this is not a one-shot request.\n\n### Action: Get signal stats\n\n- `GET \u002Fapi\u002Fv1\u002Fcopy-signals\u002Fstats`\n\nReturns signal counts grouped by action and by trader.\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \"$BASE\u002Fapi\u002Fv1\u002Fcopy-signals\u002Fstats\"\n```\n\n---\n\n## TPSL Rules (Take-Profit \u002F Stop-Loss)\n\n### Action: Get TPSL rule\n\n- `GET \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}\u002Ftpsl-rules\u002F{ruleId}`\n\nMinimum fields to ask:\n\n- Always ask: `taskId`, `ruleId`\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\u002Ftpsl-rules\u002F$RULE_ID\"\n```\n\n### Action: Simulate TPSL rule\n\n- `POST \u002Fapi\u002Fv1\u002Fcopy-tasks\u002F{taskId}\u002Ftpsl-rules\u002F{ruleId}\u002Fsimulate`\n\nMinimum fields to ask:\n\n- Always ask: `taskId`, `ruleId`\n\n```bash\ncurl -sS --fail-with-body \"${AUTH[@]}\" -X POST \"$BASE\u002Fapi\u002Fv1\u002Fcopy-tasks\u002F$TASK_ID\u002Ftpsl-rules\u002F$RULE_ID\u002Fsimulate\"\n```\n\n### TPSL inline payload guidance\n\nWhen creating a task, `tpslRules` items may include:\n\n- `sourceOrderId`, `sourceType`\n- Optional entry info: `conditionId`, `tokenId`, `assetId`, `entryPrice`, `entrySize`, `side`\n- Optional risk config: `takeProfitPct`, `takeProfitProb`, `stopLossPct`, `limitPriceOffset`, `orderTimeout`, `fallbackToMarket`\n\nWhen updating a task, `tpslRules` should be wrapped as:\n\n- `create`: array of new inline rules\n- `update`: array of `{id, ...patchFields}`\n- `cancel`: array of `ruleId`\n\nExample: create a task with one TPSL rule\n\n```bash\nPAYLOAD=\"$(jq -n \\\n  --arg targetTrader \"0x...\" \\\n  --arg sourceOrderId \"order_123\" \\\n  --arg sourceType \"copy_trade\" \\\n  --argjson takeProfitPct 20 \\\n  --argjson stopLossPct 10 \\\n  '{\n    targetTrader: $targetTrader,\n    tpslRules: [\n      {\n        sourceOrderId: $sourceOrderId,\n        sourceType: $sourceType,\n        takeProfitPct: $takeProfitPct,\n        stopLossPct: $stopLossPct\n      }\n    ]\n  }')\"\n```\n\n---\n\n## Error handling\n\n- `401`: API key missing\u002Finvalid\u002Fexpired\u002Fdisabled. Ask user to check or regenerate key.\n- `404`: Task or resource not found. Ask user to verify `taskId`.\n- `409`: Task already exists (duplicate `targetTrader`).\n- `422`: Copy task limit exceeded.\n- `400`: Invalid payload or invalid query param such as `includeDeleted`.\n- `5xx`: Server error. Retry once with backoff; if still failing, report response body.\n",{"name":5,"description":7},"main","3df1d0d67b30ff15236561f8c0f9f06d33f42dfd","skills\u002Ftrading\u002Fpolyhub-copy",17,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia","https:\u002F\u002Feth2030.com","Hardcore infra. Building @alt-research and applied cryptography.","2026-11-12 02:28:42",{"source":8,"skillName":5,"commands":44,"prompt":54,"zipAvailable":55},[45,48,51],{"tool":46,"command":47},"npx","npx skills add jiayaoqijia\u002Fcryptoskill --skill polyhub_copy",{"tool":49,"command":50},"bunx","bunx skills add jiayaoqijia\u002Fcryptoskill --skill polyhub_copy",{"tool":52,"command":53},"pnpm","pnpm dlx skills add jiayaoqijia\u002Fcryptoskill --skill polyhub_copy","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Ftrading\u002Fpolyhub-copy\u002FSKILL.md",true,[57,63],{"path":58,"resourceType":59,"resourceTypeDesc":60,"sizeBytes":61,"sourceHtmlUrl":62},"SOURCE.md","REFERENCE","参考文档",169,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Ftrading\u002Fpolyhub-copy\u002FSOURCE.md",{"path":64,"resourceType":59,"resourceTypeDesc":60,"sizeBytes":65,"sourceHtmlUrl":66},"TRUST.auto.yaml",2197,"https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Ftrading\u002Fpolyhub-copy\u002FTRUST.auto.yaml",[68,96,118,136,149,159],{"skillNo":69,"name":70,"nameZh":6,"description":71,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":72,"licenseFileUrl":73,"sourceHtmlUrl":74,"categories":75,"keywords":76,"publishedAt":29},"01M712C436EQYE43342Q4E7GG1","recipe-performance","Diagnose a specific MetaMask user flow's real-app performance and Sentry critical-user-flow telemetry with deterministic mm-harness recipes. Use for CUF boundaries, cold\u002Fwarm\u002Fbackground-resume behavior, latency regressions, lifecycle tags, duplicate or blocking network requests, long tasks, layout\u002Fpaint cost, screen redraws, React rerenders, or browser trace analysis where tests alone cannot prove the real app.","MIT","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fwallets\u002Fmetamask-official-recipe-performance\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fwallets\u002Fmetamask-official-recipe-performance\u002FSKILL.md",[],[77,78,79,80,81,82,83,84,85,86,87,88,89,21,90,91,92,93,94,95],"performance","recipe performance","recipe","mm","sentry","harness","app","deterministic","recipes","flow","cold","critical","analysis","react","browser","layout","screen","network","metamask",{"skillNo":97,"name":98,"nameZh":6,"description":99,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":100,"licenseFileUrl":101,"sourceHtmlUrl":102,"categories":103,"keywords":104,"publishedAt":29},"01M70XT2F8A5CQZ81JBP98KSW3","mexc-spot-websocket","MEXC Spot WebSocket workflows for public streams, protobuf handling, depth maintenance, listen keys, and private streams without exposing API keys.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-websocket\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-websocket\u002FSKILL.md",[],[105,106,107,22,108,109,110,111,112,113,114,115,116,117],"mexc spot websocket","spot","websocket","workflows","public","listen","streams","depth","keys","for","api keys","maintenance","protobuf",{"skillNo":119,"name":120,"nameZh":6,"description":121,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":100,"licenseFileUrl":122,"sourceHtmlUrl":123,"categories":124,"keywords":125,"publishedAt":29},"01M70XT0MBXN3WZY1BKN0CPNKR","mexc-spot-rest","MEXC Spot REST workflows for public data, signed account requests, orders, wallet\u002Fadmin actions, and secure signing without exposing API keys.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-rest\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-spot-rest\u002FSKILL.md",[],[126,106,127,128,129,130,131,115,114,113,132,133,134,109,135,108,22],"mexc spot rest","REST","admin","signing","Wallet","requests","actions","secure","data","orders",{"skillNo":137,"name":138,"nameZh":6,"description":139,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":100,"licenseFileUrl":140,"sourceHtmlUrl":141,"categories":142,"keywords":143,"publishedAt":29},"01M70XSYSVZ2N0N91XCAR2CAK0","mexc-futures-websocket","MEXC Futures WebSocket workflows for public streams, private account\u002Forder\u002Fposition streams, ping\u002Fpong, subscriptions, and depth maintenance.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-futures-websocket\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fexchanges\u002Fmncrftfrcnm-mexc-futures-websocket\u002FSKILL.md",[],[144,145,107,146,147,116,114,148,112,111,109,108],"mexc futures websocket","futures","position","ping","subscriptions",{"skillNo":150,"name":151,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":72,"licenseFileUrl":152,"sourceHtmlUrl":153,"categories":154,"keywords":155,"publishedAt":29},"01M6H0ZWHVE5W04WG2DKQE2SQC","0xklen-version-and-refresh-sanctions-lists","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-version-and-refresh-sanctions-lists\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-version-and-refresh-sanctions-lists\u002FSKILL.md",[],[156,157,158],"refresh","0xklen version and refresh sanctions lists","version",{"skillNo":160,"name":161,"nameZh":6,"description":162,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":72,"licenseFileUrl":163,"sourceHtmlUrl":164,"categories":165,"keywords":166,"publishedAt":29},"01M6H0Z28Q3R8J0S799GJQWXM3","verify-tests-cover-changed-lines","Use when a PR adds code that the existing suite may not exercise. Measures patch coverage — the share of newly changed lines hit by tests — before approving.","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-verify-tests-cover-changed-lines\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fjiayaoqijia\u002Fcryptoskill\u002Fblob\u002Fmain\u002Fskills\u002Fpayments\u002F0xklen-verify-tests-cover-changed-lines\u002FSKILL.md",[],[167,168,169,170,171,172,173,174,175,176,177],"tests","cover","verify tests cover changed lines","verify","coverage","pr","exercise","use","patch","code","share"]