🧠 NLP QUANT · LOCAL LLM · HFT

Polymarket NLP 情感套利系统

顶级华尔街 NLP 量化策略 — 实时抓取彭博/路透/Twitter 突发新闻, 由本地 GPU 驱动的大模型(Llama-3 / Mistral)瞬间解析情感与概率偏差, 在公众反应之前自动向 Polymarket 注入套利订单。 完全本地推理,零 API 延迟,数据绝对隐私。

847
LLM 推理延迟 (ms)
0
本会话信号数
9.3%
平均套利边缘
≥7¢
最低 edge 触发
4
系统模块

🏗️ 系统架构(端到端延迟 <3秒)

📡
信息流接入
Twitter Filtered Stream
Bloomberg/Reuters RSS
关键词白/黑名单过滤
~15s RSS / 实时 WS
🧠
本地 LLM
Ollama / vLLM
Llama-3-8B q4
JSON 结构化输出
500ms–2s(GPU)
🎯
概率引擎
相关度评分
方向判断 YES/NO
Δp 概率偏移
内含于 LLM
⚖️
风控审批
信源置信度分级
幻觉熔断器
日亏损限额
<1ms
CLOB 执行
市场搜索匹配
edge 计算
FOK 市价扫单
<500ms
数据流说明:突发新闻 → 关键词过滤 → LLM 解析(强制 JSON,含 relevance/direction/prob_delta/confidence) → 若 relevance≥0.65 且 edge≥7¢ → 拉取 CLOB 实时价 → Kelly 定仓 → FOK 扫单 → 持仓监控(30s)→ 收敛平仓
📡
MODULE 01
全天候低延迟信息流

异步多源新闻聚合,Twitter Filtered Stream v2 + RSS 轮询,智能关键词过滤降噪,信源置信度三级分类。

  • Twitter v2 Filtered Stream —— 实时 WebSocket,0延迟推送
  • 彭博/路透/BBC/NYT RSS —— 15秒轮询,覆盖传统媒体
  • Tier-1 官方账号:@WalterBloomberg/@Reuters/@WhiteHouse
  • 关键词白名单 45+ 条,黑名单自动过滤娱乐/体育
  • 50K 条去重窗口,防止重复处理同一新闻
  • 指数退避重连(2^n 秒,最大120s)
🧠
MODULE 02
本地 LLM 情感概率引擎

系统核心大脑。本地 GPU 驱动的 Llama-3-8B 量化模型,Chain-of-Thought 压缩推理,强制结构化 JSON 输出,完全隐私。

  • 支持 Ollama(/api/generate)和 vLLM(OpenAI-compat)
  • 零温度确定性输出,重复推理结果稳定
  • JSON schema 强校验:relevance/direction/prob_delta/confidence/category
  • 推理超时 8s 自动丢弃,不阻塞执行链
  • 异步并发批处理,最多 4 个飞行中请求
  • q4_K_M 量化,4-bit 精度,VRAM <8GB
MODULE 03
错价捕获与订单执行

智能市场匹配 + edge 计算 + FOK 市价扫单,实现抢跑策略。反向平仓锁定超额情绪溢价。

  • Gamma API 关键词搜索匹配活跃市场
  • 实时 CLOB 拉取隐含概率(midpoint),计算 edge
  • edge = LLM公允概率 − 市场价,≥7¢ 才触发
  • FOK 市价单,3% 滑点容忍,确保成交
  • 价格过度反应(超公允5¢)→ 自动反手平仓
  • L2 HMAC-SHA256 身份验证,EIP-712 签名
⚖️
MODULE 04
非对称风险管理

信源置信度分级资金限额 + LLM 幻觉熔断器 + 日亏损限额,三重防护防止 AI 幻觉爆仓。

  • Tier-1 官方源 → 最大15%资金;Tier-3 未知源 → 最大1%
  • 单事件最大 $150 USDC 敞口
  • 幻觉熔断:连续3亏损→50%降档;连续5亏损→暂停1小时
  • 日亏损限额 $200,触发后当日停止交易
  • 单类别(如地缘政治)最大30%总资金敞口
  • 最大持仓 8 个同时活跃事件

💻 核心代码实现

# nlp/sentiment_engine.py — 核心 LLM 调用函数

async def _call_ollama(
    session: aiohttp.ClientSession,
    text: str, cat: str
) -> Optional[dict]:
    """Ollama 本地推理(/api/generate,非流式)"""
    url = f"{llm_cfg.base_url}/api/generate"
    payload = {
        "model": llm_cfg.model,          # "llama3:8b-instruct-q4_K_M"
        "prompt": f"{SYSTEM_PROMPT}\n\n{_build_user_prompt(text, cat)}",
        "stream": False,
        "options": {
            "temperature": 0.0,    # 确定性输出,可复现
            "num_predict": 256,    # JSON 不需要太多 token
        },
    }
    async with session.post(
        url, json=payload,
        timeout=aiohttp.ClientTimeout(total=8.0)  # 超过 8s 丢弃
    ) as resp:
        data = await resp.json()
        raw = data.get("response", "")
        return _extract_json(raw)       # 从输出中提取 JSON 对象


