Skill: diagnostikon/polymarket-ai-tech-trader (version 0.0.3)

--- name: polymarket-ai-tech-trader description: Trades Polymarket prediction markets on AI model releases, tech IPOs, product launches, GPU infrastructure milestones, and AI regulation events. Use when you want to capture alpha on the dominant market theme of 2026 — AI and technology — using model benchmark feeds and tech press signals. metadata: author: Diagnostikon version: '1.0' displayName: AI & Tech Launch Trader difficulty: advanced --- # AI & Tech Launch Trader > **This is a template.** > The default signal is keyword discovery + LMSYS Chatbot Arena leaderboard monitoring — remix it with AI benchmark APIs (MMLU, HumanEval), tech news RSS feeds, SEC EDGAR filings for IPO signals, or GitHub commit activity as model release early warning. > The skill handles all the plumbing (market discovery, trade execution, safeguards). Your agent provides the alpha. ## Strategy Overview AI markets are the fastest-growing category on Polymarket in 2026. AI investment drove >90% of US GDP gains in H1 2025. This skill trades: - **AI model benchmarks** — Which company leads LMSYS rankings at a given date - **Model releases** — GPT-5, Claude 4, Gemini Ultra release/performance questions - **Tech IPOs** — OpenAI, Databricks, Stripe IPO announcement markets - **Product launches** — Apple Vision Pro 2, Tesla FSD milestones, Tesla Optimus - **AI regulation** — EU AI Act enforcement, US federal AI legislation - **Infrastructure** — NVIDIA datacenter revenue, H100 deployment counts Key insight: AI news cycles are fast and retail trades on headlines. Informed traders with benchmark data have significant edge. ## Signal Logic ### Default Signal: Benchmark Divergence + News Catalyst 1. Discover active AI/tech markets on Polymarket 2. Monitor LMSYS Chatbot Arena for ranking shifts 3. Monitor Hugging Face Open LLM Leaderboard for benchmark updates 4. Compare quantitative model performance data vs market implied probability 5. When a model clearly leads benchmarks but market hasn't repriced, enter 6. For IPO markets: monitor SEC Form S-1 EDGAR filings as leading indicator ### Remix Ideas - **GitHub API**: Watch for sudden commit activity/new repo creation on known model orgs - **Perplexity/Google Trends**: Rising AI search terms as momentum signal - **HuggingFace API**: Model download counts as proxy for adoption - **SEC EDGAR**: Automated S-1 filing alerts for IPO markets - **NVIDIA earnings call transcripts**: Forward guidance vs market pricing on infrastructure markets ## Market Categories Tracked ```python AI_TECH_KEYWORDS = [ "AI", "GPT", "Claude", "Gemini", "OpenAI", "Anthropic", "Google", "model", "benchmark", "AGI", "ChatGPT", "LLM", "IPO", "valuation", "Stripe", "Databricks", "SpaceX IPO", "Apple", "Vision Pro", "Tesla FSD", "Optimus", "robot", "NVIDIA", "GPU", "H100", "datacenter", "quantum", "EU AI Act", "regulation", "congress" ] ``` ## Risk Parameters | Parameter | Default | Notes | |-----------|---------|-------| | Max position size | $40 USDC | High-liquidity markets allow larger size | | Min market volume | $10,000 | AI markets are deeply liquid | | Max bid-ask spread | 6% | Tight spreads expected in popular markets | | Min days to resolution | 5 | News cycles move fast | | Max open positions | 10 | AI/tech is broad category | ## Edge Opportunities ### Retail Recency Bias After a major AI announcement (e.g., GPT-5 release), retail traders overweight recency and push other company markets down more than warranted. Fade the overreaction on competing platforms. ### Benchmark Lag Markets often price on last-known model rankings. When a new benchmark publishes at ~midnight UTC, markets take 1–4 hours to fully reprice. Tight monitoring loop captures this window. ## Installation & Setup ```bash clawhub install polymarket-ai-tech-trader ``` Requires: `SIMMER_API_KEY` environment variable. ## Cron Schedule Runs every 5 minutes (`*/5 * * * *`). AI news breaks around the clock; tightest loop of all category skills. ## Safety & Execution Mode **The skill defaults to paper trading (`venue="sim"`). Real trades only execute when `--live` is passed explicitly.** | Scenario | Mode | Financial risk | |----------|------|----------------| | `python trader.py` | Paper (sim) | None | | Cron / automaton | Paper (sim) | None | | `python trader.py --live` | Live (polymarket) | Real USDC | The automaton cron is set to `null` — it does not run on a schedule until you configure it in the Simmer UI. `autostart: false` means it won't start automatically on install. ## Required Credentials | Variable | Required | Notes | |----------|----------|-------| | `SIMMER_API_KEY` | Yes | Trading authority — keep this credential private. Do not place a live-capable key in any environment where automated code could call `--live`. | ## Tunables (Risk Parameters) All risk parameters are declared in `clawhub.json` as `tunables` and adjustable from the Simmer UI without code changes. They use `SIMMER_`-prefixed env vars so `apply_skill_config()` can load them securely. | Variable | Default | Purpose | |----------|---------|---------| | `SIMMER_MAX_POSITION` | `40` | Max USDC per trade (full conviction) | | `SIMMER_MIN_TRADE` | `5` | Min USDC per trade (weak conviction floor) | | `SIMMER_MIN_VOLUME` | `10000` | Min market volume filter (USD) | | `SIMMER_MAX_SPREAD` | `0.06` | Max bid-ask spread (0.10 = 10%) | | `SIMMER_MIN_DAYS` | `5` | Min days until market resolves | | `SIMMER_MAX_POSITIONS` | `10` | Max concurrent open positions | | `SIMMER_YES_THRESHOLD` | `0.38` | Buy YES if market probability ≤ this value | | `SIMMER_NO_THRESHOLD` | `0.62` | Sell NO if market probability ≥ this value | ### Conviction-based position sizing Position size scales automatically with signal strength — no flat bets. - At the threshold boundary (e.g. p=38% for YES): minimum trade (`SIMMER_MIN_TRADE`, default $5) - At maximum conviction (p=0% for YES, p=100% for NO): full position (`SIMMER_MAX_POSITION`, default $40) - Everything in between scales linearly **Example YES trades:** | Market probability | Conviction | Size | |--------------------|------------|------| | 38% (at threshold) | 0% | $5 (floor) | | 30% | 21% | $8 | | 20% | 47% | $19 | | 5% | 87% | $35 | | 0% | 100% | $40 | This means the skill automatically bets more when the edge is larger, and less when the signal is marginal.

