Xpulse

Real-time X/Twitter social signal scanner for prediction market traders. Scans via DuckDuckGo (zero API cost) with two-stage local Qwen AI filtering: tradeable signal detection, then materiality gating to prevent alert fatigue. Position-aware — only alerts on signals matching your active Kalshi positions. Fail-closed design: silence over noise. Part of the OpenClaw Prediction Market Trading Stack — signals feed into Market Morning Brief and correlate with Prediction Market Arbiter divergences.

Safety Notice

This listing is from the official public ClawHub registry. Review SKILL.md and referenced scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "Xpulse" with this command: npx skills add kingmadellc/xpulse

Xpulse — Real-Time Social Signal Scanner

Overview

Xpulse is a real-time X/Twitter signal scanner optimized for prediction market traders. It detects market-relevant signals on configurable topics using a three-stage intelligence pipeline:

  1. Stage 1: Signal Detection — Scans X via DuckDuckGo (site:x.com queries), analyzes posts with local Qwen for tradeable signals
  2. Stage 2: Materiality Gate — Compares against 48h signal history, filters out noise and repeat signals (fail-closed)
  3. Stage 3: Position Matching — Only alerts on signals that match active Kalshi positions (keyword overlap, 2+ keywords required)

Key philosophy: Zero API costs (DuckDuckGo + local Qwen), fail-closed design (silence over noise), position-aware filtering (no irrelevant alerts).

When to Use This Skill

  • You're actively trading prediction markets on Kalshi
  • You want real-time social signals for your active positions
  • You prefer local LLM analysis over expensive API calls
  • You need to prevent notification fatigue from generic social signals
  • You want signals cached for morning brief consumption

Requirements

Python & Dependencies

  • Python 3.10 or higher
  • Required packages:
    pip install ddgs pyyaml
    

