> ## Documentation Index
> Fetch the complete documentation index at: https://polymarketcn.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Subgraph 概覽

> 使用 The Graph 協議查詢 Polymarket 鏈上數據

<Callout type="success">
  還沒有帳號？[點擊這裡註冊 Polymarket](https://polymarket.com/?r=2026VIP) 並完成入金，才能用錢包私鑰為訂單籤名、實際成交。
</Callout>

<Warning>
  **法律合規提醒**：在使用 Polymarket 服務或 API 前，請確認您所在地區的法律規定。Polymarket 目前不支援比利時、法國、新加坡、泰國、中國大陸等地區，政策可能隨時變化。
</Warning>

Polymarket Subgraph 提供了一個強大的 GraphQL 接口，用於查詢 Polymarket 的鏈上數據。

## 什麼是 Subgraph？

Subgraph 是基於 The Graph 協議構建的索引服務，它：

* 📊 索引區塊鏈數據
* ⚡ 提供快速查詢
* 🔍 支援複雜的數據關係
* 🆓 免費使用

<Callout type="info">
  **The Graph** 是一個去中心化的索引協議，用於組織區塊鏈數據並使其易於訪問。
</Callout>

## Polymarket Subgraph

Polymarket 維護了官方的 Subgraph，索引了：

* 條件代幣合約數據
* 市場創建和結算
* 用戶頭寸和交易
* 條件 ID 和位置 ID

### Subgraph 端點

**Polygon 主網**：

```
https://api.thegraph.com/subgraphs/name/polymarket/polymarket
```

## 為什麼使用 Subgraph？

相比直接查詢區塊鏈，Subgraph 提供：

| 特性   | 直接查詢區塊鏈     | 使用 Subgraph |
| ---- | ----------- | ----------- |
| 速度   | 慢           | 快           |
| 複雜查詢 | 困難          | 簡單          |
| 歷史數據 | 需要掃描所有區塊    | 已索引         |
| 關係查詢 | 需要多次調用      | 一次查詢        |
| 成本   | 需要大量 RPC 調用 | 免費          |

## GraphQL 查詢示例

### 查詢市場信息

```graphql theme={null}
query {
  conditions(first: 5, orderBy: createdTimestamp, orderDirection: desc) {
    id
    oracle
    questionId
    outcomeSlotCount
    resolved
    payouts
    createdTimestamp
  }
}
```

### 查詢用戶頭寸

```graphql theme={null}
query UserPositions($userAddress: String!) {
  userPositions(where: { user: $userAddress }) {
    id
    position {
      id
      conditionIds
    }
    balance
    wrappedBalance
  }
}
```

### 查詢特定條件

```graphql theme={null}
query Condition($conditionId: String!) {
  condition(id: $conditionId) {
    id
    oracle
    questionId
    outcomeSlotCount
    resolved
    resolveTimestamp
    payouts
    positions {
      id
      collateralToken
      indexSets
    }
  }
}
```

## Python 使用示例

```python theme={null}
import requests
import json

# Subgraph 端點
SUBGRAPH_URL = "https://api.thegraph.com/subgraphs/name/polymarket/polymarket"

def query_subgraph(query, variables=None):
    """
    查詢 Polymarket Subgraph
    """
    payload = {
        'query': query,
        'variables': variables or {}
    }
    
    response = requests.post(SUBGRAPH_URL, json=payload)
    return response.json()

# 查詢最近的條件
query = """
{
  conditions(first: 10, orderBy: createdTimestamp, orderDirection: desc) {
    id
    oracle
    questionId
    outcomeSlotCount
    resolved
    createdTimestamp
  }
}
"""

result = query_subgraph(query)
conditions = result['data']['conditions']

for condition in conditions:
    print(f"條件 ID: {condition['id'][:10]}...")
    print(f"結果數: {condition['outcomeSlotCount']}")
    print(f"已解決: {condition['resolved']}")
    print("---")
```

### 查詢用戶頭寸

```python theme={null}
def get_user_positions(user_address):
    """
    獲取用戶的所有頭寸
    """
    query = """
    query UserPositions($userAddress: String!) {
      userPositions(where: { user: $userAddress }) {
        id
        position {
          id
          conditionIds
          collateralToken {
            id
            symbol
          }
        }
        balance
        wrappedBalance
      }
    }
    """
    
    variables = {'userAddress': user_address.lower()}
    result = query_subgraph(query, variables)
    
    return result['data']['userPositions']

# 使用示例
user_address = "0x1234567890123456789012345678901234567890"
positions = get_user_positions(user_address)

for position in positions:
    print(f"頭寸 ID: {position['id'][:10]}...")
    print(f"餘額: {int(position['balance']) / 10**6} USDC")
    print("---")
```

## TypeScript 使用示例

```typescript theme={null}
import axios from 'axios';

const SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/polymarket/polymarket';

interface SubgraphResponse<T> {
  data: T;
  errors?: any[];
}

async function querySubgraph<T>(
  query: string,
  variables?: Record<string, any>
): Promise<T> {
  const response = await axios.post<SubgraphResponse<T>>(SUBGRAPH_URL, {
    query,
    variables: variables || {},
  });
  
  if (response.data.errors) {
    throw new Error(JSON.stringify(response.data.errors));
  }
  
  return response.data.data;
}

// 查詢條件
interface Condition {
  id: string;
  oracle: string;
  questionId: string;
  outcomeSlotCount: number;
  resolved: boolean;
  createdTimestamp: string;
}

async function getRecentConditions(): Promise<Condition[]> {
  const query = `
    {
      conditions(first: 10, orderBy: createdTimestamp, orderDirection: desc) {
        id
        oracle
        questionId
        outcomeSlotCount
        resolved
        createdTimestamp
      }
    }
  `;
  
  const result = await querySubgraph<{ conditions: Condition[] }>(query);
  return result.conditions;
}

// 使用示例
getRecentConditions().then(conditions => {
  conditions.forEach(condition => {
    console.log(`條件 ID: ${condition.id.slice(0, 10)}...`);
    console.log(`已解決: ${condition.resolved}`);
    console.log('---');
  });
});
```

## 常見查詢模式

### 1. 分頁查詢

```graphql theme={null}
query PaginatedConditions($skip: Int!, $first: Int!) {
  conditions(
    first: $first
    skip: $skip
    orderBy: createdTimestamp
    orderDirection: desc
  ) {
    id
    questionId
    resolved
  }
}
```

### 2. 過濾查詢

```graphql theme={null}
query ResolvedConditions {
  conditions(where: { resolved: true }) {
    id
    resolveTimestamp
    payouts
  }
}
```

### 3. 關係查詢

```graphql theme={null}
query ConditionWithPositions($conditionId: String!) {
  condition(id: $conditionId) {
    id
    positions {
      id
      indexSets
      userPositions {
        user {
          id
        }
        balance
      }
    }
  }
}
```

## 數據模型

### Condition（條件）

```typescript theme={null}
type Condition {
  id: ID!                      // 條件 ID
  oracle: Bytes!               // Oracle 地址
  questionId: Bytes!           // 問題 ID
  outcomeSlotCount: BigInt!    // 結果數量
  resolved: Boolean!           // 是否已解決
  resolveTimestamp: BigInt     // 解決時間戳
  payouts: [BigInt!]          // 支付向量
  positions: [Position!]!      // 相關頭寸
  createdTimestamp: BigInt!    // 創建時間戳
}
```

### Position（頭寸）

```typescript theme={null}
type Position {
  id: ID!                      // 頭寸 ID
  collateralToken: CollateralToken!  // 抵押品代幣
  conditionIds: [Bytes!]!      // 條件 ID 列表
  indexSets: [BigInt!]!        // 索引集
  userPositions: [UserPosition!]!  // 用戶頭寸
}
```

### UserPosition（用戶頭寸）

```typescript theme={null}
type UserPosition {
  id: ID!                      // 用戶頭寸 ID
  user: User!                  // 用戶
  position: Position!          // 頭寸
  balance: BigInt!             // 餘額
  wrappedBalance: BigInt!      // 包裝餘額
}
```

## 實用工具

### 監控市場結算

```python theme={null}
import time

def monitor_settlements():
    """
    監控市場結算
    """
    last_check = int(time.time())
    
    while True:
        query = """
        query RecentSettlements($timestamp: Int!) {
          conditions(
            where: { 
              resolved: true
              resolveTimestamp_gt: $timestamp
            }
            orderBy: resolveTimestamp
            orderDirection: desc
          ) {
            id
            questionId
            resolveTimestamp
            payouts
          }
        }
        """
        
        result = query_subgraph(query, {'timestamp': last_check})
        conditions = result['data']['conditions']
        
        if conditions:
            print(f"\n發現 {len(conditions)} 個新結算:")
            for condition in conditions:
                print(f"條件 ID: {condition['id'][:10]}...")
                print(f"支付: {condition['payouts']}")
                print("---")
            
            # 更新最後檢查時間
            last_check = int(conditions[0]['resolveTimestamp'])
        
        time.sleep(60)  # 每分鐘檢查一次

# 運行監控
# monitor_settlements()
```

## 性能優化

### 1. 限制欄位

只查詢需要的欄位：

```graphql theme={null}
# ✗ 差：查詢所有欄位
query {
  conditions(first: 100) {
    id
    oracle
    questionId
    outcomeSlotCount
    resolved
    resolveTimestamp
    payouts
    positions {
      id
      # ... 很多欄位
    }
  }
}

# ✓ 好：只查詢需要的欄位
query {
  conditions(first: 100) {
    id
    resolved
  }
}
```

### 2. 使用分頁

```python theme={null}
def get_all_conditions():
    """
    分頁獲取所有條件
    """
    all_conditions = []
    skip = 0
    first = 1000  # The Graph 最大限制
    
    while True:
        query = """
        query PaginatedConditions($skip: Int!, $first: Int!) {
          conditions(first: $first, skip: $skip) {
            id
            resolved
          }
        }
        """
        
        result = query_subgraph(query, {'skip': skip, 'first': first})
        conditions = result['data']['conditions']
        
        if not conditions:
            break
        
        all_conditions.extend(conditions)
        skip += first
        
        if len(conditions) < first:
            break
    
    return all_conditions
```

## 限制

<Warning>
  **注意事項**：

  1. **查詢限制**：單次查詢最多返回 1000 條記錄
  2. **速率限制**：公共端點有速率限制
  3. **延遲**：Subgraph 可能有幾秒到幾分鐘的延遲
  4. **數據完整性**：依賴於索引器的同步狀態
</Warning>

## GraphQL Playground

你可以在 The Graph Explorer 中交互式地測試查詢：

```
https://thegraph.com/explorer/subgraph/polymarket/polymarket
```

## 下一步

<CardGroup cols={2}>
  <Card title="條件代幣框架" icon="code" href="/api-tutorial/conditional-tokens/overview">
    了解條件代幣
  </Card>

  <Card title="CLOB API" icon="chart-line" href="/api-tutorial/clob/introduction">
    學習 CLOB 交易
  </Card>

  <Card title="The Graph 文檔" icon="book" href="https://thegraph.com/docs">
    深入學習 GraphQL
  </Card>

  <Card title="Gamma API" icon="database" href="/api-tutorial/gamma-structure/overview">
    使用 Gamma API
  </Card>
</CardGroup>

## 參考資源

* **The Graph 文檔**：[https://thegraph.com/docs](https://thegraph.com/docs)
* **GraphQL 教程**：[https://graphql.org/learn/](https://graphql.org/learn/)
* **Polymarket Subgraph**：[https://thegraph.com/explorer/subgraph/polymarket/polymarket](https://thegraph.com/explorer/subgraph/polymarket/polymarket)