path: clawhub.json
content: {
  "emoji": "\ud83e\udd16",
  "requires": {
    "env": [
      "SIMMER_API_KEY"
    ],
    "pip": [
      "simmer-sdk"
    ]
  },
  "cron": null,
  "autostart": false,
  "automaton": {
    "managed": true,
    "entrypoint": "trader.py"
  },
  "tunables": [
    {
      "env": "SIMMER_MAX_POSITION",
      "default": 40,
      "range": [
        1,
        200
      ],
      "step": 1,
      "label": "Max position size (USD)",
      "type": "number"
    },
    {
      "env": "SIMMER_MIN_VOLUME",
      "default": 1000,
      "range": [
        0,
        100000
      ],
      "step": 1000,
      "label": "Min market volume (USD)",
      "type": "number"
    },
    {
      "env": "SIMMER_MAX_SPREAD",
      "default": 0.06,
      "range": [
        0.01,
        0.5
      ],
      "step": 0.01,
      "label": "Max bid-ask spread",
      "type": "number"
    },
    {
      "env": "SIMMER_MIN_DAYS",
      "default": 0,
      "range": [
        0,
        90
      ],
      "step": 1,
      "label": "Min days until resolution",
      "type": "number"
    },
    {
      "env": "SIMMER_MAX_POSITIONS",
      "default": 8,
      "range": [
        1,
        20
      ],
      "step": 1,
      "label": "Max open positions",
      "type": "number"
    },
    {
      "env": "SIMMER_YES_THRESHOLD",
      "type": "number",
      "default": 0.42,
      "range": [
        0.01,
        0.49
      ],
      "step": 0.01,
      "label": "YES threshold"
    },
    {
      "env": "SIMMER_NO_THRESHOLD",
      "type": "number",
      "default": 0.58,
      "range": [
        0.51,
        0.99
      ],
      "step": 0.01,
      "label": "NO threshold"
    },
    {
      "env": "SIMMER_MIN_TRADE",
      "type": "number",
      "default": 5,
      "range": [
        1,
        100
      ],
      "step": 1,
      "label": "Min trade size (USD)"
    }
  ],
  "version": "0.0.2"
}

path: trader.py
content: """
polymarket-ai-tech-trader
Trades AI model releases, tech IPOs, product launches, and AI infrastructure markets on Polymarket.

SAFE BY DEFAULT:
- No --live flag = paper trading (venue="sim"), zero financial risk.
- Cron/automaton runs default to paper mode.
- Real trades only with explicit --live flag.
"""
import os
import argparse
from datetime import datetime, timezone
from simmer_sdk import SimmerClient

TRADE_SOURCE = "sdk:polymarket-ai-tech-trader"
SKILL_SLUG   = "polymarket-ai-tech-trader"

