Skip to content

Commit 0c77aba

Browse files
authored
Merge pull request #10 from second-state/feat/binance-enhancements
feat: Binance enhancements — configurable URL, quote, transfer, tests
2 parents b043bc2 + 1380f69 commit 0c77aba

36 files changed

Lines changed: 3972 additions & 100 deletions

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ jobs:
4040
./target/release/binance --help
4141
./target/release/coinbase --help
4242
./target/release/polymarket --help
43+
./target/release/okx --help
4344
4445
- name: Smoke test - init
4546
run: |

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ permissions:
99
contents: write
1010

1111
env:
12-
BINARIES: fintool hyperliquid binance coinbase polymarket
12+
BINARIES: fintool hyperliquid binance coinbase polymarket okx
1313

1414
jobs:
1515
build:

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ path = "src/bin/coinbase.rs"
3131
name = "polymarket"
3232
path = "src/bin/polymarket.rs"
3333

34+
[[bin]]
35+
name = "okx"
36+
path = "src/bin/okx.rs"
37+
3438
[dependencies]
3539
clap = { version = "4", features = ["derive"] }
3640
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
@@ -60,3 +64,4 @@ hmac = "0.12"
6064
rmp-serde = "1"
6165
sha2 = "0.10"
6266
uuid = { version = "1", features = ["v4"] }
67+
base64 = "0.22"

README.md

Lines changed: 140 additions & 44 deletions
Large diffs are not rendered by default.

config.toml.default

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,24 @@ testnet = false
3232
# Sign up at https://www.binance.com/
3333
# binance_api_key = "..."
3434
# binance_api_secret = "..."
35+
# Custom base URL (default: https://api.binance.com)
36+
# For Binance US (spot only, no futures/options): https://api.binance.us
37+
# binance_base_url = "https://api.binance.com"
3538

3639
# Coinbase Advanced Trade API credentials — enables spot trading on Coinbase
3740
# Sign up at https://www.coinbase.com/
3841
# coinbase_api_key = "..."
3942
# coinbase_api_secret = "..."
4043

44+
# OKX API credentials — enables spot/perp trading on OKX
45+
# Sign up at https://www.okx.com/
46+
# okx_api_key = "..."
47+
# okx_secret_key = "..."
48+
# okx_passphrase = "..."
49+
# Custom base URL (default: https://www.okx.com)
50+
# For OKX US: https://app.okx.com
51+
# okx_base_url = "https://www.okx.com"
52+
4153
# Polymarket — prediction market trading on Polygon
4254
# Uses the [wallet] private_key for signing. Only signature_type is configurable.
4355
# [polymarket]

skills/SKILL.md

Lines changed: 62 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: fintool
3-
description: "Financial trading CLIs — spot and perp trading on Hyperliquid, Binance, Coinbase. Prediction markets on Polymarket. Deposit and withdraw across chains. LLM-enriched price quotes with trend analysis. News and SEC filings. Use when: user asks about stock/crypto prices, wants to trade, deposit, withdraw, or check portfolio."
3+
description: "Financial trading CLIs — spot and perp trading on Hyperliquid, Binance, Coinbase, OKX. Prediction markets on Polymarket. Deposit and withdraw across chains. LLM-enriched price quotes with trend analysis. News and SEC filings. Use when: user asks about stock/crypto prices, wants to trade, deposit, withdraw, or check portfolio."
44
homepage: https://github.com/second-state/fintool
55
metadata: { "openclaw": { "emoji": "📈", "requires": { "bins": ["curl"] } } }
66
---
@@ -17,6 +17,7 @@ A suite of CLI tools for market intelligence and trading across multiple exchang
1717
| `hyperliquid` | Hyperliquid trading (spot, perp, HIP-3, deposits) | `{baseDir}/scripts/hyperliquid` |
1818
| `binance` | Binance trading (spot, perp, deposits) | `{baseDir}/scripts/binance` |
1919
| `coinbase` | Coinbase trading (spot, deposits) | `{baseDir}/scripts/coinbase` |
20+
| `okx` | OKX trading (spot, perp, deposits, withdrawals) | `{baseDir}/scripts/okx` |
2021
| `polymarket` | Polymarket prediction markets | `{baseDir}/scripts/polymarket` |
2122

