ワンクリックで
polyhub-copy
Manage copy-trading tasks, view signals, positions and trades on Polyhub using an API key.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Manage copy-trading tasks, view signals, positions and trades on Polyhub using an API key.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
View Polyhub portfolio stats, fee history, and place manual orders with explicit confirmation and field validation.
View portfolio stats on Polyhub using an API key.
Query Polyhub public discover APIs for tags, trader rankings, trader detail by address, and market tag lookup by condition IDs.
Explore public discover data on Polyhub without API key auth, including tags, trader rankings, trader detail stats, and market tag lookup.
Manage Polyhub copy-trading tasks, positions, trades, signals, sell flows, batch operations, and TPSL rules with an API key.
| name | polyhub_copy |
| description | Manage copy-trading tasks, view signals, positions and trades on Polyhub using an API key. |
Version: v0.3.9
Use this skill when the user asks about:
POLYHUB_API_BASE_URL is fixed to https://polyhub.skill-test.bedev.hubble-rpc.xyz.POLYHUB_API_KEY — API key (must start with phub_)curl must be available in the runtime environment.jq is strongly recommended for building JSON payloads safely.If POLYHUB_API_KEY is missing, guide the user to register and apply for one first at https://polyhub.hubble.xyz/.
Recommended guidance:
https://polyhub.hubble.xyz/Skills API Key.申请 API Key.POLYHUB_API_BASE_URL and POLYHUB_API_KEY.Suggested wording:
API key is not configured yet, so I can't run copy-trading or account actions for now.
Please register first on PolyHub:
https://polyhub.hubble.xyz/
After registration, click your avatar in the top-right corner and open `Skills API Key` to apply.
Send me the generated key and I'll continue right away.
POLYHUB_API_KEY in the output.POST/PATCH/DELETE), repeat the action summary and wait for explicit user confirmation before calling the API.jq -n instead of interpolating raw shell strings.taskId must be a 24-char hex MongoDB ObjectID: ^[0-9a-fA-F]{24}$ruleId must be non-empty.taskIds in batch operations must all match the taskId format.status for positions should only be passed when the user explicitly requests a filter.Use the bash tool to call the API with curl.
For common intents, map user requests like this:
GET /api/v1/copy-tasksGET /api/v1/copy-tasks/{taskId}/positions?status=active,有 active positions 时先 POST /api/v1/copy-tasks/{taskId}/sell-all,再 DELETE /api/v1/copy-tasks/{taskId}PATCH /api/v1/copy-tasks/{taskId} with statusPATCH /api/v1/copy-tasks/{taskId} with taskConfigGET /positions or GET /tradesPOST /sell or POST /sell-allGET /api/v1/copy-signals or /statsBASE="https://polyhub.skill-test.bedev.hubble-rpc.xyz"
AUTH=(-H "Authorization: Bearer $POLYHUB_API_KEY" -H "Content-Type: application/json")
if [[ ! "$TASK_ID" =~ ^[0-9a-fA-F]{24}$ ]]; then echo "Invalid taskId"; exit 2; fi
if [[ -z "${RULE_ID:-}" ]]; then echo "Invalid ruleId"; exit 2; fi
for id in "${TASK_IDS[@]}"; do
if [[ ! "$id" =~ ^[0-9a-fA-F]{24}$ ]]; then
echo "Invalid taskId in batch: $id"
exit 2
fi
done
GET /api/v1/copy-tasksincludeDeleted=true|false (default: true)curl -sS --fail-with-body "${AUTH[@]}" "$BASE/api/v1/copy-tasks?includeDeleted=true"
Guidance:
includeDeleted=true when the user wants a full history or is looking for a previously deleted task.includeDeleted=false when the user only wants active/non-deleted tasks.POST /api/v1/copy-taskstargetTrader (Polymarket address of the smart money)domain.CreateCopyTaskPayload: targetUsername, taskConfig, filteredByTag, tpslRulesBefore calling: ask the user for targetTrader at minimum. Summarize and confirm.
Minimum fields to ask:
targetTraderfilteredByTag, targetUsernametaskConfig fields explicitlytpslRulesPAYLOAD="$(jq -n \
--arg targetTrader "0x..." \
'{targetTrader: $targetTrader}')"
curl -sS --fail-with-body "${AUTH[@]}" -X POST "$BASE/api/v1/copy-tasks" \
-d "$PAYLOAD"
If the user wants advanced config, build taskConfig and tpslRules explicitly instead of accepting arbitrary JSON.
Before creating a copy task, check if the user has sufficient balance:
curl -sS --fail-with-body "${AUTH[@]}" "$BASE/api/v1/portfolio/stats"
Check availableBalance from the response:
availableBalance >= 100: proceed with task creationavailableBalance < 100: show deposit guidance (see below)availableBalance < 10: strongly recommend depositing before creating any tasksDepositing is not supported via skill or API. Always direct the user to the web UI.
When balance is insufficient, present this message:
当前可用余额: $XX
建议至少 $100 才能有效跟单。充值只能通过网页端操作:
👉 https://polyhub.hubble.xyz/copy-history?action=deposit
(打开后会自动弹出充值窗口)
充值完成后回来告诉我,我帮你继续创建跟单任务。
When the user comes from a discover flow (already has a target address and optionally a tag), use this streamlined creation:
PAYLOAD="$(jq -n \
--arg targetTrader "0x..." \
--arg filteredByTag "Sports" \
'{targetTrader: $targetTrader, filteredByTag: $filteredByTag}')"
curl -sS --fail-with-body "${AUTH[@]}" -X POST "$BASE/api/v1/copy-tasks" \
-d "$PAYLOAD"
If filteredByTag is not specified (user wants all markets), omit it:
PAYLOAD="$(jq -n \
--arg targetTrader "0x..." \
'{targetTrader: $targetTrader}')"
After successful creation, show:
✅ 跟单任务已创建
📊 查看任务: https://polyhub.hubble.xyz/copy-history
GET /api/v1/copy-tasks/{taskId}curl -sS --fail-with-body "${AUTH[@]}" "$BASE/api/v1/copy-tasks/$TASK_ID"
PATCH /api/v1/copy-tasks/{taskId}statustaskConfigfilteredByTagtargetUsernametpslRules using create / update / cancelBefore calling: validate taskId, summarize changes, and confirm.
Minimum fields to ask:
taskIdstatustaskConfigtargetUsername, filteredByTagtpslRulesPAYLOAD="$(jq -n \
--arg status "PAUSED" \
'{status: $status}')"
curl -sS --fail-with-body "${AUTH[@]}" -X PATCH "$BASE/api/v1/copy-tasks/$TASK_ID" \
-d "$PAYLOAD"
Example: update taskConfig safely
PAYLOAD="$(jq -n \
--argjson buyOnly true \
--argjson maxBoughtPerMarket 50 \
'{taskConfig: {buyOnly: $buyOnly, maxBoughtPerMarket: $maxBoughtPerMarket}}')"
Example: change copy mode to ONE_TO_ONE
PAYLOAD="$(jq -n \
'{taskConfig: {copyMode: "ONE_TO_ONE"}}')"
curl -sS --fail-with-body "${AUTH[@]}" -X PATCH "$BASE/api/v1/copy-tasks/$TASK_ID" \
-d "$PAYLOAD"
Example: change copy mode to FIXED_SIZE
FIXED_SIZE should include taskConfig.fixedAmount.
PAYLOAD="$(jq -n \
--argjson fixedAmount 5 \
'{taskConfig: {copyMode: "FIXED_SIZE", fixedAmount: $fixedAmount}}')"
curl -sS --fail-with-body "${AUTH[@]}" -X PATCH "$BASE/api/v1/copy-tasks/$TASK_ID" \
-d "$PAYLOAD"
Copy mode guidance:
taskConfig.copyMode is the field that controls the task's copy mode.ONE_TO_ONE, FIXED_SIZE.FIXED_SIZE, also ask for taskConfig.fixedAmount.ONE_TO_ONE, omit fixedAmount unless the user explicitly wants to keep it stored.Use these fields when the user wants to change task-level copy behavior. Prefer changing only the fields the user explicitly asked for.
Common fields:
taskConfig.copyMode
ONE_TO_ONE, FIXED_SIZE.taskConfig.fixedAmount
copyMode=FIXED_SIZE.taskConfig.navMultiplier
1.taskConfig.positionUtilization
0, which means no filter.taskConfig.buyOnly
true, non-BUY signals are skipped.taskConfig.buyLimitPerTradeMin
0 effectively means no lower bound.taskConfig.buyLimitPerTradeMax
0 effectively means no upper bound.taskConfig.maxBoughtPerCopyTask
0 effectively means no cap.taskConfig.maxBoughtPerMarket
0 effectively means no cap.taskConfig.priceRangeMin
0.01.taskConfig.priceRangeMax
0.99.taskConfig.minLiquidity
0 effectively means no filter.taskConfig.minFillSize
0 effectively means no filter.taskConfig.maxPriceDeviation
taskConfig.expiryHours
0.taskConfig.convictionLevel
OFF, LOOSE, STANDARD, STRICT.STANDARD.Recommended clarification rules before updating:
fixedAmount.navMultiplier or fixedAmount.buyLimitPerTradeMin, buyLimitPerTradeMax, or both.maxBoughtPerCopyTask or maxBoughtPerMarket.priceRangeMin and priceRangeMax.convictionLevel.status or a taskConfig change.Example: update navMultiplier
PAYLOAD="$(jq -n \
--argjson navMultiplier 1.5 \
'{taskConfig: {navMultiplier: $navMultiplier}}')"
Example: enable buy-only mode
PAYLOAD="$(jq -n \
--argjson buyOnly true \
'{taskConfig: {buyOnly: $buyOnly}}')"
Example: limit per-trade buy amount
PAYLOAD="$(jq -n \
--argjson min 2 \
--argjson max 10 \
'{taskConfig: {buyLimitPerTradeMin: $min, buyLimitPerTradeMax: $max}}')"
Example: limit total bought amount
PAYLOAD="$(jq -n \
--argjson maxBoughtPerCopyTask 100 \
--argjson maxBoughtPerMarket 25 \
'{taskConfig: {maxBoughtPerCopyTask: $maxBoughtPerCopyTask, maxBoughtPerMarket: $maxBoughtPerMarket}}')"
Example: restrict execution price range
PAYLOAD="$(jq -n \
--argjson min 0.1 \
--argjson max 0.9 \
'{taskConfig: {priceRangeMin: $min, priceRangeMax: $max}}')"
Example: combine multiple taskConfig changes
PAYLOAD="$(jq -n \
--argjson buyOnly true \
--argjson navMultiplier 1.2 \
--argjson maxBoughtPerMarket 20 \
'{
taskConfig: {
buyOnly: $buyOnly,
navMultiplier: $navMultiplier,
maxBoughtPerMarket: $maxBoughtPerMarket
}
}')"
curl -sS --fail-with-body "${AUTH[@]}" -X PATCH "$BASE/api/v1/copy-tasks/$TASK_ID" \
-d "$PAYLOAD"
Example: update convictionLevel
PAYLOAD="$(jq -n \
--arg convictionLevel "STRICT" \
'{taskConfig: {convictionLevel: $convictionLevel}}')"
curl -sS --fail-with-body "${AUTH[@]}" -X PATCH "$BASE/api/v1/copy-tasks/$TASK_ID" \
-d "$PAYLOAD"
Conviction level guidance:
OFF: disable conviction filter.LOOSE: lower threshold, more signals can pass.STANDARD: default mode.STRICT: higher threshold, fewer signals can pass.Example: update taskConfig and status together
PAYLOAD="$(jq -n \
--arg status "RUNNING" \
--argjson buyOnly true \
'{
status: $status,
taskConfig: {
buyOnly: $buyOnly
}
}')"
curl -sS --fail-with-body "${AUTH[@]}" -X PATCH "$BASE/api/v1/copy-tasks/$TASK_ID" \
-d "$PAYLOAD"
Example: update TPSL rules safely
PAYLOAD="$(jq -n \
--arg ruleId "$RULE_ID" \
--argjson takeProfitPct 20 \
'{tpslRules: {update: [{id: $ruleId, takeProfitPct: $takeProfitPct}]}}')"
Example: update task status
PAYLOAD="$(jq -n \
--arg status "PAUSED" \
'{status: $status}')"
curl -sS --fail-with-body "${AUTH[@]}" -X PATCH "$BASE/api/v1/copy-tasks/$TASK_ID" \
-d "$PAYLOAD"
Status guidance:
status values for update are: RUNNING, PAUSED, STOPPED.PAUSED when the user wants to temporarily stop following new trades.RUNNING when the user wants to resume an active task.STOPPED only when the user explicitly wants the task stopped rather than just paused.DELETED in update payloads; deletion should use DELETE /api/v1/copy-tasks/{taskId}.DELETE /api/v1/copy-tasks/{taskId}Required flow before delete:
taskId.GET /api/v1/copy-tasks/{taskId}/positions?status=active.POST /api/v1/copy-tasks/{taskId}/sell-all.DELETE /api/v1/copy-tasks/{taskId}.Before calling: validate taskId and confirm the full sequence.
Minimum fields to ask:
taskIdPre-check active positions:
curl -sS --fail-with-body "${AUTH[@]}" "$BASE/api/v1/copy-tasks/$TASK_ID/positions?status=active"
If active positions exist, clear them first:
curl -sS --fail-with-body "${AUTH[@]}" -X POST "$BASE/api/v1/copy-tasks/$TASK_ID/sell-all"
Then delete the task:
curl -sS --fail-with-body "${AUTH[@]}" -X DELETE "$BASE/api/v1/copy-tasks/$TASK_ID"
Guidance:
sell-all as the required position cleanup step.sell-all partially skips positions, report the skipped reasons, but continue with task deletion unless the user explicitly wants to stop.GET /api/v1/copy-tasks/total-pnlcurl -sS --fail-with-body "${AUTH[@]}" "$BASE/api/v1/copy-tasks/total-pnl"
GET /api/v1/copy-tasks/{taskId}/positionsstatus (optional)
active, closedcurl -sS --fail-with-body "${AUTH[@]}" "$BASE/api/v1/copy-tasks/$TASK_ID/positions?status=active"
Guidance:
active returns positions with remaining amount above the close threshold.closed returns positions whose remaining amount is effectively zero.status is omitted or unknown, the backend currently returns all positions.active / closed rather than open / closed.GET /api/v1/copy-tasks/{taskId}/tradescurl -sS --fail-with-body "${AUTH[@]}" "$BASE/api/v1/copy-tasks/$TASK_ID/trades"
POST /api/v1/copy-tasks/{taskId}/sellmarketId (preferred) or conditionIdamount (partial sell; omit to sell full position)Before calling: validate taskId, summarize (which market, amount), and confirm.
Minimum fields to ask:
taskIdmarketId or conditionIdamount only when the user wants a partial sellPAYLOAD="$(jq -n \
--arg marketId "..." \
--argjson amount 10 \
'{marketId: $marketId, amount: $amount}')"
curl -sS --fail-with-body "${AUTH[@]}" -X POST "$BASE/api/v1/copy-tasks/$TASK_ID/sell" \
-d "$PAYLOAD"
POST /api/v1/copy-tasks/{taskId}/sell-allBefore calling: validate taskId and confirm — this sells ALL positions for the task.
Minimum fields to ask:
taskIdcurl -sS --fail-with-body "${AUTH[@]}" -X POST "$BASE/api/v1/copy-tasks/$TASK_ID/sell-all"
POST /api/v1/copy-tasks/batch-updatetaskIds (array of task IDs)status (string), taskConfig (object)Before calling: summarize which tasks and what changes, and confirm.
Minimum fields to ask:
taskIdsstatus, taskConfigTASK_IDS=("64f0c7e7b8e4f8c1a1b2c3d4" "64f0c7e7b8e4f8c1a1b2c3d5")
PAYLOAD="$(jq -n \
--arg status "PAUSED" \
--argjson taskIds "$(printf '%s\n' "${TASK_IDS[@]}" | jq -R . | jq -s .)" \
'{taskIds: $taskIds, status: $status}')"
curl -sS --fail-with-body "${AUTH[@]}" -X POST "$BASE/api/v1/copy-tasks/batch-update" \
-d "$PAYLOAD"
Example: batch update taskConfig.copyMode
TASK_IDS=("64f0c7e7b8e4f8c1a1b2c3d4" "64f0c7e7b8e4f8c1a1b2c3d5")
PAYLOAD="$(jq -n \
--argjson taskIds "$(printf '%s\n' "${TASK_IDS[@]}" | jq -R . | jq -s .)" \
'{
taskIds: $taskIds,
taskConfig: {
copyMode: "ONE_TO_ONE"
}
}')"
curl -sS --fail-with-body "${AUTH[@]}" -X POST "$BASE/api/v1/copy-tasks/batch-update" \
-d "$PAYLOAD"
Batch update guidance:
status uses the same allowed values as single-task update: RUNNING, PAUSED, STOPPED.taskConfig replaces the task config object sent in the batch request, so only send fields you intentionally want to set.status nor taskConfig is provided, the backend currently just returns the selected tasks.POST /api/v1/copy-tasks/batch-deletetaskIds (array of task IDs)Required flow before batch delete:
taskIds.GET /api/v1/copy-tasks/{taskId}/positions?status=active.POST /api/v1/copy-tasks/{taskId}/sell-all for each task that still has active positions.taskIds.Before calling: confirm the full cleanup-then-delete operation.
Minimum fields to ask:
taskIdsExample: pre-check one task's active positions
curl -sS --fail-with-body "${AUTH[@]}" "$BASE/api/v1/copy-tasks/$TASK_ID/positions?status=active"
Example: clear positions for one task before batch delete
curl -sS --fail-with-body "${AUTH[@]}" -X POST "$BASE/api/v1/copy-tasks/$TASK_ID/sell-all"
TASK_IDS=("64f0c7e7b8e4f8c1a1b2c3d4" "64f0c7e7b8e4f8c1a1b2c3d5")
PAYLOAD="$(jq -n \
--argjson taskIds "$(printf '%s\n' "${TASK_IDS[@]}" | jq -R . | jq -s .)" \
'{taskIds: $taskIds}')"
curl -sS --fail-with-body "${AUTH[@]}" -X POST "$BASE/api/v1/copy-tasks/batch-delete" \
-d "$PAYLOAD"
Guidance:
sell-all, then call batch-delete.sell-all calls skip positions, report that in the confirmation/result summary and continue unless the user explicitly asks to stop.GET /api/v1/copy-signalslimit (int, default 50)cursor (int, offset for pagination)since (RFC3339 timestamp)sinceCreatedAt (RFC3339 timestamp)action (one of: COPIED, SKIPPED, FAILED, RECEIVED)trader (address filter)curl -sS --fail-with-body "${AUTH[@]}" "$BASE/api/v1/copy-signals?limit=20&action=COPIED"
Prefer composing the query from user intent. Only pass filters the user asked for.
Validation:
limit must be a positive integer.cursor must be a non-negative integer.since and sinceCreatedAt must be RFC3339 or RFC3339Nano timestamps.action values are: COPIED, SKIPPED, FAILED, RECEIVED.Action guidance:
RECEIVED: the signal was ingested.COPIED: the copy order was placed successfully.SKIPPED: the signal was intentionally not copied because checks or limits blocked it.FAILED: the system attempted processing but failed.Example: fetch signals since a specific time
curl -sS --fail-with-body "${AUTH[@]}" \
"$BASE/api/v1/copy-signals?since=2026-03-01T00:00:00Z&limit=50"
Example: fetch next page using cursor
curl -sS --fail-with-body "${AUTH[@]}" \
"$BASE/api/v1/copy-signals?cursor=50&limit=50"
GET /api/v1/copy-signals/streamcurl -sS -N "${AUTH[@]}" "$BASE/api/v1/copy-signals/stream"
Stream guidance:
ready and copy_signal.GET /api/v1/copy-signals/statsReturns signal counts grouped by action and by trader.
curl -sS --fail-with-body "${AUTH[@]}" "$BASE/api/v1/copy-signals/stats"
GET /api/v1/copy-tasks/{taskId}/tpsl-rules/{ruleId}Minimum fields to ask:
taskId, ruleIdcurl -sS --fail-with-body "${AUTH[@]}" "$BASE/api/v1/copy-tasks/$TASK_ID/tpsl-rules/$RULE_ID"
POST /api/v1/copy-tasks/{taskId}/tpsl-rules/{ruleId}/simulateMinimum fields to ask:
taskId, ruleIdcurl -sS --fail-with-body "${AUTH[@]}" -X POST "$BASE/api/v1/copy-tasks/$TASK_ID/tpsl-rules/$RULE_ID/simulate"
When creating a task, tpslRules items may include:
sourceOrderId, sourceTypeconditionId, tokenId, assetId, entryPrice, entrySize, sidetakeProfitPct, takeProfitProb, stopLossPct, limitPriceOffset, orderTimeout, fallbackToMarketWhen updating a task, tpslRules should be wrapped as:
create: array of new inline rulesupdate: array of {id, ...patchFields}cancel: array of ruleIdExample: create a task with one TPSL rule
PAYLOAD="$(jq -n \
--arg targetTrader "0x..." \
--arg sourceOrderId "order_123" \
--arg sourceType "copy_trade" \
--argjson takeProfitPct 20 \
--argjson stopLossPct 10 \
'{
targetTrader: $targetTrader,
tpslRules: [
{
sourceOrderId: $sourceOrderId,
sourceType: $sourceType,
takeProfitPct: $takeProfitPct,
stopLossPct: $stopLossPct
}
]
}')"
401: API key missing/invalid/expired/disabled. Ask user to check or regenerate key.404: Task or resource not found. Ask user to verify taskId.409: Task already exists (duplicate targetTrader).422: Copy task limit exceeded.400: Invalid payload or invalid query param such as includeDeleted.5xx: Server error. Retry once with backoff; if still failing, report response body.