Skill: vlprosvirkin/openclaw-skill-publish (version 2.0.4)

--- name: probtrade version: 2.0.4 description: "Polymarket prediction markets: analytics, trading, hot markets, price movements, top traders, and market search. Powered by prob.trade." homepage: https://app.prob.trade user-invocable: true metadata: {"openclaw":{"requires":{"bins":["python3"],"env":["PROBTRADE_API_KEY","PROBTRADE_API_SECRET"],"config":["~/.openclaw/skills/probtrade/config.yaml"]},"emoji":"📊","install":[{"id":"python3","kind":"brew","formula":"python@3","bins":["python3"],"label":"Install Python 3","os":["darwin","linux"]}]}} --- # prob.trade — Polymarket Analytics & Trading Get real-time prediction market intelligence and trade on Polymarket from [prob.trade](https://app.prob.trade). Browse trending markets, discover price movements, see what top traders are doing, and place orders. ## Setup (required for all commands) All commands require a prob.trade API key. Configure it in `~/.openclaw/skills/probtrade/config.yaml`: ```yaml [REDACTED_SECRET]" api_secret: "pts_..." ``` Generate keys at https://app.prob.trade (Settings → API Keys). Free account required. ## Analytics Commands Use the scripts below to query the prob.trade Public API. ### Market Overview Get a quick snapshot of the prediction market landscape: ```bash python3 {baseDir}/scripts/probtrade.py overview ``` Returns: market stats, top 10 hot markets, breaking price movements, and newest markets. ### Hot Markets See the most actively traded markets right now: ```bash python3 {baseDir}/scripts/probtrade.py hot [--limit N] ``` ### Breaking Markets Markets with the biggest price movements in the last 24 hours: ```bash python3 {baseDir}/scripts/probtrade.py breaking [--limit N] ``` ### New Markets Recently created prediction markets: ```bash python3 {baseDir}/scripts/probtrade.py new [--limit N] [--days N] ``` ### Search Markets Find markets about a specific topic: ```bash python3 {baseDir}/scripts/probtrade.py search "Trump" [--limit N] ``` ### Market Details Get detailed information about a specific market by its condition ID: ```bash python3 {baseDir}/scripts/probtrade.py market <condition_id> ``` ### Market Statistics Category breakdown and overall market counts: ```bash python3 {baseDir}/scripts/probtrade.py stats ``` ### Top Traders See the most profitable prediction market traders: ```bash python3 {baseDir}/scripts/probtrade.py traders [--limit N] [--sort pnl|roi|volume|winRate] [--period all|30d|7d|24h] ``` ## Trading Commands Trade on Polymarket using the same API key configured above. ### Place Order ```bash python3 {baseDir}/scripts/probtrade.py order --market <condition_id> --side BUY --outcome Yes --type LIMIT --price 0.55 --amount 10 ``` ### Cancel Order ```bash python3 {baseDir}/scripts/probtrade.py cancel --order-id <orderId> ``` ### View Positions ```bash python3 {baseDir}/scripts/probtrade.py positions ``` ### View Balance ```bash python3 {baseDir}/scripts/probtrade.py balance ``` ### View Open Orders ```bash python3 {baseDir}/scripts/probtrade.py orders ``` Security: API secret never leaves your machine. Only HMAC signatures are sent. No withdraw/transfer endpoints exist. ## Output Format All commands output structured JSON for easy parsing by AI agents. Key fields: - **condition_id**: Unique market identifier (use for trading on Polymarket) - **question**: The prediction market question - **tokens**: Current prices for Yes/No outcomes - **volume_24hr**: Trading volume in last 24 hours - **liquidity**: Available liquidity for trading - **end_date_iso**: When the market resolves ## Links - Dashboard: https://app.prob.trade - Market page: `https://app.prob.trade/markets/{condition_id}` - Trader profile: `https://app.prob.trade/traders/{address}` - Public API: https://api.prob.trade/api/public/overview - Trading API docs: https://prob.trade/docs/public-api - ClawHub: https://clawhub.ai/vlprosvirkin/prob-trade-polymarket-analytics

path: README.md
content: # probtrade — Polymarket Analytics for OpenClaw