2223
- **Config**: `~/.fintool/config.toml`
@@ -46,25 +47,28 @@ cat ~/.fintool/config.toml 2>/dev/null
4647
- **Hyperliquid**: `private_key` or `wallet_json` + `wallet_passcode` in `[wallet]` (spot + perps)
4748
- **Binance**: `binance_api_key` + `binance_api_secret` in `[api_keys]` (spot + perps)
4849
- **Coinbase**: `coinbase_api_key` + `coinbase_api_secret` in `[api_keys]` (spot only)
50+
- **OKX**: `okx_api_key` + `okx_secret_key` + `okx_passphrase` in `[api_keys]` (spot + perps)
4951
- **Polymarket**: Uses `wallet.private_key` (same as Hyperliquid) for prediction market trading
5052
- If none configured: Ask the user which exchange they want to use and request the credentials.
5153

5254
**If the user provides credentials**, edit `~/.fintool/config.toml` directly to add them.
5355

5456
## Exchange Capabilities
5557

56-
| Feature | `hyperliquid` | `binance` | `coinbase` | `polymarket` |
57-
|---------|---------------|-----------|------------|--------------|
58-
| Spot orders | buy, sell | buy, sell | buy, sell ||
59-
| Perp orders | perp buy/sell | perp buy/sell |||
60-
| Prediction markets |||| buy, sell, list, quote |
61-
| Orderbook | spot + perp | spot + perp | spot ||
62-
| Deposit | Unit + Across | API | API | bridge |
63-
| Withdraw | Bridge2 + Unit + Across | API | API | bridge |
64-
| Balance | balance | balance | balance | balance |
65-
| Open orders | orders | orders | orders ||
66-
| Cancel | cancel | cancel | cancel ||
67-
| Positions | positions | positions || positions |
58+
| Feature | `hyperliquid` | `binance` | `coinbase` | `okx` | `polymarket` |
59+
|---------|---------------|-----------|------------|-------|--------------|
60+
| Spot orders | buy, sell | buy, sell | buy, sell | buy, sell ||
61+
| Perp orders | perp buy/sell | perp buy/sell || perp buy/sell ||
62+
| Prediction markets ||||| buy, sell, list, quote |
63+
| Orderbook | spot + perp | spot + perp | spot | spot + perp ||
64+
| Deposit | Unit + Across | API | API | API | bridge |
65+
| Withdraw | Bridge2 + Unit + Across | API | API | API | bridge |
66+
| Transfer | spot ↔ perp ↔ dex | spot ↔ futures || funding ↔ trading ||
67+
| Balance | balance | balance | balance | balance | balance |
68+
| Open orders | orders | orders | orders | orders ||
69+
| Cancel | cancel | cancel | cancel | cancel ||
70+
| Positions | positions | positions || positions | positions |
71+
| Funding rate |||| perp funding_rate ||
6872

6973
## Error Handling
7074

