polymarket-backtest 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- polymarket_backtest-0.1.0/PKG-INFO +216 -0
- polymarket_backtest-0.1.0/README.md +188 -0
- polymarket_backtest-0.1.0/polymarket_backtest/__init__.py +35 -0
- polymarket_backtest-0.1.0/polymarket_backtest/api/__init__.py +13 -0
- polymarket_backtest-0.1.0/polymarket_backtest/api/clob.py +136 -0
- polymarket_backtest-0.1.0/polymarket_backtest/api/gamma.py +194 -0
- polymarket_backtest-0.1.0/polymarket_backtest/api/models.py +69 -0
- polymarket_backtest-0.1.0/polymarket_backtest/backtest/__init__.py +21 -0
- polymarket_backtest-0.1.0/polymarket_backtest/backtest/metrics.py +286 -0
- polymarket_backtest-0.1.0/polymarket_backtest/data/__init__.py +11 -0
- polymarket_backtest-0.1.0/polymarket_backtest/data/loader.py +136 -0
- polymarket_backtest-0.1.0/polymarket_backtest/data/sample/btc_orderbook.csv +13750 -0
- polymarket_backtest-0.1.0/polymarket_backtest/data/sample/flash_crash_summary.csv +3 -0
- polymarket_backtest-0.1.0/polymarket_backtest/data/sample/flash_crash_trades.csv +23 -0
- polymarket_backtest-0.1.0/polymarket_backtest/data/sample/hedge_arb_trades.csv +5 -0
- polymarket_backtest-0.1.0/polymarket_backtest.egg-info/PKG-INFO +216 -0
- polymarket_backtest-0.1.0/polymarket_backtest.egg-info/SOURCES.txt +20 -0
- polymarket_backtest-0.1.0/polymarket_backtest.egg-info/dependency_links.txt +1 -0
- polymarket_backtest-0.1.0/polymarket_backtest.egg-info/requires.txt +7 -0
- polymarket_backtest-0.1.0/polymarket_backtest.egg-info/top_level.txt +1 -0
- polymarket_backtest-0.1.0/pyproject.toml +46 -0
- polymarket_backtest-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: polymarket-backtest
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Polymarket API wrapper and strategy backtesting metrics toolkit
|
|
5
|
+
Author-email: Your Name <you@example.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/yourname/polymarket-backtest
|
|
8
|
+
Project-URL: Repository, https://github.com/yourname/polymarket-backtest
|
|
9
|
+
Project-URL: Issues, https://github.com/yourname/polymarket-backtest/issues
|
|
10
|
+
Keywords: polymarket,prediction-market,backtest,trading,quantitative
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Requires-Dist: requests>=2.28
|
|
23
|
+
Requires-Dist: numpy>=1.24
|
|
24
|
+
Requires-Dist: pandas>=2.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
|
|
28
|
+
|
|
29
|
+
# polymarket-backtest
|
|
30
|
+
|
|
31
|
+
Polymarket API 封装与策略回测评估工具包。
|
|
32
|
+
|
|
33
|
+
## 功能
|
|
34
|
+
|
|
35
|
+
- **API 封装**:Polymarket Gamma API(合约信息)、CLOB API(赔率历史时间序列)
|
|
36
|
+
- **内置数据集**:BTC 15 分钟市场盘口快照 + Flash Crash / Hedge Arb 策略回测记录
|
|
37
|
+
- **回测指标**:Sharpe Ratio、最大回撤、胜率、盈亏比、卡玛比率
|
|
38
|
+
|
|
39
|
+
## 安装
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install -e /path/to/polymarket_backtest
|
|
43
|
+
# 或
|
|
44
|
+
cd /path/to/polymarket_backtest && pip install -e .
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 快速开始
|
|
48
|
+
|
|
49
|
+
### 1. 查询合约信息
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from polymarket_backtest.api import GammaClient
|
|
53
|
+
|
|
54
|
+
gamma = GammaClient()
|
|
55
|
+
|
|
56
|
+
# 获取当前活跃的 BTC 15 分钟市场
|
|
57
|
+
market = gamma.get_market_info("BTC")
|
|
58
|
+
print(market.slug) # "btc-updown-15m-1775035200"
|
|
59
|
+
print(market.up_price) # 0.52
|
|
60
|
+
print(market.down_price) # 0.48
|
|
61
|
+
print(market.up_token_id) # "229931..."
|
|
62
|
+
|
|
63
|
+
# 列出最近 5 个市场
|
|
64
|
+
markets = gamma.list_recent_markets("ETH", n=5)
|
|
65
|
+
for m in markets:
|
|
66
|
+
print(m.slug, m.end_date)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 2. 拉取赔率历史
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from polymarket_backtest.api import GammaClient, ClobClient
|
|
73
|
+
|
|
74
|
+
gamma = GammaClient()
|
|
75
|
+
clob = ClobClient()
|
|
76
|
+
|
|
77
|
+
market = gamma.get_market_info("BTC")
|
|
78
|
+
|
|
79
|
+
# 拉取最近 1 天数据(每小时 1 个点)
|
|
80
|
+
history = clob.get_price_history(
|
|
81
|
+
market.up_token_id,
|
|
82
|
+
interval="1d",
|
|
83
|
+
fidelity=60,
|
|
84
|
+
)
|
|
85
|
+
print(f"获取到 {len(history)} 个价格点")
|
|
86
|
+
|
|
87
|
+
for point in history.points[:3]:
|
|
88
|
+
print(point.timestamp, point.price)
|
|
89
|
+
|
|
90
|
+
# 直接返回 DataFrame
|
|
91
|
+
df = clob.get_price_history_df(market.up_token_id, interval="1w", fidelity=60)
|
|
92
|
+
print(df.head())
|
|
93
|
+
# timestamp price datetime
|
|
94
|
+
# 0 1697875200 0.520 2023-10-21 08:00:00+00:00
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 3. 加载内置数据集
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from polymarket_backtest.data import list_datasets, load_orderbook, load_trades, load_summary
|
|
101
|
+
|
|
102
|
+
# 查看可用数据集
|
|
103
|
+
for ds in list_datasets():
|
|
104
|
+
print(f" {ds['name']}: {ds['description']}")
|
|
105
|
+
|
|
106
|
+
# 加载 BTC 盘口快照(~13750 行)
|
|
107
|
+
ob = load_orderbook("BTC")
|
|
108
|
+
print(ob.columns.tolist())
|
|
109
|
+
# ['recorded_at_ts', 'market_slug', 'coin', 'up_bid', 'up_ask', ...]
|
|
110
|
+
|
|
111
|
+
# 加载 Flash Crash 策略交易记录
|
|
112
|
+
trades = load_trades("flash_crash")
|
|
113
|
+
print(trades[["coin", "side", "gross_pnl", "exit_reason"]].head())
|
|
114
|
+
|
|
115
|
+
# 加载 Hedge Arb 策略交易记录
|
|
116
|
+
hedge_trades = load_trades("hedge_arb")
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### 4. 计算回测指标
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from polymarket_backtest.backtest import summary, sharpe_ratio, max_drawdown, win_rate
|
|
123
|
+
from polymarket_backtest.data import load_trades
|
|
124
|
+
|
|
125
|
+
# 加载回测数据
|
|
126
|
+
trades = load_trades("flash_crash")
|
|
127
|
+
pnl = trades["gross_pnl"].dropna().tolist()
|
|
128
|
+
|
|
129
|
+
# 综合摘要
|
|
130
|
+
result = summary(pnl)
|
|
131
|
+
print(result)
|
|
132
|
+
# {
|
|
133
|
+
# 'total_trades': 22,
|
|
134
|
+
# 'net_pnl': 47.92,
|
|
135
|
+
# 'avg_pnl': 2.18,
|
|
136
|
+
# 'std_pnl': 5.67,
|
|
137
|
+
# 'win_rate': 0.143,
|
|
138
|
+
# 'profit_factor': 1.08,
|
|
139
|
+
# 'sharpe_ratio': 0.384,
|
|
140
|
+
# 'max_drawdown': 18.5,
|
|
141
|
+
# 'max_drawdown_pct': 22.3,
|
|
142
|
+
# 'calmar_ratio': 2.59
|
|
143
|
+
# }
|
|
144
|
+
|
|
145
|
+
# 单独计算各指标
|
|
146
|
+
print("Sharpe Ratio:", sharpe_ratio(pnl))
|
|
147
|
+
print("年化 Sharpe (15m 市场):", sharpe_ratio(pnl, periods_per_year=35040))
|
|
148
|
+
|
|
149
|
+
dd = max_drawdown(pnl)
|
|
150
|
+
print(f"最大回撤: {dd['max_drawdown']:.2f} USDC ({dd['max_drawdown_pct']:.1f}%)")
|
|
151
|
+
|
|
152
|
+
print("胜率:", win_rate(pnl))
|
|
153
|
+
|
|
154
|
+
# 直接从 DataFrame 计算
|
|
155
|
+
from polymarket_backtest.backtest import summary_from_df
|
|
156
|
+
result2 = summary_from_df(trades, pnl_col="gross_pnl")
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## API 参考
|
|
160
|
+
|
|
161
|
+
### `GammaClient`
|
|
162
|
+
|
|
163
|
+
| 方法 | 说明 |
|
|
164
|
+
|------|------|
|
|
165
|
+
| `get_market_info(coin)` | 获取当前活跃的 15 分钟市场信息 |
|
|
166
|
+
| `get_market_by_slug(slug)` | 通过 slug 精确查询 |
|
|
167
|
+
| `list_recent_markets(coin, n=10)` | 列出最近 n 个市场 |
|
|
168
|
+
|
|
169
|
+
### `ClobClient`
|
|
170
|
+
|
|
171
|
+
| 方法 | 说明 |
|
|
172
|
+
|------|------|
|
|
173
|
+
| `get_price_history(token_id, interval, fidelity, ...)` | 拉取赔率历史,返回 `OddsHistory` |
|
|
174
|
+
| `get_price_history_df(token_id, ...)` | 同上,返回 `pd.DataFrame` |
|
|
175
|
+
|
|
176
|
+
**interval 参数**:`"1m"` / `"1h"` / `"6h"` / `"1d"` / `"1w"` / `"max"`
|
|
177
|
+
|
|
178
|
+
### 内置数据集
|
|
179
|
+
|
|
180
|
+
| 名称 | 描述 |
|
|
181
|
+
|------|------|
|
|
182
|
+
| `btc_orderbook` | BTC 15 分钟盘口快照,~13750 行 |
|
|
183
|
+
| `flash_crash_trades` | Flash Crash 策略逐笔交易 |
|
|
184
|
+
| `flash_crash_summary` | Flash Crash 策略汇总统计 |
|
|
185
|
+
| `hedge_arb_trades` | Hedge Arbitrage 策略逐笔交易 |
|
|
186
|
+
|
|
187
|
+
### 回测指标
|
|
188
|
+
|
|
189
|
+
| 函数 | 说明 |
|
|
190
|
+
|------|------|
|
|
191
|
+
| `sharpe_ratio(pnl, periods_per_year=None)` | 夏普比率,可选年化 |
|
|
192
|
+
| `max_drawdown(pnl)` | 最大回撤(金额 + 百分比) |
|
|
193
|
+
| `win_rate(pnl)` | 胜率 [0, 1] |
|
|
194
|
+
| `profit_factor(pnl)` | 盈亏比 |
|
|
195
|
+
| `calmar_ratio(pnl)` | 卡玛比率 |
|
|
196
|
+
| `summary(pnl, periods_per_year=None)` | 综合统计摘要 |
|
|
197
|
+
| `summary_from_df(df, pnl_col="net_pnl")` | 直接从 DataFrame 计算 |
|
|
198
|
+
|
|
199
|
+
## 数据说明
|
|
200
|
+
|
|
201
|
+
盘口数据字段说明:
|
|
202
|
+
|
|
203
|
+
| 字段 | 说明 |
|
|
204
|
+
|------|------|
|
|
205
|
+
| `recorded_at_ts` | UNIX 时间戳(秒) |
|
|
206
|
+
| `up_bid / up_ask / up_mid` | UP 方向的买/卖/中间价 |
|
|
207
|
+
| `down_bid / down_ask / down_mid` | DOWN 方向的买/卖/中间价 |
|
|
208
|
+
| `remaining_seconds` | 距市场结束的秒数 |
|
|
209
|
+
| `elapsed_seconds` | 市场已进行的秒数 |
|
|
210
|
+
|
|
211
|
+
## 依赖
|
|
212
|
+
|
|
213
|
+
- Python >= 3.10
|
|
214
|
+
- `requests` >= 2.28
|
|
215
|
+
- `numpy` >= 1.24(可选,如未安装则用纯标准库计算)
|
|
216
|
+
- `pandas` >= 2.0
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# polymarket-backtest
|
|
2
|
+
|
|
3
|
+
Polymarket API 封装与策略回测评估工具包。
|
|
4
|
+
|
|
5
|
+
## 功能
|
|
6
|
+
|
|
7
|
+
- **API 封装**:Polymarket Gamma API(合约信息)、CLOB API(赔率历史时间序列)
|
|
8
|
+
- **内置数据集**:BTC 15 分钟市场盘口快照 + Flash Crash / Hedge Arb 策略回测记录
|
|
9
|
+
- **回测指标**:Sharpe Ratio、最大回撤、胜率、盈亏比、卡玛比率
|
|
10
|
+
|
|
11
|
+
## 安装
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install -e /path/to/polymarket_backtest
|
|
15
|
+
# 或
|
|
16
|
+
cd /path/to/polymarket_backtest && pip install -e .
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 快速开始
|
|
20
|
+
|
|
21
|
+
### 1. 查询合约信息
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from polymarket_backtest.api import GammaClient
|
|
25
|
+
|
|
26
|
+
gamma = GammaClient()
|
|
27
|
+
|
|
28
|
+
# 获取当前活跃的 BTC 15 分钟市场
|
|
29
|
+
market = gamma.get_market_info("BTC")
|
|
30
|
+
print(market.slug) # "btc-updown-15m-1775035200"
|
|
31
|
+
print(market.up_price) # 0.52
|
|
32
|
+
print(market.down_price) # 0.48
|
|
33
|
+
print(market.up_token_id) # "229931..."
|
|
34
|
+
|
|
35
|
+
# 列出最近 5 个市场
|
|
36
|
+
markets = gamma.list_recent_markets("ETH", n=5)
|
|
37
|
+
for m in markets:
|
|
38
|
+
print(m.slug, m.end_date)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 2. 拉取赔率历史
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from polymarket_backtest.api import GammaClient, ClobClient
|
|
45
|
+
|
|
46
|
+
gamma = GammaClient()
|
|
47
|
+
clob = ClobClient()
|
|
48
|
+
|
|
49
|
+
market = gamma.get_market_info("BTC")
|
|
50
|
+
|
|
51
|
+
# 拉取最近 1 天数据(每小时 1 个点)
|
|
52
|
+
history = clob.get_price_history(
|
|
53
|
+
market.up_token_id,
|
|
54
|
+
interval="1d",
|
|
55
|
+
fidelity=60,
|
|
56
|
+
)
|
|
57
|
+
print(f"获取到 {len(history)} 个价格点")
|
|
58
|
+
|
|
59
|
+
for point in history.points[:3]:
|
|
60
|
+
print(point.timestamp, point.price)
|
|
61
|
+
|
|
62
|
+
# 直接返回 DataFrame
|
|
63
|
+
df = clob.get_price_history_df(market.up_token_id, interval="1w", fidelity=60)
|
|
64
|
+
print(df.head())
|
|
65
|
+
# timestamp price datetime
|
|
66
|
+
# 0 1697875200 0.520 2023-10-21 08:00:00+00:00
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 3. 加载内置数据集
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from polymarket_backtest.data import list_datasets, load_orderbook, load_trades, load_summary
|
|
73
|
+
|
|
74
|
+
# 查看可用数据集
|
|
75
|
+
for ds in list_datasets():
|
|
76
|
+
print(f" {ds['name']}: {ds['description']}")
|
|
77
|
+
|
|
78
|
+
# 加载 BTC 盘口快照(~13750 行)
|
|
79
|
+
ob = load_orderbook("BTC")
|
|
80
|
+
print(ob.columns.tolist())
|
|
81
|
+
# ['recorded_at_ts', 'market_slug', 'coin', 'up_bid', 'up_ask', ...]
|
|
82
|
+
|
|
83
|
+
# 加载 Flash Crash 策略交易记录
|
|
84
|
+
trades = load_trades("flash_crash")
|
|
85
|
+
print(trades[["coin", "side", "gross_pnl", "exit_reason"]].head())
|
|
86
|
+
|
|
87
|
+
# 加载 Hedge Arb 策略交易记录
|
|
88
|
+
hedge_trades = load_trades("hedge_arb")
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 4. 计算回测指标
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from polymarket_backtest.backtest import summary, sharpe_ratio, max_drawdown, win_rate
|
|
95
|
+
from polymarket_backtest.data import load_trades
|
|
96
|
+
|
|
97
|
+
# 加载回测数据
|
|
98
|
+
trades = load_trades("flash_crash")
|
|
99
|
+
pnl = trades["gross_pnl"].dropna().tolist()
|
|
100
|
+
|
|
101
|
+
# 综合摘要
|
|
102
|
+
result = summary(pnl)
|
|
103
|
+
print(result)
|
|
104
|
+
# {
|
|
105
|
+
# 'total_trades': 22,
|
|
106
|
+
# 'net_pnl': 47.92,
|
|
107
|
+
# 'avg_pnl': 2.18,
|
|
108
|
+
# 'std_pnl': 5.67,
|
|
109
|
+
# 'win_rate': 0.143,
|
|
110
|
+
# 'profit_factor': 1.08,
|
|
111
|
+
# 'sharpe_ratio': 0.384,
|
|
112
|
+
# 'max_drawdown': 18.5,
|
|
113
|
+
# 'max_drawdown_pct': 22.3,
|
|
114
|
+
# 'calmar_ratio': 2.59
|
|
115
|
+
# }
|
|
116
|
+
|
|
117
|
+
# 单独计算各指标
|
|
118
|
+
print("Sharpe Ratio:", sharpe_ratio(pnl))
|
|
119
|
+
print("年化 Sharpe (15m 市场):", sharpe_ratio(pnl, periods_per_year=35040))
|
|
120
|
+
|
|
121
|
+
dd = max_drawdown(pnl)
|
|
122
|
+
print(f"最大回撤: {dd['max_drawdown']:.2f} USDC ({dd['max_drawdown_pct']:.1f}%)")
|
|
123
|
+
|
|
124
|
+
print("胜率:", win_rate(pnl))
|
|
125
|
+
|
|
126
|
+
# 直接从 DataFrame 计算
|
|
127
|
+
from polymarket_backtest.backtest import summary_from_df
|
|
128
|
+
result2 = summary_from_df(trades, pnl_col="gross_pnl")
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## API 参考
|
|
132
|
+
|
|
133
|
+
### `GammaClient`
|
|
134
|
+
|
|
135
|
+
| 方法 | 说明 |
|
|
136
|
+
|------|------|
|
|
137
|
+
| `get_market_info(coin)` | 获取当前活跃的 15 分钟市场信息 |
|
|
138
|
+
| `get_market_by_slug(slug)` | 通过 slug 精确查询 |
|
|
139
|
+
| `list_recent_markets(coin, n=10)` | 列出最近 n 个市场 |
|
|
140
|
+
|
|
141
|
+
### `ClobClient`
|
|
142
|
+
|
|
143
|
+
| 方法 | 说明 |
|
|
144
|
+
|------|------|
|
|
145
|
+
| `get_price_history(token_id, interval, fidelity, ...)` | 拉取赔率历史,返回 `OddsHistory` |
|
|
146
|
+
| `get_price_history_df(token_id, ...)` | 同上,返回 `pd.DataFrame` |
|
|
147
|
+
|
|
148
|
+
**interval 参数**:`"1m"` / `"1h"` / `"6h"` / `"1d"` / `"1w"` / `"max"`
|
|
149
|
+
|
|
150
|
+
### 内置数据集
|
|
151
|
+
|
|
152
|
+
| 名称 | 描述 |
|
|
153
|
+
|------|------|
|
|
154
|
+
| `btc_orderbook` | BTC 15 分钟盘口快照,~13750 行 |
|
|
155
|
+
| `flash_crash_trades` | Flash Crash 策略逐笔交易 |
|
|
156
|
+
| `flash_crash_summary` | Flash Crash 策略汇总统计 |
|
|
157
|
+
| `hedge_arb_trades` | Hedge Arbitrage 策略逐笔交易 |
|
|
158
|
+
|
|
159
|
+
### 回测指标
|
|
160
|
+
|
|
161
|
+
| 函数 | 说明 |
|
|
162
|
+
|------|------|
|
|
163
|
+
| `sharpe_ratio(pnl, periods_per_year=None)` | 夏普比率,可选年化 |
|
|
164
|
+
| `max_drawdown(pnl)` | 最大回撤(金额 + 百分比) |
|
|
165
|
+
| `win_rate(pnl)` | 胜率 [0, 1] |
|
|
166
|
+
| `profit_factor(pnl)` | 盈亏比 |
|
|
167
|
+
| `calmar_ratio(pnl)` | 卡玛比率 |
|
|
168
|
+
| `summary(pnl, periods_per_year=None)` | 综合统计摘要 |
|
|
169
|
+
| `summary_from_df(df, pnl_col="net_pnl")` | 直接从 DataFrame 计算 |
|
|
170
|
+
|
|
171
|
+
## 数据说明
|
|
172
|
+
|
|
173
|
+
盘口数据字段说明:
|
|
174
|
+
|
|
175
|
+
| 字段 | 说明 |
|
|
176
|
+
|------|------|
|
|
177
|
+
| `recorded_at_ts` | UNIX 时间戳(秒) |
|
|
178
|
+
| `up_bid / up_ask / up_mid` | UP 方向的买/卖/中间价 |
|
|
179
|
+
| `down_bid / down_ask / down_mid` | DOWN 方向的买/卖/中间价 |
|
|
180
|
+
| `remaining_seconds` | 距市场结束的秒数 |
|
|
181
|
+
| `elapsed_seconds` | 市场已进行的秒数 |
|
|
182
|
+
|
|
183
|
+
## 依赖
|
|
184
|
+
|
|
185
|
+
- Python >= 3.10
|
|
186
|
+
- `requests` >= 2.28
|
|
187
|
+
- `numpy` >= 1.24(可选,如未安装则用纯标准库计算)
|
|
188
|
+
- `pandas` >= 2.0
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
polymarket-backtest
|
|
3
|
+
===================
|
|
4
|
+
|
|
5
|
+
Polymarket API 封装与策略回测评估工具包。
|
|
6
|
+
|
|
7
|
+
快速开始:
|
|
8
|
+
# 1. 查询市场信息
|
|
9
|
+
from polymarket_backtest.api import GammaClient, ClobClient
|
|
10
|
+
|
|
11
|
+
gamma = GammaClient()
|
|
12
|
+
market = gamma.get_market_info("BTC")
|
|
13
|
+
print(market.slug, market.up_price)
|
|
14
|
+
|
|
15
|
+
# 2. 拉取赔率历史
|
|
16
|
+
clob = ClobClient()
|
|
17
|
+
history = clob.get_price_history(market.up_token_id, interval="1d")
|
|
18
|
+
print(f"{len(history)} 个价格点")
|
|
19
|
+
|
|
20
|
+
# 3. 加载内置示例数据集
|
|
21
|
+
from polymarket_backtest.data import load_trades, load_orderbook
|
|
22
|
+
|
|
23
|
+
trades = load_trades("flash_crash")
|
|
24
|
+
ob = load_orderbook("BTC")
|
|
25
|
+
|
|
26
|
+
# 4. 计算回测指标
|
|
27
|
+
from polymarket_backtest.backtest import summary
|
|
28
|
+
|
|
29
|
+
pnl = trades["gross_pnl"].dropna().tolist()
|
|
30
|
+
result = summary(pnl)
|
|
31
|
+
print(result)
|
|
32
|
+
# {'net_pnl': 47.92, 'win_rate': 0.143, 'sharpe_ratio': 0.85, 'max_drawdown': 12.5, ...}
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Polymarket API 封装模块。"""
|
|
2
|
+
|
|
3
|
+
from .clob import ClobClient
|
|
4
|
+
from .gamma import GammaClient
|
|
5
|
+
from .models import MarketInfo, OddsHistory, PricePoint
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"GammaClient",
|
|
9
|
+
"ClobClient",
|
|
10
|
+
"MarketInfo",
|
|
11
|
+
"PricePoint",
|
|
12
|
+
"OddsHistory",
|
|
13
|
+
]
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Polymarket CLOB API 客户端(只读)
|
|
3
|
+
|
|
4
|
+
封装赔率历史数据查询。无需认证。
|
|
5
|
+
|
|
6
|
+
用法示例:
|
|
7
|
+
from polymarket_backtest.api import GammaClient, ClobClient
|
|
8
|
+
|
|
9
|
+
gamma = GammaClient()
|
|
10
|
+
clob = ClobClient()
|
|
11
|
+
|
|
12
|
+
market = gamma.get_market_info("BTC")
|
|
13
|
+
history = clob.get_price_history(market.up_token_id, interval="1d")
|
|
14
|
+
|
|
15
|
+
for point in history.points:
|
|
16
|
+
print(point.timestamp, point.price)
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from typing import Literal
|
|
22
|
+
|
|
23
|
+
import requests
|
|
24
|
+
|
|
25
|
+
from .models import OddsHistory, PricePoint
|
|
26
|
+
|
|
27
|
+
Interval = Literal["1m", "1h", "6h", "1d", "1w", "max"]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ClobClient:
|
|
31
|
+
"""
|
|
32
|
+
Polymarket CLOB API 客户端(只读子集)。
|
|
33
|
+
|
|
34
|
+
提供赔率历史查询,无需 API 密钥。
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
BASE_URL = "https://clob.polymarket.com"
|
|
38
|
+
|
|
39
|
+
def __init__(self, base_url: str = BASE_URL, timeout: int = 15):
|
|
40
|
+
self.base_url = base_url.rstrip("/")
|
|
41
|
+
self.timeout = timeout
|
|
42
|
+
self._session = requests.Session()
|
|
43
|
+
|
|
44
|
+
# ------------------------------------------------------------------
|
|
45
|
+
# 公开接口
|
|
46
|
+
# ------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
def get_price_history(
|
|
49
|
+
self,
|
|
50
|
+
token_id: str,
|
|
51
|
+
interval: Interval | None = "1d",
|
|
52
|
+
fidelity: int = 60,
|
|
53
|
+
start_ts: int | None = None,
|
|
54
|
+
end_ts: int | None = None,
|
|
55
|
+
) -> OddsHistory:
|
|
56
|
+
"""
|
|
57
|
+
拉取某 token 的赔率历史时间序列。
|
|
58
|
+
|
|
59
|
+
参数:
|
|
60
|
+
token_id: CLOB token ID(从 GammaClient 获取)
|
|
61
|
+
interval: 时间窗口("1m","1h","6h","1d","1w","max")
|
|
62
|
+
与 start_ts/end_ts 互斥
|
|
63
|
+
fidelity: 数据分辨率(分钟),例如 60 = 每小时一个点
|
|
64
|
+
start_ts: 开始时间 Unix 时间戳(UTC)
|
|
65
|
+
end_ts: 结束时间 Unix 时间戳(UTC)
|
|
66
|
+
|
|
67
|
+
返回:
|
|
68
|
+
OddsHistory 对象,包含时间戳和对应价格列表
|
|
69
|
+
|
|
70
|
+
示例:
|
|
71
|
+
# 拉取最近 1 天数据,每小时一个点
|
|
72
|
+
history = clob.get_price_history(token_id, interval="1d", fidelity=60)
|
|
73
|
+
|
|
74
|
+
# 拉取指定时间范围
|
|
75
|
+
history = clob.get_price_history(
|
|
76
|
+
token_id,
|
|
77
|
+
start_ts=1697875200,
|
|
78
|
+
end_ts=1697961600,
|
|
79
|
+
fidelity=5,
|
|
80
|
+
)
|
|
81
|
+
"""
|
|
82
|
+
params: dict = {"market": token_id, "fidelity": fidelity}
|
|
83
|
+
|
|
84
|
+
if start_ts is not None or end_ts is not None:
|
|
85
|
+
if start_ts is not None:
|
|
86
|
+
params["startTs"] = start_ts
|
|
87
|
+
if end_ts is not None:
|
|
88
|
+
params["endTs"] = end_ts
|
|
89
|
+
elif interval is not None:
|
|
90
|
+
params["interval"] = interval
|
|
91
|
+
|
|
92
|
+
url = f"{self.base_url}/prices-history"
|
|
93
|
+
resp = self._session.get(url, params=params, timeout=self.timeout)
|
|
94
|
+
resp.raise_for_status()
|
|
95
|
+
|
|
96
|
+
data = resp.json()
|
|
97
|
+
raw_points = data.get("history", [])
|
|
98
|
+
points = [PricePoint(timestamp=int(p["t"]), price=float(p["p"])) for p in raw_points]
|
|
99
|
+
|
|
100
|
+
return OddsHistory(
|
|
101
|
+
token_id=token_id,
|
|
102
|
+
interval=interval or "custom",
|
|
103
|
+
fidelity=fidelity,
|
|
104
|
+
points=points,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
def get_price_history_df(
|
|
108
|
+
self,
|
|
109
|
+
token_id: str,
|
|
110
|
+
interval: Interval | None = "1d",
|
|
111
|
+
fidelity: int = 60,
|
|
112
|
+
start_ts: int | None = None,
|
|
113
|
+
end_ts: int | None = None,
|
|
114
|
+
):
|
|
115
|
+
"""
|
|
116
|
+
同 get_price_history,但直接返回 pandas DataFrame。
|
|
117
|
+
|
|
118
|
+
DataFrame 列:timestamp(Unix)、price、datetime(UTC)
|
|
119
|
+
"""
|
|
120
|
+
import pandas as pd
|
|
121
|
+
|
|
122
|
+
history = self.get_price_history(
|
|
123
|
+
token_id,
|
|
124
|
+
interval=interval,
|
|
125
|
+
fidelity=fidelity,
|
|
126
|
+
start_ts=start_ts,
|
|
127
|
+
end_ts=end_ts,
|
|
128
|
+
)
|
|
129
|
+
if not history.points:
|
|
130
|
+
return pd.DataFrame(columns=["timestamp", "price", "datetime"])
|
|
131
|
+
|
|
132
|
+
df = pd.DataFrame(
|
|
133
|
+
{"timestamp": history.timestamps(), "price": history.prices()}
|
|
134
|
+
)
|
|
135
|
+
df["datetime"] = pd.to_datetime(df["timestamp"], unit="s", utc=True)
|
|
136
|
+
return df
|