Get real-time prediction market analytics from [prob.trade](https://app.prob.trade) directly in your OpenClaw agent.

## What's different from polyclaw?

| Feature | polyclaw | **probtrade** |
|---------|----------|---------------|
| Browse raw markets | Yes | Yes |
| Trading | Yes (needs private key) | **Yes** (via API keys, HMAC-secured) |
| Hot/trending markets | No | **Yes** |
| Breaking price movements | No | **Yes** |
| Top traders leaderboard | No | **Yes** |
| Copy-trading intelligence | No | **Yes** |
| Market search | Basic | **Full-text** |

**probtrade** gives you both analytics and trading — from market intelligence to placing orders, all through your OpenClaw agent.

## Installation

### From ClawHub
```bash
clawhub install probtrade
```

### Manual
```bash
cp -r probtrade/ ~/.openclaw/skills/probtrade/
```

## Usage

Just ask your OpenClaw agent naturally:

- "What prediction markets are trending right now?"
- "Show me markets about Trump"
- "Which markets have the biggest price swings today?"
- "Who are the most profitable Polymarket traders?"
- "Give me an overview of the prediction market landscape"

Or use specific commands:

```
/probtrade overview          — Market snapshot
/probtrade hot               — Trending markets
/probtrade breaking          — Biggest price movements
/probtrade new               — Recently created markets
/probtrade search "Bitcoin"  — Search markets
/probtrade traders           — Top traders leaderboard
/probtrade stats             — Category breakdown
```

## Trading API

Trade on Polymarket directly through your OpenClaw agent using prob.trade API keys.

### Setup

1. Go to [app.prob.trade](https://app.prob.trade) and create an account
2. Navigate to Settings and generate an API key
3. Configure the skill:

```yaml
# ~/.openclaw/skills/probtrade/config.yaml
[REDACTED_SECRET]"
api_secret: "pts_..."
```

### Trading Commands

```
/probtrade buy "Will Trump win?" yes $100          — Market order
/probtrade buy "Will Trump win?" yes $100 @0.55    — Limit order at $0.55
/probtrade sell "Will Trump win?" yes $50           — Sell position
/probtrade cancel <orderId>                         — Cancel order
/probtrade positions                                — Open positions
/probtrade balance                                  — USDC balance
/probtrade orders                                   — Open orders
```

Or use natural language:
- "Buy $100 of Yes on the Trump election market at 55 cents"
- "What are my current positions?"
- "Cancel all my open orders"

### Security

- API secret never leaves your machine — only HMAC signatures are sent
- No withdraw/transfer endpoints — Trading API can only trade and read
- Keys can be revoked instantly from the dashboard

## Requirements

- Python 3 (no additional packages needed — uses only stdlib)
- prob.trade API key required for all commands (free, generated in dashboard)

## API

- **Public Analytics API** (no auth): [api.prob.trade/api/public](https://api.prob.trade/api/public/overview) — markets, stats, traders
- **Trading API** (API key + HMAC): [api.prob.trade/api/trading](https://api.prob.trade/api/trading) — orders, positions, balance

## Links

- [ClawHub](https://clawhub.ai/vlprosvirkin/prob-trade-polymarket-analytics)
- [prob.trade Dashboard](https://app.prob.trade)
- [Public API Reference](https://prob.trade/docs/public-api)
- [Trading API Reference](https://github.com/vlprosvirkin/probtrade-openclaw-skill/blob/main/docs/trading-api-reference.md)


path: lib/api_client.py
content: """
prob.trade API client — Public Analytics + Trading API (HMAC-secured)
"""

import urllib.request
import urllib.parse
import json
import sys
import os
import hmac
import hashlib
import time
from typing import Optional

_HOST = "https://api.prob.trade"
API_BASE = f"{_HOST}/api/public"
TRADING_BASE = f"{_HOST}/api/trading"


def fetch(endpoint: str, params: Optional[dict] = None) -> dict:
    """Make a GET request to the prob.trade Public API (authenticated with PTK key)."""
    url = f"{API_BASE}{endpoint}"
    if params:
        filtered = {k: v for k, v in params.items() if v is not None}
        if filtered:
            url += "?" + urllib.parse.urlencode(filtered)

    req = urllib.request.Request(url)
    req.add_header("User-Agent", "probtrade-openclaw-skill/1.0")

    # Public API requires authentication — sign with PTK key if available
    config = _load_config()
    if config.get("api_key") and config.get("api_secret"):
        path = f"/api/public{endpoint}"
        auth_headers = _sign(config["api_secret"], "GET", path)
        req.add_header("X-PTK-Key", config["api_key"])
        for k, v in auth_headers.items():
            req.add_header(k, v)

    try:
        with urllib.request.urlopen(req, timeout=15) as response:
            data = json.loads(response.read().decode())
            if not data.get("success"):
                print(f"API error: {data.get('error', 'Unknown error')}", file=sys.stderr)
                sys.exit(1)
            return data.get("data", {})
    except urllib.error.HTTPError as e:
        body = e.read().decode() if e.fp else ""
        try:
            err = json.loads(body)
            print(f"API error ({e.code}): {err.get('error', body)}", file=sys.stderr)
        except json.JSONDecodeError:
            print(f"API error ({e.code}): {body}", file=sys.stderr)
        sys.exit(1)
    except urllib.error.URLError as e:
        print(f"Connection error: {e.reason}", file=sys.stderr)
        sys.exit(1)


# ---------------------------------------------------------------------------
# Trading API client (HMAC-SHA256 authenticated)
# ---------------------------------------------------------------------------

def _load_config() -> dict:
    """Load API key config from ~/.openclaw/skills/probtrade/config.yaml or env vars."""
    [REDACTED_SECRET]"PROBTRADE_API_KEY", "")
    api_secret = os.environ.get("PROBTRADE_API_SECRET", "")

    if api_key and api_secret:
        return {"api_key": api_key, "api_secret": api_secret}

    # Try config.yaml (simple key: value parsing, no yaml dependency)
    config_paths = [
        os.path.join(os.path.dirname(__file__), "..", "config.yaml"),
        os.path.expanduser("~/.openclaw/skills/probtrade/config.yaml"),
    ]
    for path in config_paths:
        if os.path.exists(path):
            with open(path, "r") as f:
                for line in f:
                    line = line.strip()
                    if line.startswith("#") or ":" not in line:
                        continue
                    key, _, value = line.partition(":")
                    value = value.strip().strip('"').strip("'")
                    if key.strip() == "api_key":
                        api_key = value
                    elif key.strip() == "api_secret":
                        api_secret = value
            if api_key and api_secret:
                return {"api_key": api_key, "api_secret": api_secret}

    return {}


def _sign(api_secret: str, method: str, path: str, body: str = "") -> dict:
    """Generate HMAC-SHA256 authentication headers."""
    timestamp = str(int(time.time() * 1000))
    message = timestamp + method.upper() + path + body
    signature = hmac.new(
        api_secret.encode(), message.encode(), hashlib.sha256
    ).hexdigest()
    return {
        "X-PTK-Timestamp": timestamp,
        "X-PTK-Signature": signature,
    }


def trading_request(method: str, endpoint: str, body: Optional[dict] = None) -> dict:
    """Make an authenticated request to the prob.trade Trading API."""
    config = _load_config()
    if not config.get("api_key") or not config.get("api_secret"):
        print(
            "Error: Trading API key not configured.\n"
            "Set PROBTRADE_API_KEY and PROBTRADE_API_SECRET env vars,\n"
            "or create config.yaml with api_key and api_secret.",
            file=sys.stderr,
        )
        sys.exit(1)

    path = f"/api/trading{endpoint}"
    url = f"{_HOST}{path}"
    body_str = json.dumps(body) if body and method.upper() not in ("GET", "DELETE") else ""

    headers = _sign(config["api_secret"], method, path, body_str)
    headers["X-PTK-Key"] = config["api_key"]
    headers["Content-Type"] = "application/json"
    headers["User-Agent"] = "probtrade-openclaw-skill/1.0"

    req = urllib.request.Request(url, method=method.upper(), headers=headers)
    if body_str:
        req.data = body_str.encode()

    try:
        with urllib.request.urlopen(req, timeout=30) as response:
            data = json.loads(response.read().decode())
            if not data.get("success"):
                err = data.get("error", {})
                msg = err.get("message", str(err)) if isinstance(err, dict) else str(err)
                print(f"Trading API error: {msg}", file=sys.stderr)
                sys.exit(1)
            return data.get("data", {})
    except urllib.error.HTTPError as e:
        body_resp = e.read().decode() if e.fp else ""
        try:
            err = json.loads(body_resp)
            err_obj = err.get("error", {})
            code = err_obj.get("code", "") if isinstance(err_obj, dict) else ""
            msg = err_obj.get("message", str(err_obj)) if isinstance(err_obj, dict) else str(err_obj)
            print(f"Trading API error ({e.code}) [{code}]: {msg}", file=sys.stderr)
        except json.JSONDecodeError:
            print(f"Trading API error ({e.code}): {body_resp}", file=sys.stderr)
        sys.exit(1)
    except urllib.error.URLError as e:
        print(f"Connection error: {e.reason}", file=sys.stderr)
        sys.exit(1)


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)