@@ -139,6 +143,38 @@ cat ~/.fintool/config.toml 2>/dev/null
139143
{"command": "withdraw", "asset": "USDC", "amount": 100, "to": "0x...", "network": "ethereum"}
140144
```
141145

146+
### OKX Trading (`okx`)
147+
148+
```json
149+
// okx --json '<JSON>'
150+
{"command": "quote", "symbol": "BTC"}
151+
{"command": "buy", "symbol": "ETH", "amount": 0.01, "price": 2000}
152+
{"command": "sell", "symbol": "ETH", "amount": 0.01, "price": 2100}
153+
{"command": "orderbook", "symbol": "BTC"}
154+
{"command": "perp_orderbook", "symbol": "ETH"}
155+
{"command": "perp_buy", "symbol": "ETH", "amount": 0.1, "price": 2000}
156+
{"command": "perp_sell", "symbol": "ETH", "amount": 0.1, "price": 2100, "close": true}
157+
{"command": "perp_leverage", "symbol": "ETH", "leverage": 5, "cross": true}
158+
{"command": "perp_funding_rate", "symbol": "BTC"}
159+
{"command": "balance"}
160+
{"command": "positions"}
161+
{"command": "orders"}
162+
{"command": "cancel", "inst_id": "BTC-USDT", "order_id": "12345"}
163+
{"command": "deposit", "asset": "USDC", "network": "base"}
164+
{"command": "deposit", "asset": "ETH", "network": "ethereum"}
165+
{"command": "withdraw", "asset": "USDC", "amount": 100, "network": "base"}
166+
{"command": "withdraw", "asset": "USDC", "amount": 100, "to": "0x...", "network": "ethereum"}
167+
{"command": "transfer", "asset": "USDT", "amount": 100, "from": "funding", "to": "trading"}
168+
{"command": "transfer", "asset": "USDT", "amount": 100, "from": "trading", "to": "funding"}
169+
```
170+
171+
**OKX Notes:**
172+
- `quote` and `orderbook` are public endpoints — no API keys needed.
173+
- OKX uses instrument IDs: spot = `BTC-USDT`, perp = `BTC-USDT-SWAP`. The CLI auto-formats from symbol.
174+
- OKX has `funding` (for deposits/withdrawals) and `trading` (unified) accounts. Use `transfer` to move between them.
175+
- Withdrawal fee is auto-fetched if `--fee` is not specified.
176+
- Cancel requires both `inst_id` (e.g. `BTC-USDT`) and `order_id`.
177+
142178
### Coinbase Trading (`coinbase`)
143179

144180
```json
@@ -209,6 +245,9 @@ Returns: bids, asks, spread, spreadPct, midPrice. Use to assess liquidity before
209245

210246
# Or on Coinbase
211247
{baseDir}/scripts/coinbase --json '{"command":"buy","symbol":"BTC","amount":0.01,"price":95000}'
248+
249+
# Or on OKX
250+
{baseDir}/scripts/okx --json '{"command":"buy","symbol":"BTC","amount":0.01,"price":95000}'
212251
```
213252

214253
**Step 4 — Verify:**
@@ -260,7 +299,7 @@ Returns: bids, asks, spread, spreadPct, midPrice. Use to assess liquidity before
260299
```
261300
Use `"close": true` to ensure the order only reduces an existing position.
262301

263-
**Note**: Perps are available on `hyperliquid` and `binance`. Coinbase does not support perps.
302+
**Note**: Perps are available on `hyperliquid`, `binance`, and `okx`. Coinbase does not support perps.
264303

265304
### Workflow 3: Portfolio Overview
266305

@@ -279,6 +318,11 @@ Use `"close": true` to ensure the order only reduces an existing position.
279318
# Coinbase
280319
{baseDir}/scripts/coinbase --json '{"command":"balance"}'
281320

321+
# OKX
322+
{baseDir}/scripts/okx --json '{"command":"balance"}'
323+
{baseDir}/scripts/okx --json '{"command":"positions"}'
324+
{baseDir}/scripts/okx --json '{"command":"orders"}'
325+
282326
# Polymarket
283327
{baseDir}/scripts/polymarket --json '{"command":"balance"}'
284328
{baseDir}/scripts/polymarket --json '{"command":"positions"}'
@@ -311,10 +355,11 @@ Sends ETH from your wallet on Ethereum L1 to a Unit bridge deposit address. Mini
311355
```
312356
BTC and SOL cannot be bridged automatically. The command returns a Unit deposit address for manual transfer.
313357

314-
**Binance / Coinbase — get deposit address:**
358+
**Binance / Coinbase / OKX — get deposit address:**
315359
```bash
316360
{baseDir}/scripts/binance --json '{"command":"deposit","asset":"USDC","from":"ethereum"}'
317361
{baseDir}/scripts/coinbase --json '{"command":"deposit","asset":"ETH"}'
362+
{baseDir}/scripts/okx --json '{"command":"deposit","asset":"USDC","network":"base"}'
318363
```
319364

320365
**Polymarket — deposit USDC:**
@@ -333,10 +378,11 @@ BTC and SOL cannot be bridged automatically. The command returns a Unit deposit
333378
{baseDir}/scripts/hyperliquid --json '{"command":"withdraw","asset":"ETH","amount":0.5}'
334379
```
335380

