perp-cli 0.4.2 → 0.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/README.md +46 -5
  2. package/dist/arb/reconcile.d.ts +28 -0
  3. package/dist/arb/reconcile.js +162 -0
  4. package/dist/arb/sizing.d.ts +12 -1
  5. package/dist/arb/sizing.js +38 -5
  6. package/dist/arb/state.d.ts +6 -0
  7. package/dist/cli-spec.d.ts +0 -4
  8. package/dist/cli-spec.js +8 -1
  9. package/dist/commands/account.d.ts +1 -1
  10. package/dist/commands/account.js +300 -63
  11. package/dist/commands/agent.js +16 -9
  12. package/dist/commands/arb/index.js +243 -49
  13. package/dist/commands/arb-auto.js +696 -9
  14. package/dist/commands/arb.d.ts +2 -1
  15. package/dist/commands/arb.js +535 -131
  16. package/dist/commands/bot.js +207 -0
  17. package/dist/commands/dex.js +7 -1
  18. package/dist/commands/funding.d.ts +2 -1
  19. package/dist/commands/funding.js +211 -4
  20. package/dist/commands/funds.d.ts +4 -0
  21. package/dist/commands/funds.js +741 -0
  22. package/dist/commands/history.d.ts +2 -1
  23. package/dist/commands/history.js +508 -5
  24. package/dist/commands/manage.js +6 -4
  25. package/dist/commands/market.js +35 -2
  26. package/dist/commands/multileg.d.ts +16 -0
  27. package/dist/commands/multileg.js +174 -0
  28. package/dist/commands/pnl.d.ts +12 -0
  29. package/dist/commands/pnl.js +243 -0
  30. package/dist/commands/risk.d.ts +2 -0
  31. package/dist/commands/risk.js +56 -0
  32. package/dist/commands/settings.js +147 -0
  33. package/dist/commands/stream.js +132 -55
  34. package/dist/commands/trade.d.ts +1 -1
  35. package/dist/commands/trade.js +270 -267
  36. package/dist/commands/wallet.d.ts +4 -0
  37. package/dist/commands/wallet.js +11 -1
  38. package/dist/config.d.ts +6 -1
  39. package/dist/config.js +21 -1
  40. package/dist/dashboard/ws-feeds.js +1 -1
  41. package/dist/equity-tracker.d.ts +57 -0
  42. package/dist/equity-tracker.js +209 -0
  43. package/dist/exchanges/hyperliquid-spot.d.ts +69 -0
  44. package/dist/exchanges/hyperliquid-spot.js +309 -0
  45. package/dist/exchanges/hyperliquid.d.ts +26 -5
  46. package/dist/exchanges/hyperliquid.js +171 -73
  47. package/dist/exchanges/interface.d.ts +1 -1
  48. package/dist/exchanges/lighter-spot.d.ts +55 -0
  49. package/dist/exchanges/lighter-spot.js +415 -0
  50. package/dist/exchanges/lighter.d.ts +10 -2
  51. package/dist/exchanges/lighter.js +210 -56
  52. package/dist/exchanges/pacifica.d.ts +11 -4
  53. package/dist/exchanges/pacifica.js +64 -37
  54. package/dist/exchanges/spot-interface.d.ts +45 -0
  55. package/dist/exchanges/spot-interface.js +22 -0
  56. package/dist/execution-log.d.ts +2 -2
  57. package/dist/funding/rates.d.ts +36 -0
  58. package/dist/funding/rates.js +146 -0
  59. package/dist/index.js +126 -161
  60. package/dist/liquidity.d.ts +12 -0
  61. package/dist/liquidity.js +43 -0
  62. package/dist/mcp-server.js +43 -96
  63. package/dist/signer/evm-local.d.ts +12 -0
  64. package/dist/signer/evm-local.js +19 -0
  65. package/dist/signer/index.d.ts +3 -0
  66. package/dist/signer/index.js +2 -0
  67. package/dist/signer/interface.d.ts +31 -0
  68. package/dist/signer/interface.js +7 -0
  69. package/dist/signer/solana-local.d.ts +13 -0
  70. package/dist/signer/solana-local.js +19 -0
  71. package/dist/smart-order.js +14 -3
  72. package/dist/strategies/split-order.d.ts +49 -0
  73. package/dist/strategies/split-order.js +138 -0
  74. package/dist/utils.js +7 -1
  75. package/dist/ws/market-feed.d.ts +74 -0
  76. package/dist/ws/market-feed.js +227 -0
  77. package/package.json +1 -1
  78. package/skills/perp-cli/SKILL.md +80 -4
  79. package/skills/perp-cli/references/agent-operations.md +19 -9
  80. package/skills/perp-cli/references/commands.md +54 -32
  81. package/skills/perp-cli/references/strategies.md +27 -17
  82. package/skills/perp-cli/scripts/arb-monitor.sh +74 -0
  83. package/skills/perp-cli/scripts/funding-analysis.sh +85 -0
  84. package/skills/perp-cli/scripts/preflight.sh +98 -0
  85. package/skills/perp-cli/scripts/spot-perp-scan.sh +83 -0
  86. package/skills/perp-cli/scripts/validate-arb.sh +112 -0
  87. package/skills/perp-cli/templates/arb-scan.sh +0 -15
  88. package/skills/perp-cli/templates/open-position.sh +0 -38
  89. package/skills/perp-cli/templates/wallet-setup.sh +0 -17
