probable-trader 1.0.0

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.
package/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # Probable Markets Trading Skill
2
+
3
+ An OpenClaw Skill that wraps the [Probable Markets](https://probable.markets) prediction market on BNB Chain (BSC). Enables agents to onboard wallets, discover markets, view orderbooks, place/cancel orders, track positions, and generate audit reports.
4
+
5
+ Built on top of `opinion_clob_sdk` — the official Probable Markets / Opinion Labs Python SDK.
6
+
7
+ ## Features
8
+
9
+ - **One-command onboarding** — auto-generates API key via L1 EIP-712 auth
10
+ - **Full trading lifecycle** — place/cancel limit & market orders, split/merge/redeem
11
+ - **Safety by default** — dry-run mode, `--confirm` required for all transactions, secret masking
12
+ - **Audit logging** — every action logged to local SQLite
13
+ - **Real-time streaming** — WebSocket orderbook & execution report subscriptions
14
+ - **Agent-native** — all output as structured JSON (ActionResult envelope)
15
+
16
+ ## Quick Start
17
+
18
+ ```bash
19
+ # 1. Install dependencies
20
+ pip install opinion_clob_sdk websockets httpx
21
+
22
+ # 2. Set your private key
23
+ export PROB_PRIVATE_KEY="0xYOUR_PRIVATE_KEY"
24
+ export PROB_RPC_URL="https://bsc-dataseed.binance.org"
25
+
26
+ # 3. Register on probable.markets (connect wallet), then set proxy wallet
27
+ export PROB_MULTI_SIG_ADDR="0xYOUR_PROXY_WALLET"
28
+
29
+ # 4. Auto-generate API key
30
+ python3 scripts/prob.py onboard --confirm --json
31
+
32
+ # 5. Enable trading approvals (on-chain)
33
+ python3 scripts/prob.py setup --confirm --json
34
+
35
+ # 6. Start trading
36
+ python3 scripts/prob.py market list --status activated --json
37
+ python3 scripts/prob.py book <token_id> --json
38
+ python3 scripts/prob.py order place --market-id <M> --token-id <T> --side BUY --price 0.55 --amount 100 --confirm --json
39
+ ```
40
+
41
+ ## CLI Commands
42
+
43
+ ```
44
+ prob.py config {show,init} # Configuration management
45
+ prob.py doctor # Health check
46
+ prob.py onboard [--confirm] # Generate API key (L1 auth)
47
+ prob.py setup [--confirm] # Enable trading (on-chain approvals)
48
+
49
+ prob.py market {list,get,search} # Market discovery
50
+ prob.py book <token_id> # Orderbook snapshot
51
+ prob.py price <token_id> # Latest price
52
+ prob.py history <token_id> # Price history
53
+ prob.py fee-rates <token_id> # Fee rates
54
+
55
+ prob.py order {place,get,list,cancel,cancel-all} # Order management
56
+ prob.py positions [--market-id M] # My positions
57
+ prob.py trades [--market-id M] # My trades
58
+ prob.py balance # My balances
59
+
60
+ prob.py split --market-id M --amount A [--confirm] # Split collateral
61
+ prob.py merge --market-id M --amount A [--confirm] # Merge tokens
62
+ prob.py redeem --market-id M [--confirm] # Redeem resolved
63
+
64
+ prob.py ws book <token_id> [--duration N] # Stream orderbook
65
+ prob.py ws user [--duration N] # Stream execution reports
66
+ prob.py report daily [--format json|markdown|both] # Trading report
67
+ ```
68
+
69
+ Global flags: `--json` (JSON output), `--confirm` (execute), `--dry-run` (preview)
70
+
71
+ ## Project Structure
72
+
73
+ ```
74
+ marketskill/
75
+ ├── SKILL.md # OpenClaw skill definition
76
+ ├── scripts/
77
+ │ ├── prob.py # CLI entry point
78
+ │ └── lib/
79
+ │ ├── config.py # Env var + config file loading
80
+ │ ├── client_wrapper.py # Wraps opinion_clob_sdk.Client
81
+ │ ├── onboard.py # L1 auth + API key generation
82
+ │ ├── safety.py # Dry-run, confirmation, secret masking
83
+ │ ├── db.py # SQLite audit log + cache
84
+ │ ├── ws_client.py # WebSocket client
85
+ │ └── report.py # Daily report generator
86
+ ├── schemas/ # JSON schemas (config, order intent, output)
87
+ ├── references/ # API, WebSocket, and onboarding docs
88
+ └── examples/ # Example interactions
89
+ ```
90
+
91
+ ## Safety Model
92
+
93
+ | Feature | Behavior |
94
+ |---------|----------|
95
+ | Default mode | Dry-run — shows what would happen without executing |
96
+ | Transactions | Require `--confirm` flag (orders, cancel, split, merge, redeem, setup) |
97
+ | Secrets | Private keys and API secrets masked in all output |
98
+ | Audit | Every action logged to `.probable/probable.db` (SQLite) |
99
+ | Output | Standardized JSON envelope with `success`, `error`, `request_id`, `timestamp` |
100
+
101
+ ## Key Contracts (BSC Mainnet)
102
+
103
+ | Contract | Address |
104
+ |----------|---------|
105
+ | ConditionalTokens | `0xAD1a38cEc043e70E83a3eC30443dB285ED10D774` |
106
+ | MultiSend | `0x998739BFdAAdde7C933B942a68053933098f9EDa` |
107
+ | FeeManager | `0xC9063Dc52dEEfb518E5b6634A6b8D624bc5d7c36` |
108
+
109
+ ## Requirements
110
+
111
+ - Python 3.10+
112
+ - `opinion_clob_sdk` (v0.4.3+)
113
+ - `websockets`, `httpx`
114
+ - BNB Chain wallet with BNB (gas) and USDT (trading)
115
+
116
+ ## License
117
+
118
+ MIT
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const { spawn } = require("child_process");
5
+ const path = require("path");
6
+ const { ensureEnvironment, checkPython, installDeps } = require("../lib/setup");
7
+
8
+ const PROB_PY = path.resolve(__dirname, "..", "scripts", "prob.py");
9
+
10
+ // Handle "setup-python" — force (re)install deps
11
+ if (process.argv[2] === "setup-python") {
12
+ try {
13
+ const pythonBin = checkPython();
14
+ console.log("Python found: " + pythonBin);
15
+ // Remove marker to force reinstall
16
+ const fs = require("fs");
17
+ const marker = path.resolve(__dirname, "..", ".probable", ".deps-installed");
18
+ if (fs.existsSync(marker)) {
19
+ fs.unlinkSync(marker);
20
+ }
21
+ installDeps(pythonBin);
22
+ console.log("Setup complete.");
23
+ } catch (err) {
24
+ console.error("Error:", err.message);
25
+ process.exit(1);
26
+ }
27
+ process.exit(0);
28
+ }
29
+
30
+ // For --help / -h / no args, only need python check (skip pip install)
31
+ const userArgs = process.argv.slice(2);
32
+ const helpOnly =
33
+ userArgs.length === 0 ||
34
+ userArgs.includes("--help") ||
35
+ userArgs.includes("-h");
36
+
37
+ let pythonBin;
38
+ try {
39
+ if (helpOnly) {
40
+ pythonBin = checkPython();
41
+ } else {
42
+ pythonBin = ensureEnvironment();
43
+ }
44
+ } catch (err) {
45
+ console.error("Error:", err.message);
46
+ process.exit(1);
47
+ }
48
+
49
+ // Forward all args after "probable-trader" to prob.py
50
+ const args = [PROB_PY, ...process.argv.slice(2)];
51
+
52
+ const child = spawn(pythonBin, args, {
53
+ stdio: "inherit",
54
+ cwd: path.resolve(__dirname, ".."),
55
+ });
56
+
57
+ child.on("error", (err) => {
58
+ console.error("Failed to start Python:", err.message);
59
+ process.exit(1);
60
+ });
61
+
62
+ child.on("close", (code) => {
63
+ process.exit(code ?? 1);
64
+ });
package/lib/setup.js ADDED
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+
3
+ const { execFileSync } = require("child_process");
4
+ const fs = require("fs");
5
+ const path = require("path");
6
+
7
+ const PKG_ROOT = path.resolve(__dirname, "..");
8
+ const MARKER_DIR = path.join(PKG_ROOT, ".probable");
9
+ const MARKER_FILE = path.join(MARKER_DIR, ".deps-installed");
10
+
11
+ /**
12
+ * Find a working python3 binary and verify version >= 3.10.
13
+ * Returns the binary name (e.g. "python3") or throws.
14
+ */
15
+ function checkPython() {
16
+ const candidates = ["python3", "python"];
17
+ for (const bin of candidates) {
18
+ try {
19
+ const raw = execFileSync(bin, ["--version"], {
20
+ encoding: "utf-8",
21
+ stdio: ["pipe", "pipe", "pipe"],
22
+ }).trim();
23
+ const match = raw.match(/Python\s+(\d+)\.(\d+)/);
24
+ if (match) {
25
+ const major = parseInt(match[1], 10);
26
+ const minor = parseInt(match[2], 10);
27
+ if (major === 3 && minor >= 10) {
28
+ return bin;
29
+ }
30
+ }
31
+ } catch {
32
+ // binary not found, try next
33
+ }
34
+ }
35
+ throw new Error(
36
+ "Python 3.10+ is required but not found.\n" +
37
+ "Install it from https://www.python.org/downloads/ and ensure it is on your PATH."
38
+ );
39
+ }
40
+
41
+ /**
42
+ * Try to run a pip install command. Returns true on success.
43
+ */
44
+ function tryPipInstall(args) {
45
+ try {
46
+ execFileSync(args[0], args.slice(1), {
47
+ stdio: "inherit",
48
+ });
49
+ return true;
50
+ } catch {
51
+ return false;
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Check if `uv` is available.
57
+ */
58
+ function hasUv() {
59
+ try {
60
+ execFileSync("uv", ["--version"], { stdio: ["pipe", "pipe", "pipe"] });
61
+ return true;
62
+ } catch {
63
+ return false;
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Install Python dependencies from requirements.txt (only once).
69
+ * Tries multiple strategies: uv pip, pip, pip --user, pip --break-system-packages.
70
+ */
71
+ function installDeps(pythonBin) {
72
+ if (fs.existsSync(MARKER_FILE)) {
73
+ return;
74
+ }
75
+
76
+ const reqFile = path.join(PKG_ROOT, "requirements.txt");
77
+ if (!fs.existsSync(reqFile)) {
78
+ throw new Error("requirements.txt not found at " + reqFile);
79
+ }
80
+
81
+ console.error("[probable-trader] Installing Python dependencies (first run)...");
82
+
83
+ const strategies = [
84
+ // 1. uv pip install (fast, respects PEP 668)
85
+ ...(hasUv() ? [["uv", "pip", "install", "-r", reqFile]] : []),
86
+ // 2. Standard pip
87
+ [pythonBin, "-m", "pip", "install", "-r", reqFile],
88
+ // 3. pip --user (avoids system site-packages)
89
+ [pythonBin, "-m", "pip", "install", "--user", "-r", reqFile],
90
+ // 4. pip --break-system-packages (PEP 668 override, last resort)
91
+ [pythonBin, "-m", "pip", "install", "--break-system-packages", "-r", reqFile],
92
+ ];
93
+
94
+ for (const args of strategies) {
95
+ console.error("[probable-trader] Trying: " + args.join(" "));
96
+ if (tryPipInstall(args)) {
97
+ // Write marker
98
+ if (!fs.existsSync(MARKER_DIR)) {
99
+ fs.mkdirSync(MARKER_DIR, { recursive: true });
100
+ }
101
+ fs.writeFileSync(MARKER_FILE, new Date().toISOString() + "\n");
102
+ console.error("[probable-trader] Python dependencies installed successfully.");
103
+ return;
104
+ }
105
+ }
106
+
107
+ throw new Error(
108
+ "Failed to install Python dependencies.\n" +
109
+ "Try running manually:\n" +
110
+ " " + pythonBin + " -m pip install -r " + reqFile + "\n" +
111
+ "Or use a virtual environment:\n" +
112
+ " " + pythonBin + " -m venv .venv && source .venv/bin/activate && pip install -r " + reqFile
113
+ );
114
+ }
115
+
116
+ /**
117
+ * Ensure Python environment is ready. Returns the python binary name.
118
+ */
119
+ function ensureEnvironment() {
120
+ const pythonBin = checkPython();
121
+ installDeps(pythonBin);
122
+ return pythonBin;
123
+ }
124
+
125
+ module.exports = { checkPython, installDeps, ensureEnvironment };
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "probable-trader",
3
+ "version": "1.0.0",
4
+ "description": "CLI for trading prediction markets on Probable Markets (BSC)",
5
+ "bin": {
6
+ "probable-trader": "bin/probable-trader.js"
7
+ },
8
+ "files": [
9
+ "bin/",
10
+ "lib/",
11
+ "scripts/**/*.py",
12
+ "schemas/",
13
+ "requirements.txt"
14
+ ],
15
+ "keywords": [
16
+ "prediction-market",
17
+ "bsc",
18
+ "trading",
19
+ "cli",
20
+ "probable-markets"
21
+ ],
22
+ "license": "MIT",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/duolaAmengweb3/probable-trader-skill"
26
+ },
27
+ "engines": {
28
+ "node": ">=16"
29
+ }
30
+ }
@@ -0,0 +1,6 @@
1
+ opinion_clob_sdk>=0.4.3
2
+ py_clob_client>=0.1.0
3
+ websockets>=12.0
4
+ httpx>=0.27
5
+ eth_account>=0.11
6
+ hexbytes>=0.3
@@ -0,0 +1,50 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "Action Output",
4
+ "description": "Standardized output envelope for all Probable Markets CLI actions",
5
+ "type": "object",
6
+ "properties": {
7
+ "success": {
8
+ "type": "boolean",
9
+ "description": "Whether the action completed successfully"
10
+ },
11
+ "action": {
12
+ "type": "string",
13
+ "description": "Action name (e.g. 'place_order', 'get_markets', 'doctor')"
14
+ },
15
+ "data": {
16
+ "description": "Action-specific response data (null on error)"
17
+ },
18
+ "error": {
19
+ "type": ["string", "null"],
20
+ "description": "Error message if success=false"
21
+ },
22
+ "dry_run": {
23
+ "type": "boolean",
24
+ "description": "True if action was simulated (not executed)",
25
+ "default": false
26
+ },
27
+ "request_id": {
28
+ "type": "string",
29
+ "description": "Unique request ID for audit correlation",
30
+ "pattern": "^[0-9a-f]{12}$"
31
+ },
32
+ "timestamp": {
33
+ "type": "string",
34
+ "format": "date-time",
35
+ "description": "UTC ISO-8601 timestamp"
36
+ }
37
+ },
38
+ "required": ["success", "action", "request_id", "timestamp"],
39
+ "examples": [
40
+ {
41
+ "success": true,
42
+ "action": "get_markets",
43
+ "data": [{"id": 1, "title": "Will BTC hit 100k?"}],
44
+ "error": null,
45
+ "dry_run": false,
46
+ "request_id": "a1b2c3d4e5f6",
47
+ "timestamp": "2026-03-04T12:00:00+00:00"
48
+ }
49
+ ]
50
+ }
@@ -0,0 +1,49 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "Probable Markets Skill Configuration",
4
+ "description": "Configuration schema for the probable-trader skill",
5
+ "type": "object",
6
+ "properties": {
7
+ "host": {
8
+ "type": "string",
9
+ "description": "Probable Markets API host URL",
10
+ "default": "https://api.probable.markets"
11
+ },
12
+ "chain_id": {
13
+ "type": "integer",
14
+ "description": "BSC chain ID",
15
+ "default": 56,
16
+ "enum": [56]
17
+ },
18
+ "rpc_url": {
19
+ "type": "string",
20
+ "description": "BSC RPC endpoint URL (e.g. https://bsc-dataseed.binance.org)"
21
+ },
22
+ "api_key": {
23
+ "type": "string",
24
+ "description": "Probable Markets API key (from onboarding)"
25
+ },
26
+ "private_key": {
27
+ "type": "string",
28
+ "description": "EOA private key for signing (hex, with or without 0x prefix)",
29
+ "pattern": "^(0x)?[0-9a-fA-F]{64}$"
30
+ },
31
+ "multi_sig_addr": {
32
+ "type": "string",
33
+ "description": "Gnosis Safe proxy wallet address",
34
+ "pattern": "^0x[0-9a-fA-F]{40}$"
35
+ }
36
+ },
37
+ "required": [],
38
+ "additionalProperties": false,
39
+ "examples": [
40
+ {
41
+ "host": "https://api.probable.markets",
42
+ "chain_id": 56,
43
+ "rpc_url": "https://bsc-dataseed.binance.org",
44
+ "api_key": "your-api-key",
45
+ "private_key": "0x...",
46
+ "multi_sig_addr": "0x..."
47
+ }
48
+ ]
49
+ }
@@ -0,0 +1,47 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "Order Intent",
4
+ "description": "Input schema for placing an order on Probable Markets",
5
+ "type": "object",
6
+ "properties": {
7
+ "market_id": {
8
+ "type": "integer",
9
+ "description": "Market/Topic ID"
10
+ },
11
+ "token_id": {
12
+ "type": "string",
13
+ "description": "CTF ERC1155 token ID for the outcome to trade"
14
+ },
15
+ "side": {
16
+ "type": "string",
17
+ "enum": ["BUY", "SELL"],
18
+ "description": "Order side"
19
+ },
20
+ "price": {
21
+ "type": "string",
22
+ "description": "Price per token (0.001 to 0.999)",
23
+ "pattern": "^0\\.[0-9]{1,3}$"
24
+ },
25
+ "amount": {
26
+ "type": "string",
27
+ "description": "Amount in quote token (for BUY) or base token (for SELL), in token units"
28
+ },
29
+ "order_type": {
30
+ "type": "string",
31
+ "enum": ["limit", "market"],
32
+ "default": "limit",
33
+ "description": "Order type: limit (GTC) or market (IOC)"
34
+ }
35
+ },
36
+ "required": ["market_id", "token_id", "side", "price", "amount"],
37
+ "examples": [
38
+ {
39
+ "market_id": 42,
40
+ "token_id": "12345678901234567890",
41
+ "side": "BUY",
42
+ "price": "0.55",
43
+ "amount": "100",
44
+ "order_type": "limit"
45
+ }
46
+ ]
47
+ }
@@ -0,0 +1 @@
1
+ # Probable Markets Skill library