接入数据库
This commit is contained in:
1 parent
1bd9d25f60
commit
59fcb11ffa
9 files changed
+1560
-103
No files matched your search
@@ -0,0 +1,390 @@
|
||||
"""
|
||||
Polymarket API 客户端
|
||||
|
||||
用于与Polymarket CLOB API交互,支持:
|
||||
- 搜索BTC相关市场
|
||||
- 获取订单簿和价格
|
||||
- 下单交易
|
||||
"""
|
||||
|
||||
import os
|
||||
import httpx
|
||||
from typing import Optional, Dict, List, Any
|
||||
from dataclasses import dataclass
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# 加载环境变量
|
||||
load_dotenv()
|
||||
|
||||
|
||||
@dataclass
|
||||
class MarketInfo:
|
||||
"""市场信息"""
|
||||
condition_id: str
|
||||
question: str
|
||||
outcomes: List[str]
|
||||
outcome_prices: List[float]
|
||||
tokens: List[Dict]
|
||||
volume: float
|
||||
liquidity: float
|
||||
end_date: str
|
||||
|
||||
|
||||
class PolymarketClient:
|
||||
"""Polymarket API客户端"""
|
||||
|
||||
GAMMA_API = "https://gamma-api.polymarket.com"
|
||||
CLOB_API = "https://clob.polymarket.com"
|
||||
|
||||
def __init__(self, private_key: Optional[str] = None):
|
||||
"""
|
||||
初始化客户端
|
||||
|
||||
Args:
|
||||
private_key: 钱包私钥(用于交易),如不提供则只能读取数据
|
||||
"""
|
||||
self.private_key = private_key or os.getenv("POLYMARKET_PRIVATE_KEY")
|
||||
|
||||
# 配置代理
|
||||
proxy = os.getenv("SOCKS5_PROXY") if os.getenv("USE_PROXY", "false").lower() == "true" else None
|
||||
|
||||
# HTTP客户端 - 禁用压缩避免brotli问题
|
||||
self.http = httpx.Client(
|
||||
timeout=30.0,
|
||||
proxy=proxy,
|
||||
headers={'Accept-Encoding': 'identity'} # 禁用压缩
|
||||
)
|
||||
|
||||
# 如果有私钥,初始化CLOB客户端
|
||||
self.clob_client = None
|
||||
if self.private_key:
|
||||
self._init_clob_client()
|
||||
|
||||
def _init_clob_client(self):
|
||||
"""初始化CLOB交易客户端"""
|
||||
try:
|
||||
from py_clob_client.client import ClobClient
|
||||
from py_clob_client.clob_types import ApiCreds
|
||||
|
||||
# Polygon链ID
|
||||
chain_id = 137
|
||||
|
||||
# 初始化客户端
|
||||
self.clob_client = ClobClient(
|
||||
host=self.CLOB_API,
|
||||
key=self.private_key,
|
||||
chain_id=chain_id,
|
||||
)
|
||||
|
||||
# 获取或创建API凭证
|
||||
self.clob_client.set_api_creds(self.clob_client.create_or_derive_api_creds())
|
||||
|
||||
print("✓ CLOB客户端初始化成功")
|
||||
except Exception as e:
|
||||
print(f"⚠️ CLOB客户端初始化失败: {e}")
|
||||
self.clob_client = None
|
||||
|
||||
def search_markets(self, query: str = "BTC", limit: int = 20) -> List[Dict]:
|
||||
"""
|
||||
搜索市场
|
||||
|
||||
Args:
|
||||
query: 搜索关键词
|
||||
limit: 返回数量限制
|
||||
|
||||
Returns:
|
||||
市场列表
|
||||
"""
|
||||
try:
|
||||
response = self.http.get(
|
||||
f"{self.GAMMA_API}/markets",
|
||||
params={
|
||||
"active": "true",
|
||||
"closed": "false",
|
||||
"limit": limit,
|
||||
}
|
||||
)
|
||||
response.raise_for_status()
|
||||
markets = response.json()
|
||||
|
||||
# 过滤包含关键词的市场
|
||||
filtered = [m for m in markets if query.lower() in m.get("question", "").lower()]
|
||||
return filtered
|
||||
except Exception as e:
|
||||
print(f"搜索市场失败: {e}")
|
||||
return []
|
||||
|
||||
def search_btc_1h_markets(self) -> List[Dict]:
|
||||
"""
|
||||
搜索BTC 1小时价格预测市场
|
||||
|
||||
Returns:
|
||||
BTC 1H相关市场列表
|
||||
"""
|
||||
try:
|
||||
response = self.http.get(
|
||||
f"{self.GAMMA_API}/markets",
|
||||
params={
|
||||
"active": "true",
|
||||
"closed": "false",
|
||||
"limit": 100,
|
||||
}
|
||||
)
|
||||
response.raise_for_status()
|
||||
markets = response.json()
|
||||
|
||||
# 过滤BTC 1小时相关市场
|
||||
btc_1h_markets = []
|
||||
keywords = ["btc", "bitcoin"]
|
||||
time_keywords = ["1h", "1 hour", "hourly", "hour"]
|
||||
|
||||
for m in markets:
|
||||
question = m.get("question", "").lower()
|
||||
# 检查是否包含BTC关键词
|
||||
has_btc = any(kw in question for kw in keywords)
|
||||
# 检查是否包含1小时关键词
|
||||
has_1h = any(kw in question for kw in time_keywords)
|
||||
|
||||
if has_btc and has_1h:
|
||||
btc_1h_markets.append(m)
|
||||
|
||||
return btc_1h_markets
|
||||
except Exception as e:
|
||||
print(f"搜索BTC 1H市场失败: {e}")
|
||||
return []
|
||||
|
||||
def get_market_info(self, condition_id: str) -> Optional[MarketInfo]:
|
||||
"""
|
||||
获取市场详细信息
|
||||
|
||||
Args:
|
||||
condition_id: 市场条件ID
|
||||
|
||||
Returns:
|
||||
市场信息对象
|
||||
"""
|
||||
try:
|
||||
response = self.http.get(f"{self.GAMMA_API}/markets/{condition_id}")
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
|
||||
return MarketInfo(
|
||||
condition_id=data.get("conditionId", ""),
|
||||
question=data.get("question", ""),
|
||||
outcomes=data.get("outcomes", []),
|
||||
outcome_prices=data.get("outcomePrices", []),
|
||||
tokens=data.get("tokens", []),
|
||||
volume=float(data.get("volume", 0)),
|
||||
liquidity=float(data.get("liquidity", 0)),
|
||||
end_date=data.get("endDate", ""),
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"获取市场信息失败: {e}")
|
||||
return None
|
||||
|
||||
def get_orderbook(self, token_id: str) -> Dict:
|
||||
"""
|
||||
获取订单簿
|
||||
|
||||
Args:
|
||||
token_id: 代币ID
|
||||
|
||||
Returns:
|
||||
订单簿数据
|
||||
"""
|
||||
try:
|
||||
response = self.http.get(
|
||||
f"{self.CLOB_API}/book",
|
||||
params={"token_id": token_id}
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except Exception as e:
|
||||
print(f"获取订单簿失败: {e}")
|
||||
return {}
|
||||
|
||||
def get_price(self, token_id: str) -> Optional[float]:
|
||||
"""
|
||||
获取代币当前价格
|
||||
|
||||
Args:
|
||||
token_id: 代币ID
|
||||
|
||||
Returns:
|
||||
当前价格(0-1之间)
|
||||
"""
|
||||
try:
|
||||
response = self.http.get(
|
||||
f"{self.CLOB_API}/price",
|
||||
params={"token_id": token_id, "side": "buy"}
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
return float(data.get("price", 0))
|
||||
except Exception as e:
|
||||
print(f"获取价格失败: {e}")
|
||||
return None
|
||||
|
||||
def place_market_order(
|
||||
self,
|
||||
token_id: str,
|
||||
side: str, # "BUY" or "SELL"
|
||||
amount: float, # USDC金额
|
||||
) -> Optional[Dict]:
|
||||
"""
|
||||
下市价单
|
||||
|
||||
Args:
|
||||
token_id: 代币ID
|
||||
side: 买卖方向 "BUY" 或 "SELL"
|
||||
amount: 下注金额(USDC)
|
||||
|
||||
Returns:
|
||||
订单响应
|
||||
"""
|
||||
if not self.clob_client:
|
||||
print("❌ CLOB客户端未初始化,无法下单")
|
||||
return None
|
||||
|
||||
try:
|
||||
from py_clob_client.order_builder.constants import BUY, SELL
|
||||
|
||||
order_side = BUY if side.upper() == "BUY" else SELL
|
||||
|
||||
# 创建市价单
|
||||
order = self.clob_client.create_market_order(
|
||||
token_id=token_id,
|
||||
amount=amount,
|
||||
side=order_side,
|
||||
)
|
||||
|
||||
# 提交订单
|
||||
response = self.clob_client.post_order(order)
|
||||
print(f"✓ 订单已提交: {response}")
|
||||
return response
|
||||
except Exception as e:
|
||||
print(f"❌ 下单失败: {e}")
|
||||
return None
|
||||
|
||||
def place_limit_order(
|
||||
self,
|
||||
token_id: str,
|
||||
side: str, # "BUY" or "SELL"
|
||||
price: float, # 价格(0-1)
|
||||
size: float, # 数量
|
||||
) -> Optional[Dict]:
|
||||
"""
|
||||
下限价单
|
||||
|
||||
Args:
|
||||
token_id: 代币ID
|
||||
side: 买卖方向 "BUY" 或 "SELL"
|
||||
price: 价格(0-1之间)
|
||||
size: 购买数量
|
||||
|
||||
Returns:
|
||||
订单响应
|
||||
"""
|
||||
if not self.clob_client:
|
||||
print("❌ CLOB客户端未初始化,无法下单")
|
||||
return None
|
||||
|
||||
try:
|
||||
from py_clob_client.order_builder.constants import BUY, SELL
|
||||
|
||||
order_side = BUY if side.upper() == "BUY" else SELL
|
||||
|
||||
# 创建限价单
|
||||
order = self.clob_client.create_limit_order(
|
||||
token_id=token_id,
|
||||
price=price,
|
||||
size=size,
|
||||
side=order_side,
|
||||
)
|
||||
|
||||
# 提交订单
|
||||
response = self.clob_client.post_order(order)
|
||||
print(f"✓ 限价单已提交: {response}")
|
||||
return response
|
||||
except Exception as e:
|
||||
print(f"❌ 下单失败: {e}")
|
||||
return None
|
||||
|
||||
def get_positions(self) -> List[Dict]:
|
||||
"""
|
||||
获取当前仓位
|
||||
|
||||
Returns:
|
||||
仓位列表
|
||||
"""
|
||||
if not self.clob_client:
|
||||
print("❌ CLOB客户端未初始化")
|
||||
return []
|
||||
|
||||
try:
|
||||
positions = self.clob_client.get_positions()
|
||||
return positions
|
||||
except Exception as e:
|
||||
print(f"获取仓位失败: {e}")
|
||||
return []
|
||||
|
||||
def cancel_order(self, order_id: str) -> bool:
|
||||
"""
|
||||
取消订单
|
||||
|
||||
Args:
|
||||
order_id: 订单ID
|
||||
|
||||
Returns:
|
||||
是否成功
|
||||
"""
|
||||
if not self.clob_client:
|
||||
print("❌ CLOB客户端未初始化")
|
||||
return False
|
||||
|
||||
try:
|
||||
self.clob_client.cancel(order_id)
|
||||
print(f"✓ 订单已取消: {order_id}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"❌ 取消订单失败: {e}")
|
||||
return False
|
||||
|
||||
def close(self):
|
||||
"""关闭客户端"""
|
||||
self.http.close()
|
||||
|
||||
|
||||
# 测试函数
|
||||
def test_search_markets():
|
||||
"""测试搜索市场功能"""
|
||||
client = PolymarketClient()
|
||||
|
||||
print("搜索BTC相关市场...")
|
||||
markets = client.search_markets("BTC", limit=10)
|
||||
|
||||
if markets:
|
||||
print(f"\n找到 {len(markets)} 个BTC相关市场:\n")
|
||||
for m in markets[:5]:
|
||||
print(f" 问题: {m.get('question', 'N/A')}")
|
||||
print(f" 条件ID: {m.get('conditionId', 'N/A')}")
|
||||
print(f" 结果: {m.get('outcomes', [])}")
|
||||
print(f" 价格: {m.get('outcomePrices', [])}")
|
||||
print("-" * 50)
|
||||
else:
|
||||
print("未找到BTC相关市场")
|
||||
|
||||
print("\n搜索BTC 1H市场...")
|
||||
btc_1h = client.search_btc_1h_markets()
|
||||
if btc_1h:
|
||||
print(f"找到 {len(btc_1h)} 个BTC 1H市场")
|
||||
for m in btc_1h:
|
||||
print(f" {m.get('question', 'N/A')}")
|
||||
else:
|
||||
print("未找到BTC 1H市场")
|
||||
|
||||
client.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_search_markets()
|
||||
Reference in new issue
Block a user