@@ -173,7 +173,7 @@ Desired size: 1.0
173
173
 
174
174
  **CRITICAL: Each exchange has its own minimum order size and step size.**
175
175
  ```bash
176
- perp --json -e <EX> market info <SYM> # check minOrderSize, stepSize
176
+ perp --json -e <EX> market info <SYM> # check maxLeverage, volume, openInterest
177
177
  ```
178
178
  Round `ORDER_SIZE` to the coarser step size of the two exchanges. If the matched size falls below either exchange's minimum, the arb is NOT executable at this size — reduce target or skip.
179
179
 
@@ -202,19 +202,38 @@ perp --json -e <SHORT_EX> account positions # size must = X
202
202
  ```
203
203
  If sizes differ (partial fill, rounding), immediately adjust the larger position to match the smaller one.
204
204
 
205
- #### Step 3: Split Large Orders into Matched Chunks
205
+ #### Step 3: Split Large Orders with `trade split`
206
206
 
207
- If your desired size exceeds what the orderbooks can absorb at best ticks, split into chunks — but **every chunk must be a matched pair with identical size on both sides**:
207
+ For large orders, use the built-in orderbook-aware split execution instead of manual chunking:
208
208
 
209
+ ```bash
210
+ # Single exchange: split $5000 buy into depth-based slices
211
+ perp --json -e <EX> trade split <SYM> buy 5000
212
+
213
+ # With options
214
+ perp --json -e <EX> trade split <SYM> buy 5000 --max-slippage 0.5 --max-slices 5 --delay 2000
215
+
216
+ # Or use --split flag on market command
217
+ perp --json -e <EX> trade market <SYM> buy <SIZE> --split
209
218
  ```
210
- Chunk 1: buy 0.3 on Exchange A → sell 0.3 on Exchange B → verify both
211
- Chunk 2: buy 0.3 on Exchange A → sell 0.3 on Exchange B → verify both
212
- ... repeat until full size is executed
219
+
220
+ How it works:
221
+ 1. Fetches fresh orderbook before each slice
222
+ 2. Walks levels via `computeExecutableSize` to find fillable amount at target slippage
223
+ 3. Places IOC limit at worst acceptable price within slippage tolerance
224
+ 4. Waits for book to refresh, repeats until target filled or max slices reached
225
+
226
+ **For arb, both legs must still match.** Use `trade split` on each side independently with the same total USD, then verify sizes match:
227
+
228
+ ```
229
+ Leg A: perp --json -e <LONG_EX> trade split <SYM> buy 5000
230
+ Leg B: perp --json -e <SHORT_EX> trade split <SYM> sell 5000
231
+ → Verify positions, adjust if sizes differ
213
232
  ```
214
233
 
215
234
  **Rules:**
216
- 1. Re-check orderbook depth between chunks — liquidity changes
217
- 2. Each chunk: same size on both sides, no exceptions
235
+ 1. Each chunk re-checks orderbook depth — liquidity changes between slices
236
+ 2. For arb: same total USD on both sides, verify matched sizes after execution
218
237
  3. If one leg fails → STOP immediately, do NOT continue
219
238
  4. Assess exposure: retry the failed leg, or unwind the completed leg
220
239
  5. NEVER execute multiple orders on one side without matching the other
@@ -418,15 +437,6 @@ Or use TP/SL together:
418
437
  perp --json -e <EX> trade tp-sl <SYM> --tp <PRICE> --sl <PRICE>
419
438
  ```
420
439
 