KEYWORDS = ['AI', 'GPT', 'Claude', 'Gemini', 'OpenAI', 'Anthropic', 'benchmark', 'AGI', 'ChatGPT', 'LLM', 'model release', 'OpenAI IPO', 'Stripe IPO', 'Databricks', 'Apple Vision', 'Tesla FSD', 'NVIDIA', 'H100']

# Risk parameters — declared as tunables in clawhub.json, tunable from Simmer UI.
# Named SIMMER_* so apply_skill_config() can load automaton-managed overrides.
MAX_POSITION   = float(os.environ.get("SIMMER_MAX_POSITION",  "40"))
MIN_VOLUME     = float(os.environ.get("SIMMER_MIN_VOLUME",    "1000"))
MAX_SPREAD     = float(os.environ.get("SIMMER_MAX_SPREAD",    "0.06"))
MIN_DAYS       = int(os.environ.get(  "SIMMER_MIN_DAYS",      "0"))
MAX_POSITIONS  = int(os.environ.get(  "SIMMER_MAX_POSITIONS", "10"))
# Signal thresholds — buy YES below YES_THRESHOLD, sell NO above NO_THRESHOLD.
# Position size scales linearly with conviction: full MAX_POSITION at p=0 (or p=1),
# MIN_TRADE at the threshold boundary.
YES_THRESHOLD  = float(os.environ.get("SIMMER_YES_THRESHOLD", "0.42"))
NO_THRESHOLD   = float(os.environ.get("SIMMER_NO_THRESHOLD",  "0.58"))
MIN_TRADE      = float(os.environ.get("SIMMER_MIN_TRADE",     "5"))

_client: SimmerClient | None = None


def get_client(live: bool = False) -> SimmerClient:
    """
    live=False → venue="sim"  (paper trades — safe default).
    live=True  → venue="polymarket" (real trades, only with --live flag).
    """
    global _client, MAX_POSITION, MIN_VOLUME, MAX_SPREAD, MIN_DAYS, MAX_POSITIONS, YES_THRESHOLD, NO_THRESHOLD, MIN_TRADE
    if _client is None:
        venue = "polymarket" if live else "sim"
        _client = SimmerClient(
            [REDACTED_SECRET]"SIMMER_API_KEY"],
            venue=venue,
        )
        # Load tunable overrides set via the Simmer UI (SIMMER_* vars only).
        if live:
            _client.live = True
        try:
            _client.apply_skill_config(SKILL_SLUG)
        except AttributeError:
            pass  # apply_skill_config only available in Simmer runtime
        # Re-read params in case apply_skill_config updated os.environ.
        MAX_POSITION   = float(os.environ.get("SIMMER_MAX_POSITION",  str(MAX_POSITION)))
        MIN_VOLUME     = float(os.environ.get("SIMMER_MIN_VOLUME",    str(MIN_VOLUME)))
        MAX_SPREAD     = float(os.environ.get("SIMMER_MAX_SPREAD",    str(MAX_SPREAD)))
        MIN_DAYS       = int(os.environ.get(  "SIMMER_MIN_DAYS",      str(MIN_DAYS)))
        MAX_POSITIONS  = int(os.environ.get(  "SIMMER_MAX_POSITIONS", str(MAX_POSITIONS)))
        YES_THRESHOLD  = float(os.environ.get("SIMMER_YES_THRESHOLD", str(YES_THRESHOLD)))
        NO_THRESHOLD   = float(os.environ.get("SIMMER_NO_THRESHOLD",  str(NO_THRESHOLD)))
        MIN_TRADE      = float(os.environ.get("SIMMER_MIN_TRADE",     str(MIN_TRADE)))
    return _client


def find_markets(client: SimmerClient) -> list:
    """Find active markets matching strategy keywords, deduplicated."""
    seen, unique = set(), []

    # Fast markets (may not exist in older SDK)
    try:
        for m in client.get_fast_markets():
            q = getattr(m, "question", "").lower()
            if m.id not in seen and any(w in q for w in ("ai ", "gpt", "claude", "openai", "google ai", "model", "artificial intelligence")):
                seen.add(m.id)
                unique.append(m)
    except (AttributeError, Exception):
        pass

    # Keyword search
    for kw in KEYWORDS:
        try:
            for m in client.find_markets(query=kw):
                if m.id not in seen:
                    seen.add(m.id)
                    unique.append(m)
        except Exception as e:
            print(f"[search] {kw!r}: {e}")

    # Bulk scan fallback
    try:
        for m in client.get_markets(limit=200):
            q = getattr(m, "question", "").lower()
            if m.id not in seen and any(w in q for w in ("ai ", "gpt", "claude", "openai", "google ai", "model", "artificial intelligence")):
                seen.add(m.id)
                unique.append(m)
    except Exception:
        pass

    return unique