class SentimentEngine:
    async def analyze(self, item: NewsItem) -> Optional[TradingSignal]:
        cat = _detect_category(item.text)
        t0 = time.perf_counter()

        raw = await _call_ollama(self._session, item.text, cat)
        latency_ms = (time.perf_counter() - t0) * 1000

        if raw is None or not _validate_signal(raw):
            return None    # 无效输出直接丢弃

        sig = TradingSignal(
            news_item=item,
            relevance=float(raw["relevance"]),
            direction=raw["direction"],       # YES | NO | NEUTRAL
            prob_delta=float(raw["prob_delta"]),  # +0.15 = +15%
            confidence=float(raw["confidence"]),
            category=raw["category"],
            reasoning=raw.get("reasoning", ""),
            latency_ms=latency_ms,
        )
        return sig
# nlp/sentiment_engine.py — System Prompt 设计(Chain-of-Thought 压缩)

SYSTEM_PROMPT = """
You are a prediction market analyst. Analyze breaking news for Polymarket relevance.
Respond ONLY with valid JSON. No markdown, no explanation outside JSON.

JSON schema (required):
{
  "relevance": <float 0-1>,
  "direction": <"YES"|"NO"|"NEUTRAL">,
  "prob_delta": <float -1 to 1>,
  "confidence": <float 0-1>,
  "category": <"fed_rate"|"us_election"|"geopolitical"|"crypto_reg"|"macro"|"political"|"other">,
  "reasoning": <string max 60 chars>
}

Rules:
- relevance: how likely this news affects an active Polymarket prediction market
- direction: YES = increases probability of YES outcome; NO = decreases it
- prob_delta: estimated absolute change to event probability (e.g. 0.15 = +15%)
- confidence: your certainty in this assessment
- If news is irrelevant, set relevance<0.3, direction=NEUTRAL, prob_delta=0
"""

# 示例 LLM 输出(Fed降息新闻):
# {
#   "relevance": 0.97,
#   "direction": "YES",
#   "prob_delta": 0.23,
#   "confidence": 0.91,
#   "category": "fed_rate",
#   "reasoning": "Emergency 50bps cut signals Fed pivot confirmed"
# }
# execution/order_executor.py — 核心 Alpha 捕获逻辑

async def process_signal(self, signal: TradingSignal) -> bool:
    # ── 1. 搜索匹配市场 ──────────────────────
    cat_kws = CATEGORY_KEYWORDS.get(signal.category, [])
    markets_raw = await self._clob.search_markets(cat_kws)
    markets = [_parse_market(m) for m in markets_raw]

    # ── 2. 计算每个市场的 edge ───────────────
    for market in markets[:5]:
        token_id = (market.yes_token_id if signal.direction == "YES"
                    else market.no_token_id)
        current_price = await self._clob.get_midpoint(token_id)

        # LLM 估算公允价 = 当前价 + 概率偏移
        llm_fair = min(max(current_price + signal.prob_delta, 0.01), 0.99)
        edge = llm_fair - current_price   # 正数 = 被低估

        if edge >= risk_cfg.min_edge_pct:    # ≥ 7¢ 才触发
            best_market = market
            best_edge = edge

    # ── 3. Kelly 定仓 ────────────────────────
    # f* = (b×p - q)/b × 0.25 (1/4 Kelly)
    b = (1 - price) / price
    kelly_f = (b * (price + best_edge) - (1 - price - best_edge)) / b * 0.25
    size_usdc = min(max_capital * kelly_f / 0.15, max_capital)

    # ── 4. 提交 FOK 市价单扫平低价筹码 ───────
    order_id = await self._clob.place_market_order(
        token_id=token_id,
        side="BUY",
        size_usdc=size_usdc,
        price=current_price * 1.03,  # 3% 滑点容忍
    )
    return order_id is not None

async def check_exit_conditions(self):
    for cid, pos in self._open_positions.items():
        current = await self._clob.get_midpoint(pos.token_id)
        # 收敛平仓:当前价格接近 LLM 公允价 ±3¢
        if abs(current - pos.fair_value) <= 0.03:
            await self._clob.place_market_order(..., side="SELL")
        # 过度反应平仓:超过公允价 5¢(散户 FOMO)
        elif current > pos.fair_value + 0.05:
            await self._clob.place_market_order(..., side="SELL")
