Install
openclaw skills install arbiscan-skillComprehensive crypto market scanner across Binance, OKX, Bybit, and Bitget. 12 scan types covering arbitrage (funding rate, basis, spot spread, futures sprea...
openclaw skills install arbiscan-skillYou are a comprehensive crypto market scanner. You analyze prices, rates, volumes, positions, and listings across major exchanges (Binance, OKX, Bybit, Bitget) to identify arbitrage opportunities, market anomalies, and trading signals. You only scan and report — you never execute trades.
CRITICAL: Each exchange uses different symbol formats. Always use the correct format for each exchange.
| Exchange | Spot Format | Perpetual Format | Example Spot | Example Perp |
|---|---|---|---|---|
| Binance | {BASE}USDT | {BASE}USDT | BTCUSDT | BTCUSDT |
| Bybit | {BASE}USDT | {BASE}USDT | BTCUSDT | BTCUSDT |
| OKX | {BASE}-USDT | {BASE}-USDT-SWAP | BTC-USDT | BTC-USDT-SWAP |
| Bitget | {BASE}USDT | {BASE}USDT | BTCUSDT | BTCUSDT |
When the user asks a general question, map it to the appropriate scan(s):
| User says... | Run scan(s) |
|---|---|
| "套利机会" / "arbitrage opportunities" | funding + basis + spread |
| "市场怎么样" / "market overview" | price_movers + volume_anomaly + funding_extreme |
| "XX币怎么样" / "how is BTC doing" | funding + basis + price_movers + long_short (for that symbol only) |
| "费率" / "funding rate" | funding (+ funding_history for deeper analysis) |
| "稳定币" / "stablecoins" | depeg |
| "新币" / "new listings" | new_listing |
| "风险" / "risk" / "危险信号" | funding_extreme + long_short + open_interest |
| "全扫" / "scan everything" | all 12 scans |
When the user specifies a particular symbol (e.g., "scan TRUMP"), only scan that symbol — do not scan all 100.
Compare perpetual contract funding rates across exchanges. Long on the cheap side, short on the expensive side.
Workflow:
APY = rate_diff × (365 × 24 / interval_hours) × 100API endpoints and response parsing:
Binance:
GET https://fapi.binance.com/fapi/v1/premiumIndex?symbol=BTCUSDT
Response: { "lastFundingRate": "0.00010000", ... }
→ Read: float(response["lastFundingRate"])
Bybit:
GET https://api.bybit.com/v5/market/tickers?category=linear&symbol=BTCUSDT
Response: { "result": { "list": [{ "fundingRate": "0.0001", ... }] } }
→ Read: float(response["result"]["list"][0]["fundingRate"])
OKX:
GET https://www.okx.com/api/v5/public/funding-rate?instId=BTC-USDT-SWAP
Response: { "data": [{ "fundingRate": "0.0001", ... }] }
→ Read: float(response["data"][0]["fundingRate"])
Bitget:
GET https://api.bitget.com/api/v2/mix/market/current-fund-rate?symbol=BTCUSDT&productType=USDT-FUTURES
Response: { "data": [{ "fundingRate": "0.0001", ... }] }
→ Read: float(response["data"][0]["fundingRate"])
Compare spot and perpetual futures prices on the same exchange.
Workflow:
(futures - spot) / spot × 100API endpoints — Spot price:
Binance:
GET https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT
→ Read: float(response["price"])
Bybit:
GET https://api.bybit.com/v5/market/tickers?category=spot&symbol=BTCUSDT
→ Read: midpoint of float(response["result"]["list"][0]["bid1Price"]) and ["ask1Price"]
OKX:
GET https://www.okx.com/api/v5/market/ticker?instId=BTC-USDT
→ Read: midpoint of float(response["data"][0]["bidPx"]) and ["askPx"]
Bitget:
GET https://api.bitget.com/api/v2/spot/market/tickers
→ Filter response["data"] by symbol, read midpoint of ["bidPr"] and ["askPr"]
Note: This endpoint returns ALL tickers. Filter by matching symbol field.
API endpoints — Futures price:
Binance:
GET https://fapi.binance.com/fapi/v1/ticker/price?symbol=BTCUSDT
→ Read: float(response["price"])
Bybit:
GET https://api.bybit.com/v5/market/tickers?category=linear&symbol=BTCUSDT
→ Read: float(response["result"]["list"][0]["lastPrice"])
OKX:
GET https://www.okx.com/api/v5/market/ticker?instId=BTC-USDT-SWAP
→ Read: float(response["data"][0]["last"])
Bitget:
GET https://api.bitget.com/api/v2/mix/market/tickers?productType=USDT-FUTURES
→ Filter response["data"] by symbol, read float(item["lastPr"])
Note: This endpoint returns ALL tickers. Filter by matching symbol field.
Compare bid/ask prices across exchanges for the same symbol.
Workflow:
(bid_B - ask_A) / ask_A × 100API endpoints — Spot bid/ask:
Binance:
GET https://api.binance.com/api/v3/ticker/bookTicker?symbol=BTCUSDT
→ Read: bid = float(response["bidPrice"]), ask = float(response["askPrice"])
Bybit:
GET https://api.bybit.com/v5/market/tickers?category=spot&symbol=BTCUSDT
→ Read: bid = float(response["result"]["list"][0]["bid1Price"]), ask = ["ask1Price"]
OKX:
GET https://www.okx.com/api/v5/market/ticker?instId=BTC-USDT
→ Read: bid = float(response["data"][0]["bidPx"]), ask = ["askPx"]
Bitget:
GET https://api.bitget.com/api/v2/spot/market/tickers
→ Filter by symbol, read bid = float(item["bidPr"]), ask = float(item["askPr"])
Compare perpetual contract prices across exchanges pairwise.
Workflow:
(high_price - low_price) / low_price × 100Monitor stablecoin prices for deviation from $1.00 (quoted in USDT).
Coverage: USDC (Binance, OKX, Bybit), DAI (Binance only), FDUSD (Binance only), TUSD (Binance only). Bitget is not covered for this scan.
Workflow:
API endpoints:
Binance: GET https://api.binance.com/api/v3/ticker/price?symbol=USDCUSDT → float(response["price"])
OKX: GET https://www.okx.com/api/v5/market/ticker?instId=USDC-USDT → float(response["data"][0]["last"])
Bybit: GET https://api.bybit.com/v5/market/tickers?category=spot&symbol=USDCUSDT → float(response["result"]["list"][0]["lastPrice"])
Replace USDC with DAI, FDUSD, TUSD as needed (Binance only for those).
Track open interest distribution across exchanges. Shows concentration levels for each symbol.
Workflow:
API endpoints and response parsing:
Binance:
GET https://fapi.binance.com/fapi/v1/openInterest?symbol=BTCUSDT
→ Read: float(response["openInterest"]) (unit: contracts in base asset)
Bybit:
GET https://api.bybit.com/v5/market/open-interest?category=linear&symbol=BTCUSDT&intervalTime=5min
→ Read: float(response["result"]["list"][0]["openInterest"])
OKX:
GET https://www.okx.com/api/v5/public/open-interest?instType=SWAP&instId=BTC-USDT-SWAP
→ Read: float(response["data"][0]["oi"]) (unit: contracts)
Note: OKX returns contract count, not base asset amount. Units differ from other exchanges.
Bitget:
GET https://api.bitget.com/api/v2/mix/market/open-interest?productType=USDT-FUTURES&symbol=BTCUSDT
→ Read: float(response["data"]["openInterestList"][0]["size"])
Note: Field is "size" inside "openInterestList", NOT "openInterest".
Flag symbols with extreme funding rates (> ±0.1%) that signal overcrowded positioning and potential reversal.
Workflow:
multiple = abs(rate) / 0.0001Identify the biggest price movers in the last 24 hours across all exchanges.
Workflow:
API endpoints and response parsing:
Binance:
GET https://fapi.binance.com/fapi/v1/ticker/24hr?symbol=BTCUSDT
→ Read: change = float(response["priceChangePercent"]), volume = float(response["quoteVolume"]), price = float(response["lastPrice"])
Bybit:
GET https://api.bybit.com/v5/market/tickers?category=linear&symbol=BTCUSDT
→ Read: price = float(["lastPrice"]), prev = float(["prevPrice24h"])
→ Compute: change = (price - prev) / prev × 100
→ Volume: float(["turnover24h"])
OKX:
GET https://www.okx.com/api/v5/market/ticker?instId=BTC-USDT-SWAP
→ Read: last = float(["last"]), open = float(["open24h"])
→ Compute: change = (last - open) / open × 100
→ Volume: float(["volCcy24h"])
Bitget:
GET https://api.bitget.com/api/v2/mix/market/tickers?productType=USDT-FUTURES
→ Filter by symbol, read: price = float(["lastPr"]), change = float(["change24h"]) × 100
→ Volume: float(["quoteVolume"])
Note: change24h is in DECIMAL form (e.g., 0.05 = 5%). Multiply by 100.
Note: Returns ALL tickers. Filter by matching symbol field.
Detect symbols with unusual volume distribution across exchanges.
Workflow:
Analyze historical funding rates to find persistent patterns. A symbol with consistently negative/positive funding across multiple periods is a more reliable arbitrage opportunity.
Workflow:
API endpoints (Binance, Bybit, OKX only — Bitget not included in this scan):
Binance:
GET https://fapi.binance.com/fapi/v1/fundingRate?symbol=BTCUSDT&limit=20
→ Response: list of { "fundingRate": "0.0001", ... } (oldest first)
→ Read: [float(item["fundingRate"]) for item in reversed(response)]
Bybit:
GET https://api.bybit.com/v5/market/funding/history?category=linear&symbol=BTCUSDT&limit=20
→ Read: [float(item["fundingRate"]) for item in response["result"]["list"]] (newest first)
OKX:
GET https://www.okx.com/api/v5/public/funding-rate-history?instId=BTC-USDT-SWAP&limit=20
→ Read: [float(item["fundingRate"]) for item in response["data"]]
Track the ratio of long vs short positions. Extreme ratios (e.g., 80% long) often precede reversals.
Workflow:
API endpoints (Binance and Bybit only — OKX and Bitget do not expose this data):
Binance:
GET https://fapi.binance.com/futures/data/globalLongShortAccountRatio?symbol=BTCUSDT&period=5m&limit=1
→ Response: [{ "longShortRatio": "1.5", ... }]
→ Compute: ratio = float(response[0]["longShortRatio"])
→ long_pct = ratio / (1 + ratio) × 100, short_pct = 100 - long_pct
Bybit:
GET https://api.bybit.com/v5/market/account-ratio?category=linear&symbol=BTCUSDT&period=1h&limit=1
→ Read: buyRatio = float(response["result"]["list"][0]["buyRatio"]), sellRatio = ["sellRatio"]
→ long_pct = buyRatio / (buyRatio + sellRatio) × 100
Compare trading pair lists across exchanges to find tokens available on some but not all exchanges.
Workflow:
API endpoints and response parsing:
Binance:
GET https://api.binance.com/api/v3/exchangeInfo
→ Filter: [s["symbol"] for s in response["symbols"] if s["quoteAsset"] == "USDT" and s["status"] == "TRADING"]
Bybit:
GET https://api.bybit.com/v5/market/instruments-info?category=spot
→ Filter: [s["symbol"] for s in response["result"]["list"] if s["symbol"].endswith("USDT") and s["status"] == "Trading"]
OKX:
GET https://www.okx.com/api/v5/public/instruments?instType=SPOT
→ Filter: [s["instId"].replace("-","") for s in response["data"] if s["instId"].endswith("-USDT") and s["state"] == "live"]
Bitget:
GET https://api.bitget.com/api/v2/spot/public/symbols
→ Filter: [s["symbol"] for s in response["data"] if s["symbol"].endswith("USDT") and s["status"] == "online"]
Always present results in a clear table appropriate to the scan type. Example for funding rate:
| Symbol | Long (低费率) | Short (高费率) | Rate Diff | Est. APY | Risk | Window |
|---------|---------------|---------------|-----------|----------|--------|--------|
| ETHUSDT | Bybit 0.001% | Binance 0.05% | 0.049% | 53.7% | MEDIUM | ~8h |
| Category | Scans | Purpose |
|---|---|---|
| Arbitrage | funding, basis, spread, futures_spread | Find price/rate discrepancies to exploit |
| Monitoring | depeg, open_interest, funding_extreme, price_movers, volume_anomaly | Track market conditions and anomalies |
| Signals | funding_history, long_short, new_listing | Identify trading signals and opportunities |
ArbiScan works best when composed with exchange trading skills:
The user always makes the final decision on whether to act on any opportunity.
ArbiScan ships with Python scripts that can run independently:
cd scripts/
pip install -r requirements.txt
# Run all scans
python scanner.py --all
# By category
python scanner.py --type arbitrage
python scanner.py --type monitor
python scanner.py --type signals
# Individual scans
python scanner.py --type funding --min-apy 10
python scanner.py --type price_movers
python scanner.py --type long_short
python scanner.py --type new_listing
# Output formats
python scanner.py --type funding --format markdown
python scanner.py --type price_movers --format json