def compute_signal(market) -> tuple[str | None, float, str]:
    """
    Returns (side, size, reasoning) or (None, 0, skip_reason).

    Conviction-based sizing: position scales linearly with edge distance from
    the threshold — MIN_TRADE at the boundary, MAX_POSITION at p=0 (or p=1).
    This means a market at 20% gets a larger bet than one at 35%.

    Benchmark lag 1-4h after LMSYS/HuggingFace updates.
    """
    p = market.current_probability
    q = market.question

    # Spread gate
    if market.spread_cents is not None and market.spread_cents / 100 > MAX_SPREAD:
        return None, 0, f"Spread {market.spread_cents/100:.1%} > {MAX_SPREAD:.1%}"

    # Days-to-resolution gate
    if market.resolves_at:
        try:
            resolves = datetime.fromisoformat(market.resolves_at.replace("Z", "+00:00"))
            days = (resolves - datetime.now(timezone.utc)).days
            if days < MIN_DAYS:
                return None, 0, f"Only {days} days to resolve"
        except Exception:
            pass

    if p <= YES_THRESHOLD:
        # conviction=0 at threshold boundary, conviction=1 at p=0
        conviction = (YES_THRESHOLD - p) / YES_THRESHOLD
        size = max(MIN_TRADE, round(conviction * MAX_POSITION, 2))
        edge = YES_THRESHOLD - p
        return "yes", size, f"YES {p:.0%} edge={edge:.0%} size=${size} — {q[:70]}"

    if p >= NO_THRESHOLD:
        conviction = (p - NO_THRESHOLD) / (1 - NO_THRESHOLD)
        size = max(MIN_TRADE, round(conviction * MAX_POSITION, 2))
        edge = p - NO_THRESHOLD
        return "no", size, f"NO YES={p:.0%} edge={edge:.0%} size=${size} — {q[:70]}"

    return None, 0, f"Neutral at {p:.1%} (outside {YES_THRESHOLD:.0%}/{NO_THRESHOLD:.0%} bands)"


def context_ok(client: SimmerClient, market_id: str) -> tuple[bool, str]:
    """Check flip-flop and slippage safeguards."""
    try:
        ctx = client.get_market_context(market_id)
        if not ctx:
            return True, "no context"
        if ctx.get("discipline", {}).get("is_flip_flop"):
            reason = ctx["discipline"].get("flip_flop_reason", "recent reversal")
            return False, f"Flip-flop: {reason}"
        slip = ctx.get("slippage", {})
        if isinstance(slip, dict) and slip.get("slippage_pct", 0) > 0.15:
            return False, f"Slippage {slip['slippage_pct']:.1%}"
        for w in ctx.get("warnings", []):
            print(f"  [warn] {w}")
    except Exception as e:
        print(f"  [ctx] {market_id}: {e}")
    return True, "ok"


def run(live: bool = False) -> None:
    mode = "LIVE" if live else "PAPER (sim)"
    print(f"[polymarket-ai-tech-trader] mode={mode} max_pos=${MAX_POSITION} min_vol=${MIN_VOLUME} max_spread={MAX_SPREAD:.0%} min_days={MIN_DAYS}")

    client  = get_client(live=live)
    markets = find_markets(client)
    print(f"[polymarket-ai-tech-trader] {len(markets)} candidate markets")

    placed = 0
    for m in markets:
        if placed >= MAX_POSITIONS:
            break

        side, size, reasoning = compute_signal(m)
        if not side:
            print(f"  [skip] {reasoning}")
            continue

        ok, why = context_ok(client, m.id)
        if not ok:
            print(f"  [skip] {why}")
            continue

        try:
            r = client.trade(
                market_id=m.id,
                side=side,
                amount=size,
                source=TRADE_SOURCE,
                skill_slug=SKILL_SLUG,
                reasoning=reasoning,
            )
            tag = "(sim)" if r.simulated else "(live)"
            status = "OK" if r.success else f"FAIL:{r.error}"
            print(f"  [trade] {side.upper()} ${size} {tag} {status} — {reasoning[:70]}")
            if r.success:
                placed += 1
        except Exception as e:
            print(f"  [error] {m.id}: {e}")

    print(f"[polymarket-ai-tech-trader] done. {placed} orders placed.")


if __name__ == "__main__":
    ap = argparse.ArgumentParser(description="Trades AI model releases, tech IPOs, product launches, and AI infrastructure markets on Polymarket.")
    ap.add_argument("--live", action="store_true",
                    help="Real trades on Polymarket. Default is paper (sim) mode.")
    run(live=ap.parse_args().live)


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