Local Infrastructure

  • Ollama (https://ollama.ai) with Qwen model
    • Install from https://ollama.ai (macOS, Linux, Windows)
    • Then: ollama pull qwen3:latest
    • Must be running: ollama serve (background process)

Kalshi API (for position matching)

  • Free Kalshi account with API credentials (https://kalshi.com)
    • API key ID
    • Private key file (ES256 format)
    • Cost: Free (read-only access to positions)

Configuration

Create or update your config.yaml:

kalshi:
  enabled: true
  api_key_id: "your-key-id"
  private_key_file: "/path/to/private.key"

ollama:
  enabled: true
  model: "qwen3:latest"
  timeout_seconds: 30

xpulse:
  enabled: true
  check_interval_minutes: 30
  topics:
    - "tariff"
    - "Ukraine"
    - "inflation"
    - "Fed rate"
    - "Trump policy"
  min_confidence: 0.7       # Stage 1: signal confidence threshold
  materiality_gate: true    # Stage 2: enable 48h deduplication
  position_gate: true       # Stage 3: only alert on matched positions
  max_history_entries: 200

Topics Configuration

topics list should contain:

  • Market-relevant keywords you're interested in
  • DuckDuckGo will search: site:x.com {topic}
  • Examples: "Trump tariff", "inflation CPI", "Fed rate", "crypto SEC", "presidential election"

Thresholds

ParameterDefaultMeaning
min_confidence0.7Stage 1: Only keep signals with ≥70% AI confidence of being tradeable
check_interval_minutes30Minimum minutes between scans (prevent API hammering)
materiality_gatetrueStage 2: Enable/disable deduplication filter
position_gatetrueStage 3: Enable/disable Kalshi position matching
max_history_entries200Max entries in 48h signal history (auto-trimmed)

The Three-Stage Pipeline

Stage 1: Signal Detection

Input: List of topics (e.g., ["tariff", "inflation", "Ukraine"])

Process:

  1. For each topic, search X/Twitter via DuckDuckGo: site:x.com {topic}
  2. Fetch up to 5 recent posts
  3. Feed posts to local Qwen with this prompt:
You are a prediction market analyst. Given these recent X/Twitter posts about '{topic}',
determine if there's a tradeable signal.

{combined_posts}

Respond in JSON: {"has_signal": true/false, "confidence": 0.0-1.0,
"direction": "bullish/bearish/neutral", "summary": "one line"}

Thresholding: Only keep signals where:

  • has_signal == true
  • confidence >= min_confidence (default 0.7)

Output: List of candidate signals with direction + confidence


Stage 2: Materiality Gate (Fail-Closed)

Input: Candidate signals from Stage 1 + 48h signal history

Purpose: Prevent alert fatigue by filtering out:

  • Repeat signals about the same story (different wording)
  • Ongoing background noise (tariffs in news for days)
  • Speculation with no concrete new event
  • Minor updates to previously alerted developments

Process:

  1. Load recently sent signal history (last 20 alerts, 48h window)
  2. Build prompt with:
    • Candidate new signals
    • What the user already knows (recent alerts)
  3. Send to Qwen:
You are a personal alert filter for a prediction market trader.
Your job is to PREVENT notification fatigue.

RECENTLY SENT ALERTS (what the user already knows):
- [3h ago] tariff: Trump announces new steel tariffs (confidence: 0.82)
- [6h ago] inflation: Core CPI steady at 3.2% (confidence: 0.75)

CANDIDATE NEW SIGNALS:
- [tariff] Trump discusses additional tariffs (confidence: 0.68)
- [inflation] Fed signals no near-term cuts (confidence: 0.79)

RULES:
- REJECT if same story as recent alert (even different wording)
- REJECT if ongoing background noise
- REJECT if no concrete new event
- ACCEPT only if genuinely new development or significant escalation
- When in doubt, REJECT. The user prefers silence over noise.

Respond in JSON: {"keep": [list of topic strings to keep], "reasoning": "..."}

Fail-Closed Design:

  • If Qwen fails (timeout, error, unparseable): drop all signals
  • This prevents spam of uncertain signals when the filter breaks
  • Better to miss a signal than spam the user

Output: Filtered list (subset of Stage 1 candidates)


Stage 3: Position Matching Gate

Input: Filtered signals from Stage 2 + active Kalshi positions

Purpose: Only alert the user about signals that match their active positions

Process:

  1. Fetch active Kalshi positions (unsettled)
  2. Extract keywords from ticker + market title (>2 char words)
    • Example: "POTUS-2028-DEM" → keywords: {potus, 2028, dem}
  3. For each signal, extract keywords from topic + summary
  4. Match if 2+ keyword overlap

Example:

Signal: topic="Trump tariff", summary="Trump announces new steel tariffs"
Signal words: {trump, tariff, steel, announces, new}

Kalshi position: ticker="TRUMP-TARIFF-2025", title="Will Trump enact steel tariffs?"
Position keywords: {trump, tariff, 2025, steel, enact}

Overlap: {trump, tariff, steel} = 3 keywords ✓ MATCH
→ Signal passes to iMessage alert

Suppressed Signals:

  • Signals without matching positions are logged silently
  • Available in cache (.x_signal_cache.json) for morning brief
  • Not sent to user

Output: Critical signals matched to positions → iMessage alert


Signal Caching

All signals (pre-filter) are cached in .x_signal_cache.json:

{
  "signals": [
    {
      "topic": "tariff",
      "confidence": 0.82,
      "direction": "bearish",
      "summary": "Trump announces new steel tariffs",
      "post_count": 3
    }
  ],
  "topics_scanned": 5,
  "timestamp": 1709990400.0
}

Used for:

  • Morning brief consumption (all signals, even suppressed ones)
  • On-demand signal review (what was detected but not alerted)
  • Debugging signal pipeline

Running Xpulse

Command Line

# Single run
python -m xpulse.xpulse

# With full logging
DEBUG=1 python -m xpulse.xpulse

# Dry run (logs but doesn't send alerts)
python -m xpulse.xpulse --dry-run

# Force a run regardless of interval
python -m xpulse.xpulse --force

Scheduled (Every 30 Minutes)

Via OpenClaw config:

skills:
  xpulse:
    enabled: true
    schedule: "*/30 * * * *"
    timeout_seconds: 120

Via crontab:

# Add to crontab -e:
*/30 * * * * cd /path/to/xpulse && python -m xpulse.xpulse >> /tmp/xpulse.log 2>&1

Via launchd (macOS):

<!-- ~/.launchd/com.xpulse.scanner.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.xpulse.scanner</string>
  <key>ProgramArguments</key>
  <array>
    <string>/usr/bin/python3</string>
    <string>/path/to/xpulse.py</string>
  </array>
  <key>StartInterval</key>
  <integer>1800</integer>
  <key>StandardOutPath</key>
  <string>/tmp/xpulse.log</string>
  <key>StandardErrorPath</key>
  <string>/tmp/xpulse.log</string>
</dict>
</plist>

Example Output

Alert to iMessage (Stage 3 Pass)

⚠️ X signal — affects your Kalshi positions:

  📈 Trump tariff: Trump announces new 25% steel tariffs (82% conf) [TRUMP-TARIFF-2025]
  📉 Inflation: Core CPI stays sticky, Fed unlikely to cut (75% conf) [FED-RATE-2026]
  ➡️  Ukraine: Peace talks accelerate, settlement probability rising (68% conf) [UKRAINE-2026]

Signal Cache (Stage 1 → Morning Brief)

{
  "signals": [
    {
      "topic": "Trump tariff",
      "confidence": 0.82,
      "direction": "bearish",
      "summary": "Trump announces new 25% steel tariffs",
      "post_count": 3
    },
    {
      "topic": "inflation",
      "confidence": 0.75,
      "direction": "bearish",
      "summary": "Core CPI stays sticky, Fed unlikely to cut further",
      "post_count": 2
    }
  ],
  "topics_scanned": 5,
  "timestamp": 1709990400.0
}

Materiality Gate — Technical Details

See references/materiality-gate.md for detailed explanation of:

  • How the 48h rolling window works
  • Example filtering scenarios (signal vs noise)
  • Fail-closed behavior

Position Matching — Technical Details

See references/position-matching.md for:

  • Keyword extraction algorithm (>2 char threshold)
  • Overlap matching logic (2+ keyword requirement)
  • Example position-signal pairs

Troubleshooting

Ollama Not Running

Error: Connection refused or ollama: command not found

Fix:

# Start Ollama in background
ollama serve &

# Or install if missing:
# Install from https://ollama.ai, then:
ollama pull qwen:latest

Qwen Model Not Found

Error: ollama run qwen:latest fails

Fix:

ollama pull qwen:latest
# Or use qwen3 if available:
# ollama pull qwen3:latest

DuckDuckGo Returning No Results

Likely causes:

  • Topic is too specific or niche
  • No recent posts on X about that topic
  • DuckDuckGo rate limiting (try again later)

Debug:

from ddgs import DDGS
d = DDGS()
results = list(d.text("site:x.com Trump tariff", max_results=5))
print(results)

No Kalshi Positions (Stage 3 Suppresses All)

Expected behavior: If you have no active Kalshi positions, all signals are suppressed (logged silently). This is intentional — position-aware alerting is the goal.

To test: Either:

  1. Create a test Kalshi position matching your topic
  2. Disable Stage 3: set position_gate: false in config (alerts all non-materiality signals)

Signal History Growing Too Large

Automatic: History is capped at 200 entries (oldest trimmed first)

Manual reset:

rm ~/.openclaw/state/x_signal_history.json

Qwen Prompts (Core IP)

Stage 1 Prompt: Signal Detection

You are a prediction market analyst. Given these recent X/Twitter posts about '{topic}',
determine if there's a tradeable signal.

{combined_posts}

Respond in JSON: {"has_signal": true/false, "confidence": 0.0-1.0,
"direction": "bullish/bearish/neutral", "summary": "one line"}

Stage 2 Prompt: Materiality Gate

You are a personal alert filter for a prediction market trader.
Your job is to PREVENT notification fatigue. Only let through signals that are genuinely NEW and MATERIAL.

RECENTLY SENT ALERTS (what the user already knows):
{history_block}

CANDIDATE NEW SIGNALS:
{candidate_block}

RULES:
- REJECT if the signal covers the same story/development as a recent alert (even with different wording)
- REJECT if it's ongoing background noise (e.g. 'Trump discusses tariffs' when tariffs have been in the news for days)
- REJECT if there's no concrete new event, just commentary or speculation
- ACCEPT only if: (a) a genuinely new development occurred (vote, announcement, emergency, data release, market move),
OR (b) a significant escalation/reversal of something previously reported
- When in doubt, REJECT. The user prefers silence over noise.

Respond in JSON: {"keep": [list of topic strings to keep], "reasoning": "one line explaining why"}

OpenClaw Ecosystem Integration

Social signal intelligence layer for the Prediction Market Trading Stack.

Connected SkillHow It Connects
Market Morning BriefX signals appear in your daily morning digest
KalshalystSocial signals validate or challenge contrarian edges
Prediction Market ArbiterCorrelate social sentiment with cross-platform divergences
Kalshi Command CenterAct on position-matched signals via trade execution

Install the complete stack:

clawhub install kalshalyst kalshi-command-center polymarket-command-center prediction-market-arbiter xpulse portfolio-drift-monitor market-morning-brief personality-engine

Implementation Notes

Battle-tested in production trading environments. Design principles:

  1. Standalone implementation — zero external dependencies beyond listed packages
  2. Direct alerts — sends signals straight to you via your OpenClaw agent
  3. All thresholds, filters, and prompts — refined through live social signal monitoring
  4. Fail-closed design — no signal is better than a false positive
  5. Scripts are standalone — works with any OpenClaw setup

Performance & Cost

Typical Run

  • Runtime: 1-2 minutes (5 topics, Qwen Stage 1+2)
  • API calls:
    • DuckDuckGo: 5 calls (1 per topic)
    • Kalshi: 1 call (fetch positions)
    • Ollama (local): 2 calls (Stage 1 + 2)
  • Cost: $0 (DuckDuckGo free, Ollama local, Kalshi free read-only)

Scaling

10 runs per day = ~10-20 minutes total runtime + zero API cost. Minimal resource usage.


Further Reading

  • references/materiality-gate.md — Signal deduplication + 48h window
  • references/position-matching.md — Keyword overlap logic

API Reference

Main Function

from xpulse import check_x_signals

# Single run
result = check_x_signals(state={}, dry_run=False, force=False)
# Returns: bool (True if alert sent, False otherwise)

State Management

# State dict tracks:
state = {
  "last_x_signal_check": 1709990400.0,  # Unix timestamp of last scan
  "last_x_signals_silent": [...]        # Suppressed signals (logged only)
}

Support & Iteration

Xpulse is designed for iteration:

  1. Topic Tuning: Add/remove topics as your trading focus changes
  2. Confidence Threshold: Lower min_confidence to catch more signals (noisier), raise to reduce false positives
  3. Materiality Gate: Disable if you're missing important signals, enable if too noisy
  4. Position Gate: Disable position_gate: false if you want ALL signals (not recommended)
  5. Qwen Prompts: Customize Stage 1/2 prompts for your trading style

License & Attribution

Author: KingMadeLLC


Feedback & Issues

Found a bug? Have a feature request? Want to share results?

Part of the OpenClaw Prediction Stack — the first prediction market skill suite on ClawHub.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

yuqing-bitable-and-label

Incrementally sync data from XiaoAi API to Feishu Bitable and optionally auto-label records with machine-based type and sentiment annotations.

Registry SourceRecently Updated
General

张律师综合套装

张律师法律AI中台 - 中国首个开源法律AI技能库,涵盖刑事辩护、民商事诉讼、合同审查全流程

Registry SourceRecently Updated
General

刑事辩护

刑事辩护全流程AI助手 - 6大阶段21个模板,从接案到执行全覆盖

Registry SourceRecently Updated