Polyhub-skills polyhub_copy
Manage copy-trading tasks, view signals, positions and trades on Polyhub using an API key.
git clone https://github.com/HubbleVision/polyhub-skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/HubbleVision/polyhub-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/openclaw/skills/polyhub_copy" ~/.claude/skills/hubblevision-polyhub-skills-polyhub-copy-8e49ed && rm -rf "$T"
T=$(mktemp -d) && git clone --depth=1 https://github.com/HubbleVision/polyhub-skills "$T" && mkdir -p ~/.openclaw/skills && cp -r "$T/openclaw/skills/polyhub_copy" ~/.openclaw/skills/hubblevision-polyhub-skills-polyhub-copy-8e49ed && rm -rf "$T"
openclaw/skills/polyhub_copy/SKILL.mdPolyhub Copy Skill
Version: v0.3.9
When to use
Use this skill when the user asks about:
- Listing, creating, updating or deleting copy-trading tasks
- Viewing copy task positions or trades
- Selling positions (single or all)
- Batch updating or deleting copy tasks
- Viewing total PnL across copy tasks
- Viewing copy signals and signal stats
- Managing take-profit / stop-loss (TPSL) rules
Requirements
is fixed toPOLYHUB_API_BASE_URL
.https://polyhub.skill-test.bedev.hubble-rpc.xyz
— API key (must start withPOLYHUB_API_KEY
)phub_
must be available in the runtime environment.curl
is strongly recommended for building JSON payloads safely.jq
If
POLYHUB_API_KEY is missing, guide the user to register and apply for one first at https://polyhub.hubble.xyz/.
Recommended guidance:
- Open Polyhub Web:
https://polyhub.hubble.xyz/ - Click the avatar menu.
- Open
.Skills API Key - Click
.申请 API Key - Set both
andPOLYHUB_API_BASE_URL
.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.
Safety rules
- Never print
in the output.POLYHUB_API_KEY - Treat all IDs and user-provided JSON fields as untrusted input.
- For write actions (
/POST
/PATCH
), repeat the action summary and wait for explicit user confirmation before calling the API.DELETE - Prefer building JSON with
instead of interpolating raw shell strings.jq -n - Validation rules:
must be a 24-char hex MongoDB ObjectID:taskId^[0-9a-fA-F]{24}$
must be non-empty.ruleId
in batch operations must all match thetaskIds
format.taskId
for positions should only be passed when the user explicitly requests a filter.status
Tools
Use the
bash tool to call the API with curl.
Fast Path
For common intents, map user requests like this:
- “列出任务” ->
GET /api/v1/copy-tasks - “删除任务” -> 先
,有 active positions 时先GET /api/v1/copy-tasks/{taskId}/positions?status=active
,再POST /api/v1/copy-tasks/{taskId}/sell-allDELETE /api/v1/copy-tasks/{taskId} - “暂停/恢复/停止任务” ->
withPATCH /api/v1/copy-tasks/{taskId}status - “改跟单模式/改单笔或总仓位限制” ->
withPATCH /api/v1/copy-tasks/{taskId}taskConfig - “看持仓/成交” ->
orGET /positionsGET /trades - “卖出某个仓位/全部仓位” ->
orPOST /sellPOST /sell-all - “看跟单信号/统计” ->
orGET /api/v1/copy-signals/stats
Curl base setup
BASE="https://polyhub.skill-test.bedev.hubble-rpc.xyz" AUTH=(-H "Authorization: Bearer $POLYHUB_API_KEY" -H "Content-Type: application/json")
Validate helpers
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
Copy Tasks
Action: List copy tasks
GET /api/v1/copy-tasks- Query params:
(default: true)includeDeleted=true|false
curl -sS --fail-with-body "${AUTH[@]}" "$BASE/api/v1/copy-tasks?includeDeleted=true"
Guidance:
- Use
when the user wants a full history or is looking for a previously deleted task.includeDeleted=true - Use
when the user only wants active/non-deleted tasks.includeDeleted=false
Action: Create copy task
POST /api/v1/copy-tasks- Required field:
(Polymarket address of the smart money)targetTrader - Optional fields from
:domain.CreateCopyTaskPayload
,targetUsername
,taskConfig
,filteredByTagtpslRules
Before calling: ask the user for
targetTrader at minimum. Summarize and confirm.
Minimum fields to ask:
- Always ask:
targetTrader - Ask only if needed:
,filteredByTagtargetUsername - If the user wants custom copy behavior: ask for the relevant
fields explicitlytaskConfig - If the user wants TPSL on creation: ask for
tpslRules
PAYLOAD="$(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.
Pre-flight: Balance Check
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:
- If
: proceed with task creationavailableBalance >= 100 - If
: show deposit guidance (see below)availableBalance < 100 - If
: strongly recommend depositing before creating any tasksavailableBalance < 10
Deposit Guidance
Depositing 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 (打开后会自动弹出充值窗口) 充值完成后回来告诉我,我帮你继续创建跟单任务。
Quick Copy from Discover
When the user comes from a discover flow (already has a target address and optionally a tag), use this streamlined creation:
- Run balance check (see Pre-flight above)
- Confirm with user: "要跟单 {address} 吗?标签: {tag or '全部市场'}"
- Create task:
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
Action: Get copy task
GET /api/v1/copy-tasks/{taskId}
curl -sS --fail-with-body "${AUTH[@]}" "$BASE/api/v1/copy-tasks/$TASK_ID"
Action: Update copy task
PATCH /api/v1/copy-tasks/{taskId}- Body: partial JSON. Common fields:
statustaskConfigfilteredByTagtargetUsername
usingtpslRules
/create
/updatecancel
Before calling: validate
taskId, summarize changes, and confirm.
Minimum fields to ask:
- Always ask:
taskId - Ask only the fields the user wants to change:
- Task lifecycle:
status - Copy behavior:
taskConfig - Trader label/tag filters:
,targetUsernamefilteredByTag - TPSL maintenance:
tpslRules
- Task lifecycle:
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"
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:
is the field that controls the task's copy mode.taskConfig.copyMode- Confirmed mode values in the current codebase:
,ONE_TO_ONE
.FIXED_SIZE - If switching to
, also ask forFIXED_SIZE
.taskConfig.fixedAmount - If switching to
, omitONE_TO_ONE
unless the user explicitly wants to keep it stored.fixedAmount
TaskConfig field guidance
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- Controls copy sizing mode.
- Confirmed values:
,ONE_TO_ONE
.FIXED_SIZE
taskConfig.fixedAmount- Used when
.copyMode=FIXED_SIZE - Represents a fixed notional amount for copied orders.
- Used when
taskConfig.navMultiplier- Multiplies the computed order size.
- Current default in backend user config is
.1
taskConfig.positionUtilization- Position utilization / max amount per copy-trade style control.
- Backend default is
, which means no filter.0
taskConfig.buyOnly- If
, non-true
signals are skipped.BUY
- If
taskConfig.buyLimitPerTradeMin- Minimum allowed copied buy amount per trade.
effectively means no lower bound.0
taskConfig.buyLimitPerTradeMax- Maximum allowed copied buy amount per trade.
effectively means no upper bound.0
taskConfig.maxBoughtPerCopyTask- Caps total bought amount at task level.
effectively means no cap.0
taskConfig.maxBoughtPerMarket- Caps total bought amount for a single market inside the task.
effectively means no cap.0
taskConfig.priceRangeMin- Minimum allowed execution price.
- Default from user config is typically
.0.01
taskConfig.priceRangeMax- Maximum allowed execution price.
- Default from user config is typically
.0.99
taskConfig.minLiquidity- Minimum market liquidity filter.
effectively means no filter.0
taskConfig.minFillSize- Minimum fill shares filter.
effectively means no filter.0
taskConfig.maxPriceDeviation- Maximum allowed price deviation percentage.
taskConfig.expiryHours- Order expiry configuration for copied orders.
- Backend default from user config is typically
.0
taskConfig.convictionLevel- Conviction-based filter level.
- Confirmed values:
,OFF
,LOOSE
,STANDARD
.STRICT - Backend default is
.STANDARD
Recommended clarification rules before updating:
- If the user says “改成固定金额跟单”, ask for
.fixedAmount - If the user says “放大/缩小仓位”, clarify whether they mean
ornavMultiplier
.fixedAmount - If the user says “限制单笔金额”, clarify whether they mean
,buyLimitPerTradeMin
, or both.buyLimitPerTradeMax - If the user says “限制总仓位”, clarify whether they mean
ormaxBoughtPerCopyTask
.maxBoughtPerMarket - If the user says “限制价格区间”, ask for both
andpriceRangeMin
.priceRangeMax - If the user says “调严格一点/调宽松一点”, clarify whether they mean
.convictionLevel - If the user says “恢复跟单/暂停跟单/停止任务”, clarify whether they mean task
or astatus
change.taskConfig
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:
: disable conviction filter.OFF
: lower threshold, more signals can pass.LOOSE
: default mode.STANDARD
: higher threshold, fewer signals can pass.STRICT- If the user gives an unknown value, normalize to one of the four explicit options before calling the API.
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:
- Valid task
values for update are:status
,RUNNING
,PAUSED
.STOPPED - Use
when the user wants to temporarily stop following new trades.PAUSED - Use
when the user wants to resume an active task.RUNNING - Use
only when the user explicitly wants the task stopped rather than just paused.STOPPED - Do not use
in update payloads; deletion should useDELETED
.DELETE /api/v1/copy-tasks/{taskId} - Prefer uppercase status values in payloads.
Action: Delete copy task
DELETE /api/v1/copy-tasks/{taskId}
Required flow before delete:
- Validate
.taskId - Check active positions with
.GET /api/v1/copy-tasks/{taskId}/positions?status=active - If any active positions exist, restate that deleting the task will first clear those positions, then delete the task.
- After explicit confirmation, call
.POST /api/v1/copy-tasks/{taskId}/sell-all - Only after the position cleanup step finishes, call
.DELETE /api/v1/copy-tasks/{taskId}
Before calling: validate
taskId and confirm the full sequence.
Minimum fields to ask:
- Always ask:
taskId
Pre-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:
- There is no dedicated API to delete positions directly; use
as the required position cleanup step.sell-all - If no active positions are returned, delete the task directly after confirmation.
- If
partially skips positions, report the skipped reasons, but continue with task deletion unless the user explicitly wants to stop.sell-all
Action: Get total PnL
GET /api/v1/copy-tasks/total-pnl
curl -sS --fail-with-body "${AUTH[@]}" "$BASE/api/v1/copy-tasks/total-pnl"
Positions & Trades
Action: List positions
GET /api/v1/copy-tasks/{taskId}/positions- Query params:
(optional)status- Confirmed values in current code:
,activeclosed
- Confirmed values in current code:
curl -sS --fail-with-body "${AUTH[@]}" "$BASE/api/v1/copy-tasks/$TASK_ID/positions?status=active"
Guidance:
returns positions with remaining amount above the close threshold.active
returns positions whose remaining amount is effectively zero.closed- If
is omitted or unknown, the backend currently returns all positions.status - Prefer
/active
rather thanclosed
/open
.closed
Action: List trades
GET /api/v1/copy-tasks/{taskId}/trades
curl -sS --fail-with-body "${AUTH[@]}" "$BASE/api/v1/copy-tasks/$TASK_ID/trades"
Action: Sell position
POST /api/v1/copy-tasks/{taskId}/sell- Required field:
(preferred) ormarketIdconditionId - Optional field:
(partial sell; omit to sell full position)amount
Before calling: validate
taskId, summarize (which market, amount), and confirm.
Minimum fields to ask:
- Always ask:
taskId - Always ask one of:
ormarketIdconditionId - Ask
only when the user wants a partial sellamount
PAYLOAD="$(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"
Action: Sell all positions
POST /api/v1/copy-tasks/{taskId}/sell-all
Before calling: validate
taskId and confirm — this sells ALL positions for the task.
Minimum fields to ask:
- Always ask:
taskId
curl -sS --fail-with-body "${AUTH[@]}" -X POST "$BASE/api/v1/copy-tasks/$TASK_ID/sell-all"
Batch Operations
Action: Batch update tasks
POST /api/v1/copy-tasks/batch-update- Required:
(array of task IDs)taskIds - Optional:
(string),status
(object)taskConfig
Before calling: summarize which tasks and what changes, and confirm.
Minimum fields to ask:
- Always ask:
taskIds - Ask at least one of:
,statustaskConfig
TASK_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:
uses the same allowed values as single-task update:status
,RUNNING
,PAUSED
.STOPPED
replaces the task config object sent in the batch request, so only send fields you intentionally want to set.taskConfig- If neither
norstatus
is provided, the backend currently just returns the selected tasks.taskConfig - Use batch update only when the same change should apply to all listed tasks.
Action: Batch delete tasks
POST /api/v1/copy-tasks/batch-delete- Required:
(array of task IDs)taskIds
Required flow before batch delete:
- Validate all
.taskIds - For each task, check
.GET /api/v1/copy-tasks/{taskId}/positions?status=active - If a task has active positions, include it in the confirmation summary and state that those positions will be cleared before deletion.
- After explicit confirmation, run
for each task that still has active positions.POST /api/v1/copy-tasks/{taskId}/sell-all - After the position cleanup passes finish, call batch delete once with all
.taskIds
Before calling: confirm the full cleanup-then-delete operation.
Minimum fields to ask:
- Always ask:
taskIds
Example: 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:
- There is no batch position-delete endpoint; clean positions task by task with
, then callsell-all
.batch-delete - If some
calls skip positions, report that in the confirmation/result summary and continue unless the user explicitly asks to stop.sell-all
Copy Signals
Action: List copy signals
GET /api/v1/copy-signals- Query params:
(int, default 50)limit
(int, offset for pagination)cursor
(RFC3339 timestamp)since
(RFC3339 timestamp)sinceCreatedAt
(one of:action
,COPIED
,SKIPPED
,FAILED
)RECEIVED
(address filter)trader
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:
must be a positive integer.limit
must be a non-negative integer.cursor
andsince
must be RFC3339 or RFC3339Nano timestamps.sinceCreatedAt- Valid
values are:action
,COPIED
,SKIPPED
,FAILED
.RECEIVED
Action guidance:
: the signal was ingested.RECEIVED
: the copy order was placed successfully.COPIED
: the signal was intentionally not copied because checks or limits blocked it.SKIPPED
: the system attempted processing but failed.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"
Action: Stream copy signals
GET /api/v1/copy-signals/stream- Response type: Server-Sent Events (SSE)
curl -sS -N "${AUTH[@]}" "$BASE/api/v1/copy-signals/stream"
Stream guidance:
- Use this only when the user explicitly wants real-time signal updates.
- Expect events such as
andready
.copy_signal - Keep the connection open; this is not a one-shot request.
Action: Get signal stats
GET /api/v1/copy-signals/stats
Returns signal counts grouped by action and by trader.
curl -sS --fail-with-body "${AUTH[@]}" "$BASE/api/v1/copy-signals/stats"
TPSL Rules (Take-Profit / Stop-Loss)
Action: Get TPSL rule
GET /api/v1/copy-tasks/{taskId}/tpsl-rules/{ruleId}
Minimum fields to ask:
- Always ask:
,taskIdruleId
curl -sS --fail-with-body "${AUTH[@]}" "$BASE/api/v1/copy-tasks/$TASK_ID/tpsl-rules/$RULE_ID"
Action: Simulate TPSL rule
POST /api/v1/copy-tasks/{taskId}/tpsl-rules/{ruleId}/simulate
Minimum fields to ask:
- Always ask:
,taskIdruleId
curl -sS --fail-with-body "${AUTH[@]}" -X POST "$BASE/api/v1/copy-tasks/$TASK_ID/tpsl-rules/$RULE_ID/simulate"
TPSL inline payload guidance
When creating a task,
tpslRules items may include:
,sourceOrderIdsourceType- Optional entry info:
,conditionId
,tokenId
,assetId
,entryPrice
,entrySizeside - Optional risk config:
,takeProfitPct
,takeProfitProb
,stopLossPct
,limitPriceOffset
,orderTimeoutfallbackToMarket
When updating a task,
tpslRules should be wrapped as:
: array of new inline rulescreate
: array ofupdate{id, ...patchFields}
: array ofcancelruleId
Example: 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 } ] }')"
Error handling
: API key missing/invalid/expired/disabled. Ask user to check or regenerate key.401
: Task or resource not found. Ask user to verify404
.taskId
: Task already exists (duplicate409
).targetTrader
: Copy task limit exceeded.422
: Invalid payload or invalid query param such as400
.includeDeleted
: Server error. Retry once with backoff; if still failing, report response body.5xx