336-
**Binance / Coinbase:**
381+
**Binance / Coinbase / OKX:**
337382
```bash
338383
{baseDir}/scripts/binance --json '{"command":"withdraw","asset":"USDC","amount":100,"to":"0x...","network":"ethereum"}'
339384
{baseDir}/scripts/coinbase --json '{"command":"withdraw","asset":"USDC","amount":100,"to":"0x..."}'
385+
{baseDir}/scripts/okx --json '{"command":"withdraw","asset":"USDC","amount":100,"network":"base"}'
340386
```
341387

342388
**Polymarket:**

skills/bootstrap.sh

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,25 @@ esac
4242
echo "Downloading ${ARTIFACT}..."
4343
curl -L -o /tmp/fintool.zip "${RELEASE_BASE}/${ARTIFACT}.zip"
4444
unzip -o /tmp/fintool.zip -d /tmp/fintool-extract
45-
cp "/tmp/fintool-extract/${ARTIFACT}/fintool" "$SKILL_DIR/scripts/fintool"
46-
chmod +x "$SKILL_DIR/scripts/fintool"
45+
BINARIES="fintool hyperliquid binance coinbase polymarket okx"
46+
for bin in $BINARIES; do
47+
src="/tmp/fintool-extract/${ARTIFACT}/${bin}"
48+
if [ -f "$src" ]; then
49+
cp "$src" "$SKILL_DIR/scripts/${bin}"
50+
chmod +x "$SKILL_DIR/scripts/${bin}"
51+
elif [ -f "${src}.exe" ]; then
52+
cp "${src}.exe" "$SKILL_DIR/scripts/${bin}.exe"
53+
else
54+
echo "⚠️ Binary not found in release: ${bin}"
55+
fi
56+
done
4757
rm -rf /tmp/fintool.zip /tmp/fintool-extract
4858

4959
# 4. Initialize config (never overwrites existing)
5060
"$SKILL_DIR/scripts/fintool" init
5161

5262
echo ""
53-
echo "✅ fintool installed to $SKILL_DIR/scripts/fintool"
63+
echo "✅ fintool binaries installed to $SKILL_DIR/scripts/"
5464
echo ""
5565

5666
# 5. Check config for required keys
@@ -76,9 +86,13 @@ fi
7686
if grep -q '^coinbase_api_key\s*=' "$CONFIG" 2>/dev/null; then
7787
HAS_COINBASE=true
7888
fi
89+
HAS_OKX=false
90+
if grep -q '^okx_api_key\s*=' "$CONFIG" 2>/dev/null; then
91+
HAS_OKX=true
92+
fi
7993

80-
if [ "$HAS_HL" = false ] && [ "$HAS_BINANCE" = false ] && [ "$HAS_COINBASE" = false ]; then
81-
MISSING+=("At least one exchange (Hyperliquid wallet, Binance API keys, or Coinbase API keys)")
94+
if [ "$HAS_HL" = false ] && [ "$HAS_BINANCE" = false ] && [ "$HAS_COINBASE" = false ] && [ "$HAS_OKX" = false ]; then
95+
MISSING+=("At least one exchange (Hyperliquid wallet, Binance API keys, Coinbase API keys, or OKX API keys)")
8296
fi
8397