# feeds/news_firehose.py — 关键词过滤器

class KeywordFilter:
    """白名单命中 AND 黑名单未命中 → 放行"""

    def __init__(self):
        self.whitelist = [w.lower() for w in feed_cfg.keyword_whitelist]
        self.blacklist = [b.lower() for b in feed_cfg.keyword_blacklist]
        self._seen: set[str] = set()   # 去重窗口(最大 50K 条)

    def passes(self, item: NewsItem) -> bool:
        if item.item_id in self._seen:
            return False       # 去重
        low = item.text.lower()
        if any(b in low for b in self.blacklist):
            return False       # 黑名单命中
        if not any(w in low for w in self.whitelist):
            return False       # 白名单未命中
        self._seen.add(item.item_id)
        return True

# 白名单 45+ 条关键词示例:
WHITELIST = [
    "rate cut", "rate hike", "fed funds", "interest rate",
    "election", "resign", "impeach", "indicted",
    "ceasefire", "invasion", "sanction", "nuclear",
    "approve", "reject", "veto", "passed", "signed",
    "bitcoin", "crypto", "sec", "etf approved",
    "gdp", "recession", "unemployment", "cpi",
    "breaking", "urgent", "flash", ...
]
# risk/exposure_manager.py — LLM 幻觉熔断器

def record_close(self, category: str, pnl_usdc: float):
    self._daily_pnl += pnl_usdc

    if pnl_usdc < 0:
        self._consecutive_losses += 1
    else:
        self._consecutive_losses = 0
        self._hallucination_scale = min(
            self._hallucination_scale * 1.1, 1.0
        )

    # 幻觉熔断器三级响应
    if self._consecutive_losses >= 5:
        self._halted_until = time.time() + 3600  # 暂停1小时
        # LLM 可能产生幻觉或模型过时,强制停止
    elif self._consecutive_losses >= 3:
        self._hallucination_scale = 0.5           # 资金降至50%档

def approve_trade(self, signal: TradingSignal):
    # 置信度分级资金上限
    pct = {1: 0.15, 2: 0.05}.get(signal.news_item.tier, 0.01)
    max_usdc = min(
        risk_cfg.total_capital_usdc * pct * self._hallucination_scale,
        150.0   # 单事件绝对上限 $150
    )
    return (not self.is_halted()) and max_usdc > 0, max_usdc

🔴 实时信号流演示

模拟 · 仅供展示

⚖️ 信源置信度资金矩阵

信源级别代表账号/来源最大资金比例最大 USDC
TIER-1@WhiteHouse/@Reuters/美联储官网15%$150
TIER-2@politico/@axios/@disclosetv5%$50
TIER-3未知账号/匿名消息1%$10
单事件类别上限(如地缘政治)30%$300
日亏损限额$200

🔢 LLM JSON 输出格式

{
  "relevance": 0.94,   // 0-1,与 PM 市场相关度
  "direction": "YES",   // YES/NO/NEUTRAL
  "prob_delta": +0.18,  // 概率变化量,+18%
  "confidence": 0.87,  // LLM 自我置信度
  "category": "fed_rate",
  "reasoning": "Emergency cut confirms pivot"
}

// 触发条件:
// relevance ≥ 0.65  AND
// direction ≠ NEUTRAL  AND
// |prob_delta| ≥ 0.05  AND
// confidence ≥ 0.50  AND
// edge (LLM公允 - 市场价) ≥ 0.07 (7¢)

🚀 部署指南

1

安装本地 LLM(Ollama 推荐)

运行 curl -fsSL https://ollama.ai/install.sh | sh,然后 ollama pull llama3:8b-instruct-q4_K_M。RTX 3080+ 推理延迟约 800ms。

2

配置环境变量

设置 POLY_PRIVATE_KEYPOLY_API_KEYPOLY_API_SECRET(从 Polymarket CLOB 获取),以及 TWITTER_BEARER(Twitter v2 API)。

3

安装 Python 依赖

pip install aiohttp feedparser python-dotenv websockets。无需 GPU 专属框架,Ollama 已处理推理。

4

干跑测试(DRY_RUN 默认开启)

运行 python main.py --test-llm 验证 LLM 引擎,python main.py --test-news 验证新闻流,确认无误后设置 DRY_RUN=false 上线。

5

监控信号日志

tail -f /root/pm_nlp/logs/signals.jsonl | jq .,每条可行动信号将包含完整的 JSON 交易信号,实时追踪 edge 与执行结果。

Python asyncio Ollama / vLLM Llama-3-8B q4 Twitter v2 Stream RSS Polling Polymarket CLOB FOK Market Order L2 HMAC Auth Kelly Criterion 幻觉熔断器