421
- ### Monitoring Alerts
422
-
423
- Set up alerts so you get notified of dangerous conditions without polling:
424
- ```bash
425
- perp --json alert add -t margin --margin-pct 70 # alert when margin usage > 70%
426
- perp --json alert add -t price -s BTC --below 50000 --above 80000 # price boundaries
427
- perp --json alert add -t funding -s ETH --spread 50 # funding spread alert
428
- ```
429
-
430
440
  ### What to Track Over Time
431
441
  As you operate, build awareness of:
432
442
  - Which symbols consistently have the best funding spreads
@@ -0,0 +1,74 @@
1
+ #!/bin/bash
2
+ # Monitor open arb positions and evaluate exit conditions
3
+ # Usage: ./arb-monitor.sh [--json] [--min-spread 5]
4
+ # Checks: current spread vs entry, funding earned, PnL, liquidation distance
5
+ # Returns JSON with position health + actionable recommendations
6
+
7
+ set -euo pipefail
8
+
9
+ # Auto-detect perp command (supports npx fallback for agents without install permissions)
10
+ if command -v perp &>/dev/null; then
11
+ PERP="perp"
12
+ else
13
+ PERP="npx -y perp-cli@latest"
14
+ fi
15
+
16
+ JSON_MODE=false
17
+ MIN_SPREAD=5
18
+ while [[ $# -gt 0 ]]; do
19
+ case "$1" in
20
+ --json) JSON_MODE=true; shift ;;
21
+ --min-spread) MIN_SPREAD="$2"; shift 2 ;;
22
+ *) shift ;;
23
+ esac
24
+ done
25
+
26
+ # 1. Get current arb status
27
+ ARB_STATUS=$($PERP --json arb status 2>/dev/null || echo '{"ok":false}')
28
+ if ! echo "$ARB_STATUS" | grep -q '"ok":true'; then
29
+ if $JSON_MODE; then
30
+ echo '{"ok":false,"error":"No arb positions or arb status unavailable"}'
31
+ else
32
+ echo "No open arb positions found."
33
+ fi
34
+ exit 0
35
+ fi
36
+
37
+ # 2. Get current spreads
38
+ ARB_SCAN=$($PERP --json arb scan --min 0 2>/dev/null || echo '{"ok":false,"data":{"opportunities":[]}}')
39
+
40
+ # 3. Get funding earned
41
+ FUNDING=$($PERP --json arb funding-earned 2>/dev/null || echo '{"ok":false}')
42
+
43
+ # 4. Get liquidation distances
44
+ LIQ_DIST=$($PERP --json risk liquidation-distance 2>/dev/null || echo '{"ok":false}')
45
+
46
+ # 5. Output combined analysis
47
+ if $JSON_MODE; then
48
+ cat <<EOF
49
+ {
50
+ "ok": true,
51
+ "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
52
+ "positions": $ARB_STATUS,
53
+ "currentSpreads": $ARB_SCAN,
54
+ "fundingEarned": $FUNDING,
55
+ "liquidationDistance": $LIQ_DIST,
56
+ "minSpreadThreshold": $MIN_SPREAD
57
+ }
58
+ EOF
59
+ else
60
+ echo "=== Arb Position Monitor ==="
61
+ echo "Timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
62
+ echo ""
63
+ echo "--- Positions ---"
64
+ echo "$ARB_STATUS" | jq -r '.data // empty'
65
+ echo ""
66
+ echo "--- Funding Earned ---"
67
+ echo "$FUNDING" | jq -r '.data // empty'
68
+ echo ""
69
+ echo "--- Liquidation Distance ---"
70
+ echo "$LIQ_DIST" | jq -r '.data // empty'
71
+ echo ""
72
+ echo "Min spread threshold: ${MIN_SPREAD} bps"
73
+ echo "Recommendation: Check if current spreads exceed ${MIN_SPREAD} bps to continue holding."
74
+ fi
@@ -0,0 +1,85 @@
1
+ #!/bin/bash
2
+ # Funding rate analysis across all exchanges
3
+ # Usage: ./funding-analysis.sh [--json] [--symbol ETH] [--top 10]
4
+ # Fetches current + historical funding data for comparison
5
+
6
+ set -euo pipefail
7
+
8
+ # Auto-detect perp command (supports npx fallback for agents without install permissions)
9
+ if command -v perp &>/dev/null; then
10
+ PERP="perp"
11
+ else
12
+ PERP="npx -y perp-cli@latest"
13
+ fi
14
+
15
+ JSON_MODE=false
16
+ SYMBOL=""
17
+ TOP=10
18
+ while [[ $# -gt 0 ]]; do
19
+ case "$1" in
20
+ --json) JSON_MODE=true; shift ;;
21
+ --symbol) SYMBOL="$2"; shift 2 ;;
22
+ --top) TOP="$2"; shift 2 ;;
23
+ *) shift ;;
24
+ esac
25
+ done
26
+
27
+ if [[ -n "$SYMBOL" ]]; then
28
+ # Single symbol detailed analysis
29
+ FUNDING=$($PERP --json market funding "$SYMBOL" 2>/dev/null || echo '{"ok":false}')
30
+ SCAN=$($PERP --json arb scan --min 0 2>/dev/null || echo '{"ok":false}')
31
+ SPOT_SCAN=$($PERP --json arb scan --mode spot-perp --min 0 2>/dev/null || echo '{"ok":false}')
32
+
33
+ if $JSON_MODE; then
34
+ cat <<EOF
35
+ {
36
+ "ok": true,
37
+ "symbol": "$SYMBOL",
38
+ "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
39
+ "funding": $FUNDING,
40
+ "perpPerpArb": $SCAN,
41
+ "spotPerpArb": $SPOT_SCAN
42
+ }
43
+ EOF
44
+ else
45
+ echo "=== Funding Analysis: $SYMBOL ==="
46
+ echo ""
47
+ echo "--- Current Funding Rates ---"
48
+ echo "$FUNDING" | jq -r '.data // empty' 2>/dev/null || echo "(unavailable)"
49
+ echo ""
50
+ echo "--- Perp-Perp Arb ---"
51
+ echo "$SCAN" | jq -r '
52
+ .data // [] | map(select(.symbol == "'"$SYMBOL"'")) | .[] |
53
+ " \(.longExch // .longExchange)→\(.shortExch // .shortExchange): \(.netSpread // .spread)bps"
54
+ ' 2>/dev/null || echo " (no opportunity)"
55
+ echo ""
56
+ echo "--- Spot+Perp Arb ---"
57
+ echo "$SPOT_SCAN" | jq -r '
58
+ .data // [] | map(select(.symbol == "'"$SYMBOL"'")) | .[] |
59
+ " \(.direction): \(.annualSpreadPct // .spread)% annual"
60
+ ' 2>/dev/null || echo " (no opportunity)"
61
+ fi
62
+ else
63
+ # All symbols scan
64
+ SCAN=$($PERP --json arb scan --mode all --min 0 2>/dev/null || echo '{"ok":false}')
65
+ FUNDING_DETAIL=$($PERP --json arb rates 2>/dev/null || echo '{"ok":false}')
66
+
67
+ if $JSON_MODE; then
68
+ cat <<EOF
69
+ {
70
+ "ok": true,
71
+ "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
72
+ "topN": $TOP,
73
+ "allOpportunities": $SCAN,
74
+ "ratesDetail": $FUNDING_DETAIL
75
+ }
76
+ EOF
77
+ else
78
+ echo "=== Funding Rate Overview (top $TOP) ==="
79
+ echo ""
80
+ echo "$SCAN" | jq -r "
81
+ .data // [] | .[0:$TOP] | .[] |
82
+ \" \(.symbol) | \(.mode // \"perp\") | \(.netSpread // .spread)bps | \(.longExch // .longExchange)→\(.shortExch // .shortExchange)\"
83
+ " 2>/dev/null || echo "(no data)"
84
+ fi
85
+ fi
@@ -0,0 +1,98 @@
1
+ #!/bin/bash
2
+ # Pre-flight validation for perp-cli operations
3
+ # Checks: install, wallet, connectivity, balances, risk
4
+ # Usage: ./preflight.sh [--json]
5
+ # Returns JSON with { ready: bool, checks: [...], issues: [...] }
6
+
7
+ set -euo pipefail
8
+
9
+ # Auto-detect perp command (supports npx fallback for agents without install permissions)
10
+ if command -v perp &>/dev/null; then
11
+ PERP="perp"
12
+ else
13
+ PERP="npx -y perp-cli@latest"
14
+ fi
15
+
16
+ JSON_MODE=false
17
+ [[ "${1:-}" == "--json" ]] && JSON_MODE=true
18
+
19
+ issues=()
20
+ checks=()
21
+
22
+ add_check() {
23
+ local name="$1" status="$2" detail="$3"
24
+ checks+=("{\"name\":\"$name\",\"status\":\"$status\",\"detail\":\"$detail\"}")
25
+ [[ "$status" == "fail" ]] && issues+=("$name: $detail")
26
+ }
27
+
28
+ # 1. perp-cli installed and version check
29
+ VERSION=$($PERP --version 2>/dev/null || echo "unknown")
30
+ if [[ "$VERSION" != "unknown" ]]; then
31
+ add_check "install" "pass" "perp-cli $VERSION ($(command -v perp &>/dev/null && echo 'global' || echo 'npx'))"
32
+ else
33
+ add_check "install" "fail" "perp-cli not found — run: npm i -g perp-cli@latest or use npx"
34
+ fi
35
+
36
+ # 2. Wallet configured
37
+ WALLET_OUT=$($PERP --json wallet show 2>/dev/null || echo '{"ok":false}')
38
+ if echo "$WALLET_OUT" | grep -q '"ok":true'; then
39
+ add_check "wallet" "pass" "Wallet configured"
40
+ else
41
+ add_check "wallet" "fail" "No wallet configured — run: perp wallet set <exchange> <key>"
42
+ fi
43
+
44
+ # 3. Exchange connectivity
45
+ HEALTH_OUT=$($PERP --json agent ping 2>/dev/null || echo '{"ok":false}')
46
+ if echo "$HEALTH_OUT" | grep -q '"ok":true'; then
47
+ add_check "connectivity" "pass" "Exchanges reachable"
48
+ else
49
+ add_check "connectivity" "warn" "Some exchanges unreachable"
50
+ fi
51
+
52
+ # 4. Portfolio & balances
53
+ PORTFOLIO_OUT=$($PERP --json portfolio 2>/dev/null || echo '{"ok":false}')
54
+ if echo "$PORTFOLIO_OUT" | grep -q '"ok":true'; then
55
+ add_check "portfolio" "pass" "Portfolio accessible"
56
+ else
57
+ add_check "portfolio" "warn" "Could not fetch portfolio"
58
+ fi
59
+
60
+ # 5. Risk status
61
+ RISK_OUT=$($PERP --json risk status 2>/dev/null || echo '{"ok":false}')
62
+ if echo "$RISK_OUT" | grep -q '"canTrade":true'; then
63
+ add_check "risk" "pass" "Trading allowed (canTrade=true)"
64
+ elif echo "$RISK_OUT" | grep -q '"canTrade":false'; then
65
+ add_check "risk" "fail" "Trading blocked — check risk violations"
66
+ else
67
+ add_check "risk" "warn" "Could not check risk status"
68
+ fi
69
+
70
+ # Output
71
+ READY=true
72
+ [[ ${#issues[@]} -gt 0 ]] && READY=false
73
+
74
+ if $JSON_MODE; then
75
+ CHECKS_JSON=$(IFS=,; echo "${checks[*]}")
76
+ ISSUES_JSON=$(printf '%s\n' "${issues[@]}" | jq -R . | jq -s .)
77
+ echo "{\"ready\":$READY,\"checks\":[$CHECKS_JSON],\"issues\":$ISSUES_JSON}"
78
+ else
79
+ echo "=== perp-cli Pre-flight Check ==="
80
+ for c in "${checks[@]}"; do
81
+ name=$(echo "$c" | jq -r .name)
82
+ status=$(echo "$c" | jq -r .status)
83
+ detail=$(echo "$c" | jq -r .detail)
84
+ case "$status" in
85
+ pass) icon="✓" ;;
86
+ warn) icon="⚠" ;;
87
+ fail) icon="✗" ;;
88
+ esac
89
+ printf " %s %-15s %s\n" "$icon" "$name" "$detail"
90
+ done
91
+ echo ""
92
+ if $READY; then
93
+ echo "Ready to trade."
94
+ else
95
+ echo "Issues found:"
96
+ for i in "${issues[@]}"; do echo " - $i"; done
97
+ fi
98
+ fi
@@ -0,0 +1,83 @@
1
+ #!/bin/bash
2
+ # Scan spot+perp funding rate arbitrage opportunities
3
+ # Usage: ./spot-perp-scan.sh [--json] [--mode all|spot-perp|perp-perp] [--min 10]
4
+ # Combines perp-perp and spot-perp scans with validation
5
+
6
+ set -euo pipefail
7
+
8
+ # Auto-detect perp command (supports npx fallback for agents without install permissions)
9
+ if command -v perp &>/dev/null; then
10
+ PERP="perp"
11
+ else
12
+ PERP="npx -y perp-cli@latest"
13
+ fi
14
+
15
+ JSON_MODE=false
16
+ MODE="all"
17
+ MIN_SPREAD=10
18
+ while [[ $# -gt 0 ]]; do
19
+ case "$1" in
20
+ --json) JSON_MODE=true; shift ;;
21
+ --mode) MODE="$2"; shift 2 ;;
22
+ --min) MIN_SPREAD="$2"; shift 2 ;;
23
+ *) shift ;;
24
+ esac
25
+ done
26
+
27
+ # 1. Portfolio check (ensure we have balances)
28
+ PORTFOLIO=$($PERP --json portfolio 2>/dev/null || echo '{"ok":false}')
29
+ if ! echo "$PORTFOLIO" | grep -q '"ok":true'; then
30
+ if $JSON_MODE; then
31
+ echo '{"ok":false,"error":"Cannot fetch portfolio — check wallet setup"}'
32
+ else
33
+ echo "ERROR: Cannot fetch portfolio. Check wallet setup first."
34
+ fi
35
+ exit 1
36
+ fi
37
+
38
+ # 2. Run appropriate scan
39
+ SCAN_RESULT=$($PERP --json arb scan --mode "$MODE" --min "$MIN_SPREAD" 2>/dev/null || echo '{"ok":false}')
40
+
41
+ # 3. Get exchange health for context
42
+ HEALTH=$($PERP --json agent ping 2>/dev/null || echo '{"ok":false}')
43
+
44
+ if $JSON_MODE; then
45
+ cat <<EOF
46
+ {
47
+ "ok": true,
48
+ "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
49
+ "mode": "$MODE",
50
+ "minSpread": $MIN_SPREAD,
51
+ "portfolio": $PORTFOLIO,
52
+ "scan": $SCAN_RESULT,
53
+ "health": $HEALTH
54
+ }
55
+ EOF
56
+ else
57
+ echo "=== Spot+Perp Arb Scanner ==="
58
+ echo "Mode: $MODE | Min spread: ${MIN_SPREAD} bps"
59
+ echo ""
60
+
61
+ # Show balances
62
+ echo "--- Balances ---"
63
+ echo "$PORTFOLIO" | jq -r '
64
+ .data.exchanges // [] | .[] |
65
+ " \(.exchange): $\(.balance // .equity // "N/A")"
66
+ ' 2>/dev/null || echo " (unable to parse)"
67
+ echo ""
68
+
69
+ # Show opportunities
70
+ echo "--- Opportunities ---"
71
+ echo "$SCAN_RESULT" | jq -r '
72
+ .data // [] | .[] |
73
+ " \(.symbol) | \(.mode // "perp-perp") | spread: \(.netSpread // .spread)bps | \(.longExch // .longExchange)→\(.shortExch // .shortExchange)"
74
+ ' 2>/dev/null || echo " (no opportunities or parse error)"
75
+
76
+ # Show exchange health
77
+ echo ""
78
+ echo "--- Exchange Health ---"
79
+ echo "$HEALTH" | jq -r '
80
+ .data // {} | to_entries[] |
81
+ " \(.key): \(.value.status // .value // "unknown")"
82
+ ' 2>/dev/null || echo " (unable to check)"
83
+ fi
@@ -0,0 +1,112 @@
1
+ #!/bin/bash
2
+ # Validate an arb opportunity before execution
3
+ # Usage: ./validate-arb.sh <SYMBOL> <LONG_EX> <SHORT_EX> <SIZE_USD> [--leverage N]
4
+ # Performs: price check, liquidity check, balance check, risk check, slippage estimate
5
+ # Returns JSON validation report
6
+
7
+ set -euo pipefail
8
+
9
+ # Auto-detect perp command (supports npx fallback for agents without install permissions)
10
+ if command -v perp &>/dev/null; then
11
+ PERP="perp"
12
+ else
13
+ PERP="npx -y perp-cli@latest"
14
+ fi
15
+
16
+ SYM="${1:?Usage: validate-arb.sh <SYMBOL> <LONG_EX> <SHORT_EX> <SIZE_USD> [--leverage N]}"
17
+ LONG_EX="${2:?Usage: validate-arb.sh <SYMBOL> <LONG_EX> <SHORT_EX> <SIZE_USD>}"
18
+ SHORT_EX="${3:?Usage: validate-arb.sh <SYMBOL> <LONG_EX> <SHORT_EX> <SIZE_USD>}"
19
+ SIZE="${4:?Usage: validate-arb.sh <SYMBOL> <LONG_EX> <SHORT_EX> <SIZE_USD>}"
20
+ LEVERAGE=""
21
+
22
+ shift 4
23
+ while [[ $# -gt 0 ]]; do
24
+ case "$1" in
25
+ --leverage) LEVERAGE="$2"; shift 2 ;;
26
+ *) shift ;;
27
+ esac
28
+ done
29
+
30
+ checks=()
31
+ pass=true
32
+
33
+ add_result() {
34
+ local name="$1" ok="$2" detail="$3"
35
+ checks+=("{\"check\":\"$name\",\"ok\":$ok,\"detail\":\"$detail\"}")
36
+ [[ "$ok" == "false" ]] && pass=false
37
+ }
38
+
39
+ # 1. Price comparison — both exchanges must report similar prices
40
+ LONG_PRICE=$($PERP --json -e "$LONG_EX" market mid "$SYM" 2>/dev/null | jq -r '.data.mid // "0"')
41
+ SHORT_PRICE=$($PERP --json -e "$SHORT_EX" market mid "$SYM" 2>/dev/null | jq -r '.data.mid // "0"')
42
+
43
+ if [[ "$LONG_PRICE" == "0" || "$SHORT_PRICE" == "0" ]]; then
44
+ add_result "price" "false" "Cannot fetch price: long=$LONG_PRICE short=$SHORT_PRICE"
45
+ else
46
+ # Check deviation
47
+ DEVIATION=$(echo "$LONG_PRICE $SHORT_PRICE" | awk '{d=($1-$2)/$2*100; print (d<0?-d:d)}')
48
+ if (( $(echo "$DEVIATION > 5" | bc -l) )); then
49
+ add_result "price" "false" "Price deviation ${DEVIATION}% > 5% — possible wrong token"
50
+ else
51
+ add_result "price" "true" "long=$LONG_PRICE short=$SHORT_PRICE dev=${DEVIATION}%"
52
+ fi
53
+ fi
54
+
55
+ # 2. Balance check on both exchanges
56
+ LONG_BAL=$($PERP --json -e "$LONG_EX" account info 2>/dev/null | jq -r '.data.available // .data.equity // "0"')
57
+ SHORT_BAL=$($PERP --json -e "$SHORT_EX" account info 2>/dev/null | jq -r '.data.available // .data.equity // "0"')
58
+
59
+ NEEDED=$(echo "$SIZE" | awk '{print $1}')
60
+ if (( $(echo "$LONG_BAL < $NEEDED" | bc -l 2>/dev/null || echo 1) )); then
61
+ add_result "balance_long" "false" "$LONG_EX balance $LONG_BAL < needed $NEEDED"
62
+ else
63
+ add_result "balance_long" "true" "$LONG_EX balance=$LONG_BAL"
64
+ fi
65
+ if (( $(echo "$SHORT_BAL < $NEEDED" | bc -l 2>/dev/null || echo 1) )); then
66
+ add_result "balance_short" "false" "$SHORT_EX balance $SHORT_BAL < needed $NEEDED"
67
+ else
68
+ add_result "balance_short" "true" "$SHORT_EX balance=$SHORT_BAL"
69
+ fi
70
+
71
+ # 3. Market info (symbol availability)
72
+ LONG_INFO=$($PERP --json -e "$LONG_EX" market info "$SYM" 2>/dev/null || echo '{"ok":false}')
73
+ SHORT_INFO=$($PERP --json -e "$SHORT_EX" market info "$SYM" 2>/dev/null || echo '{"ok":false}')
74
+
75
+ if echo "$LONG_INFO" | grep -q '"ok":true' && echo "$SHORT_INFO" | grep -q '"ok":true'; then
76
+ add_result "market_info" "true" "Both exchanges support $SYM"
77
+ else
78
+ add_result "market_info" "false" "Symbol $SYM not available on one or both exchanges"
79
+ fi
80
+
81
+ # 4. Risk pre-check
82
+ LEV_FLAG=""
83
+ [[ -n "$LEVERAGE" ]] && LEV_FLAG="--leverage $LEVERAGE"
84
+ RISK_CHECK=$($PERP --json risk check --notional "$SIZE" $LEV_FLAG 2>/dev/null || echo '{"ok":false}')
85
+ if echo "$RISK_CHECK" | grep -q '"ok":true'; then
86
+ add_result "risk" "true" "Within risk limits"
87
+ else
88
+ add_result "risk" "false" "Risk check failed — review risk limits"
89
+ fi
90
+
91
+ # 5. Dry-run
92
+ DRY_RUN=$($PERP --json --dry-run arb exec "$SYM" "$LONG_EX" "$SHORT_EX" "$SIZE" $LEV_FLAG 2>/dev/null || echo '{"ok":false}')
93
+ if echo "$DRY_RUN" | grep -q '"ok":true'; then
94
+ add_result "dry_run" "true" "Dry-run succeeded"
95
+ else
96
+ DRY_ERR=$(echo "$DRY_RUN" | jq -r '.error.message // .error // "unknown"' 2>/dev/null)
97
+ add_result "dry_run" "false" "Dry-run failed: $DRY_ERR"
98
+ fi
99
+
100
+ # Output
101
+ CHECKS_JSON=$(IFS=,; echo "${checks[*]}")
102
+ cat <<EOF
103
+ {
104
+ "ok": true,
105
+ "symbol": "$SYM",
106
+ "longExchange": "$LONG_EX",
107
+ "shortExchange": "$SHORT_EX",
108
+ "sizeUsd": $SIZE,
109
+ "allPassed": $pass,
110
+ "checks": [$CHECKS_JSON]
111
+ }
112
+ EOF
@@ -1,15 +0,0 @@
1
- #!/bin/bash
2
- # Scan funding rate arbitrage opportunities
3
- # Usage: ./arb-scan.sh [min-spread-bps]
4
- # Example: ./arb-scan.sh 20
5
-
6
- set -e
7
-
8
- MIN_SPREAD="${1:-10}"
9
-
10
- echo "=== Funding Rate Arbitrage Scanner ==="
11
- echo "Minimum spread: ${MIN_SPREAD} bps"
12
- echo ""
13
-
14
- echo "1. Opportunities (>= ${MIN_SPREAD} bps):"
15
- perp --json arb scan --min "$MIN_SPREAD"
@@ -1,38 +0,0 @@
1
- #!/bin/bash
2
- # Open a perp position with pre-flight checks
3
- # Usage: ./open-position.sh <exchange> <symbol> <side> <size>
4
- # Example: ./open-position.sh hl BTC buy 0.01
5
-
6
- set -e
7
-
8
- EX="${1:?Usage: open-position.sh <exchange> <symbol> <side> <size>}"
9
- SYM="${2:?Usage: open-position.sh <exchange> <symbol> <side> <size>}"
10
- SIDE="${3:?Usage: open-position.sh <exchange> <symbol> <side> <size>}"
11
- SIZE="${4:?Usage: open-position.sh <exchange> <symbol> <side> <size>}"
12
-
13
- echo "=== Pre-flight checks ==="
14
- echo "1. Account info:"
15
- perp --json -e "$EX" account info
16
-
17
- echo "2. Current price:"
18
- perp --json -e "$EX" market mid "$SYM"
19
-
20
- echo "3. Trade validation:"
21
- perp --json -e "$EX" trade check "$SYM" "$SIDE" "$SIZE"
22
-
23
- echo ""
24
- echo "=== Ready to execute ==="
25
- echo " Exchange: $EX"
26
- echo " Symbol: $SYM"
27
- echo " Side: $SIDE"
28
- echo " Size: $SIZE"
29
- echo ""
30
- read -p "Confirm? (y/N): " CONFIRM
31
-
32
- if [ "$CONFIRM" = "y" ] || [ "$CONFIRM" = "Y" ]; then
33
- perp --json -e "$EX" trade market "$SYM" "$SIDE" "$SIZE"
34
- echo "=== Position verification ==="
35
- perp --json -e "$EX" account positions
36
- else
37
- echo "Cancelled."
38
- fi
@@ -1,17 +0,0 @@
1
- #!/bin/bash
2
- # Wallet setup for perp-cli
3
- # Usage: ./wallet-setup.sh <exchange> <private-key>
4
- # Exchanges: hl (Hyperliquid), pac (Pacifica), lt (Lighter)
5
-
6
- set -e
7
-
8
- EXCHANGE="${1:?Usage: wallet-setup.sh <exchange> <private-key>}"
9
- KEY="${2:?Usage: wallet-setup.sh <exchange> <private-key>}"
10
-
11
- echo "Setting up wallet for $EXCHANGE..."
12
- perp --json wallet set "$EXCHANGE" "$KEY"
13
-
14
- echo "Verifying..."
15
- perp --json wallet show
16
-
17
- echo "Done. Wallet configured for $EXCHANGE."