8498
if [ ${#MISSING[@]} -gt 0 ]; then
@@ -94,6 +108,7 @@ if [ ${#MISSING[@]} -gt 0 ]; then
94108
echo " • Hyperliquid (wallet): spot + perps"
95109
echo " • Binance (API key): spot + perps + options"
96110
echo " • Coinbase (API key): spot only"
111+
echo " • OKX (API key): spot + perps"
97112
else
98113
echo "✅ Configuration looks good!"
99114
fi

skills/install.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ rm -rf /tmp/fintool-repo
2323
The bootstrap script will:
2424
1. Clone skill files to `~/.openclaw/skills/fintool/`
2525
2. Detect your platform (Linux x86_64/aarch64, macOS Apple Silicon)
26-
3. Download the correct binary from the latest GitHub release
26+
3. Download all binaries (fintool, hyperliquid, binance, coinbase, polymarket, okx) from the latest GitHub release
2727
4. Run `fintool init` to create `~/.fintool/config.toml` (never overwrites existing)
2828
5. Check config for required keys and tell you what's missing
2929

@@ -36,6 +36,7 @@ After installation, edit `~/.fintool/config.toml` to add your credentials:
3636
- **Hyperliquid**`private_key` or `wallet_json` + `wallet_passcode` in `[wallet]` (spot + perps)
3737
- **Binance**`binance_api_key` + `binance_api_secret` in `[api_keys]` (spot + perps + options)
3838
- **Coinbase**`coinbase_api_key` + `coinbase_api_secret` in `[api_keys]` (spot only)
39+
- **OKX**`okx_api_key` + `okx_secret_key` + `okx_passphrase` in `[api_keys]` (spot + perps)
3940

4041
Verify installation:
4142

@@ -57,8 +58,8 @@ If the bootstrap script fails:
5758
```bash
5859
mkdir -p ~/.openclaw/skills/fintool/scripts
5960
unzip fintool-<platform>.zip
60-
cp fintool-<platform>/fintool ~/.openclaw/skills/fintool/scripts/fintool
61-
chmod +x ~/.openclaw/skills/fintool/scripts/fintool
61+
cp fintool-<platform>/{fintool,hyperliquid,binance,coinbase,polymarket,okx} ~/.openclaw/skills/fintool/scripts/
62+
chmod +x ~/.openclaw/skills/fintool/scripts/*
6263
```
6364
4. Copy the skill definition:
6465
```bash

src/bin/binance.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,24 @@ enum Commands {
102102
#[arg(long)]
103103
dry_run: bool,
104104
},
105+
106+
/// Get a price quote for a symbol
107+
Quote { symbol: String },
108+
109+
/// Transfer assets between spot and futures wallets
110+
Transfer {
111+
/// Asset: USDT, USDC, BTC, ETH, etc.
112+
asset: String,
113+
/// Amount to transfer
114+
#[arg(long)]
115+
amount: String,
116+
/// Source wallet: spot or futures
117+
#[arg(long)]
118+
from: String,
119+
/// Destination wallet: spot or futures
120+
#[arg(long)]
121+
to: String,
122+
},
105123
}
106124

107125
#[derive(Subcommand)]
@@ -223,6 +241,15 @@ enum JsonCommand {
223241
#[serde(default)]
224242
dry_run: bool,
225243
},
244+
Quote {
245+
symbol: String,
246+
},
247+
Transfer {
248+
asset: String,
249+
amount: f64,
250+
from: String,
251+
to: String,
252+
},
226253
}
227254

228255
async fn run_json(json_str: &str) -> Result<()> {
@@ -329,6 +356,13 @@ async fn run_json(json_str: &str) -> Result<()> {
329356
)
330357
.await
331358
}
359+
JsonCommand::Quote { symbol } => commands::quote::run_spot(&symbol, true).await,
360+
JsonCommand::Transfer {
361+
asset,
362+
amount,
363+
from,
364+
to,
365+
} => commands::transfer::run(&asset, &fmt_num(amount), &from, &to, EXCHANGE, true).await,
332366
}
333367
}
334368

@@ -439,6 +473,13 @@ async fn main() -> Result<()> {
439473
)
440474
.await
441475
}
476+
Commands::Quote { symbol } => commands::quote::run_spot(&symbol, json_output).await,
477+
Commands::Transfer {
478+
asset,
479+
amount,
480+
from,
481+
to,
482+
} => commands::transfer::run(&asset, &amount, &from, &to, EXCHANGE, json_output).await,
442483
};
443484

444485
if let Err(e) = result {

src/bin/hyperliquid.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ async fn run_json(json_str: &str) -> Result<()> {
465465
amount,
466466
from,
467467
to,
468-
} => commands::transfer::run(&asset, &fmt_num(amount), &from, &to, true).await,
468+
} => commands::transfer::run(&asset, &fmt_num(amount), &from, &to, EXCHANGE, true).await,
469469
JsonCommand::BridgeStatus => commands::bridge_status::run(true).await,
470470
}
471471
}
@@ -628,7 +628,7 @@ async fn main() -> Result<()> {
628628
amount,
629629
from,
630630
to,
631-
} => commands::transfer::run(&asset, &amount, &from, &to, json_output).await,
631+
} => commands::transfer::run(&asset, &amount, &from, &to, EXCHANGE, json_output).await,
632632
Commands::BridgeStatus => commands::bridge_status::run(json_output).await,
633633
};
634634

0 commit comments

Comments
 (0)