Skip to content

Commit cae1f3f

Browse files
committed
Add event_slug_builder support to PolymarketInstrumentProvider
1 parent d6be483 commit cae1f3f

File tree

6 files changed

+638
-9
lines changed

6 files changed

+638
-9
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#!/usr/bin/env python3
2+
# -------------------------------------------------------------------------------------------------
3+
# Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
4+
# https://nautechsystems.io
5+
#
6+
# Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
7+
# You may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
# -------------------------------------------------------------------------------------------------
16+
"""
17+
Example TradingNode script demonstrating the event_slug_builder feature.
18+
19+
This script shows how to efficiently load niche Polymarket markets using
20+
dynamically generated event slugs instead of downloading all 151k+ markets.
21+
22+
The event_slug_builder takes a fully qualified path to a callable that returns
23+
a list of event slugs. The provider fetches only those specific events from
24+
the Gamma API.
25+
26+
Usage:
27+
python examples/live/polymarket/polymarket_slug_builder_tester.py
28+
29+
Environment variables required (set these before running):
30+
export POLYMARKET_PK="your_private_key"
31+
export POLYMARKET_API_KEY="your_api_key"
32+
export POLYMARKET_API_SECRET="your_api_secret"
33+
export POLYMARKET_PASSPHRASE="your_passphrase"
34+
35+
To get Polymarket API credentials:
36+
1. Go to https://polymarket.com and connect your wallet
37+
2. Navigate to Settings -> API Keys
38+
3. Create new API credentials
39+
40+
"""
41+
42+
from nautilus_trader.adapters.polymarket import POLYMARKET
43+
from nautilus_trader.adapters.polymarket import PolymarketDataClientConfig
44+
from nautilus_trader.adapters.polymarket import PolymarketLiveDataClientFactory
45+
from nautilus_trader.adapters.polymarket.providers import PolymarketInstrumentProviderConfig
46+
from nautilus_trader.config import LiveExecEngineConfig
47+
from nautilus_trader.config import LoggingConfig
48+
from nautilus_trader.config import TradingNodeConfig
49+
from nautilus_trader.live.node import TradingNode
50+
from nautilus_trader.model.identifiers import TraderId
51+
52+
53+
# Configure the instrument provider with event_slug_builder
54+
# NOTE: load_all=True is required to trigger the provider's load_all_async() method,
55+
# but event_slug_builder takes priority and only loads the specific events.
56+
instrument_config = PolymarketInstrumentProviderConfig(
57+
load_all=True, # Required to trigger loading
58+
event_slug_builder="examples.live.polymarket.slug_builders:build_btc_updown_slugs",
59+
)
60+
61+
# Alternative slug builders you can try:
62+
# - "examples.live.polymarket.slug_builders:build_eth_updown_slugs" # ETH 15-min UpDown
63+
# - "examples.live.polymarket.slug_builders:build_crypto_updown_slugs" # BTC, ETH, SOL
64+
# - "examples.live.polymarket.slug_builders:build_sample_slugs" # Static sample slugs
65+
66+
# Configure the trading node
67+
config_node = TradingNodeConfig(
68+
trader_id=TraderId("SLUG-BUILDER-001"),
69+
logging=LoggingConfig(log_level="INFO", use_pyo3=True),
70+
exec_engine=LiveExecEngineConfig(
71+
reconciliation=False, # Not applicable for data-only
72+
),
73+
data_clients={
74+
POLYMARKET: PolymarketDataClientConfig(
75+
private_key=None, # 'POLYMARKET_PK' env var
76+
api_key=None, # 'POLYMARKET_API_KEY' env var
77+
api_secret=None, # 'POLYMARKET_API_SECRET' env var
78+
passphrase=None, # 'POLYMARKET_PASSPHRASE' env var
79+
instrument_config=instrument_config,
80+
compute_effective_deltas=True,
81+
update_instruments_interval_mins=15, # Refresh every 15 mins for UpDown markets
82+
),
83+
},
84+
timeout_connection=30.0,
85+
timeout_disconnection=10.0,
86+
timeout_post_stop=1.0,
87+
)
88+
89+
# Instantiate the node with a configuration
90+
node = TradingNode(config=config_node)
91+
92+
# Register your client factories with the node
93+
node.add_data_client_factory(POLYMARKET, PolymarketLiveDataClientFactory)
94+
node.build()
95+
96+
97+
# Stop and dispose of the node with SIGINT/CTRL+C
98+
if __name__ == "__main__":
99+
try:
100+
node.run()
101+
finally:
102+
node.dispose()
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#!/usr/bin/env python3
2+
# -------------------------------------------------------------------------------------------------
3+
# Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
4+
# https://nautechsystems.io
5+
#
6+
# Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
7+
# You may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
# -------------------------------------------------------------------------------------------------
16+
"""
17+
Example slug builder functions for Polymarket event_slug_builder feature.
18+
19+
These functions dynamically generate event slugs for niche markets with
20+
predictable naming patterns, allowing efficient loading without downloading
21+
all 151k+ markets.
22+
23+
Usage:
24+
In your PolymarketInstrumentProviderConfig:
25+
```python
26+
instrument_config = PolymarketInstrumentProviderConfig(
27+
load_all=True,
28+
event_slug_builder="examples.live.polymarket.slug_builders:build_btc_updown_slugs",
29+
)
30+
```
31+
32+
"""
33+
34+
from datetime import UTC
35+
from datetime import datetime
36+
from datetime import timedelta
37+
38+
39+
def build_btc_updown_slugs() -> list[str]:
40+
"""
41+
Build slugs for BTC 15-minute UpDown markets for the next few hours.
42+
43+
UpDown markets follow the pattern: btc-updown-15m-{unix_timestamp}
44+
Where timestamp is the START of the 15-minute window.
45+
46+
Returns
47+
-------
48+
list[str]
49+
List of event slugs for BTC UpDown markets.
50+
51+
"""
52+
slugs = []
53+
now = datetime.now(tz=UTC)
54+
55+
# Round down to nearest 15-minute interval
56+
minutes = (now.minute // 15) * 15
57+
base_time = now.replace(minute=minutes, second=0, microsecond=0)
58+
59+
# Generate slugs for the next 8 intervals (2 hours)
60+
for i in range(8):
61+
interval_time = base_time + timedelta(minutes=15 * i)
62+
timestamp = int(interval_time.timestamp())
63+
slug = f"btc-updown-15m-{timestamp}"
64+
slugs.append(slug)
65+
66+
return slugs
67+
68+
69+
def build_eth_updown_slugs() -> list[str]:
70+
"""
71+
Build slugs for ETH 15-minute UpDown markets for the next few hours.
72+
73+
Returns
74+
-------
75+
list[str]
76+
List of event slugs for ETH UpDown markets.
77+
78+
"""
79+
slugs = []
80+
now = datetime.now(tz=UTC)
81+
82+
# Round down to nearest 15-minute interval
83+
minutes = (now.minute // 15) * 15
84+
base_time = now.replace(minute=minutes, second=0, microsecond=0)
85+
86+
# Generate slugs for the next 8 intervals (2 hours)
87+
for i in range(8):
88+
interval_time = base_time + timedelta(minutes=15 * i)
89+
timestamp = int(interval_time.timestamp())
90+
slug = f"eth-updown-15m-{timestamp}"
91+
slugs.append(slug)
92+
93+
return slugs
94+
95+
96+
def build_crypto_updown_slugs() -> list[str]:
97+
"""
98+
Build slugs for multiple crypto 15-minute UpDown markets (BTC, ETH, SOL).
99+
100+
Returns
101+
-------
102+
list[str]
103+
List of event slugs for crypto UpDown markets.
104+
105+
"""
106+
cryptos = ["btc", "eth", "sol"]
107+
slugs = []
108+
now = datetime.now(tz=UTC)
109+
110+
# Round down to nearest 15-minute interval
111+
minutes = (now.minute // 15) * 15
112+
base_time = now.replace(minute=minutes, second=0, microsecond=0)
113+
114+
# Generate slugs for the next 4 intervals (1 hour) per crypto
115+
for i in range(4):
116+
interval_time = base_time + timedelta(minutes=15 * i)
117+
timestamp = int(interval_time.timestamp())
118+
for crypto in cryptos:
119+
slug = f"{crypto}-updown-15m-{timestamp}"
120+
slugs.append(slug)
121+
122+
return slugs
123+
124+
125+
def build_sample_slugs() -> list[str]:
126+
"""
127+
Build a list of sample slugs for testing.
128+
129+
Returns known active event slugs from Polymarket.
130+
131+
Returns
132+
-------
133+
list[str]
134+
List of sample event slugs.
135+
136+
"""
137+
return [
138+
"presidential-election-winner-2024",
139+
]

nautilus_trader/adapters/polymarket/config.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
# -------------------------------------------------------------------------------------------------
1515

1616
from nautilus_trader.adapters.polymarket.common.constants import POLYMARKET_VENUE
17+
from nautilus_trader.adapters.polymarket.providers import PolymarketInstrumentProviderConfig
1718
from nautilus_trader.config import LiveDataClientConfig
1819
from nautilus_trader.config import LiveExecClientConfig
1920
from nautilus_trader.config import PositiveFloat
@@ -27,6 +28,8 @@ class PolymarketDataClientConfig(LiveDataClientConfig, frozen=True):
2728
2829
Parameters
2930
----------
31+
instrument_config : PolymarketInstrumentProviderConfig, optional
32+
The Polymarket instrument provider config.
3033
venue : Venue, default POLYMARKET_VENUE
3134
The venue for the client.
3235
private_key : str, optional
@@ -70,6 +73,7 @@ class PolymarketDataClientConfig(LiveDataClientConfig, frozen=True):
7073
7174
"""
7275

76+
instrument_config: PolymarketInstrumentProviderConfig | None = None
7377
venue: Venue = POLYMARKET_VENUE
7478
private_key: str | None = None
7579
signature_type: int = 0
@@ -93,6 +97,8 @@ class PolymarketExecClientConfig(LiveExecClientConfig, frozen=True):
9397
9498
Parameters
9599
----------
100+
instrument_config : PolymarketInstrumentProviderConfig, optional
101+
The Polymarket instrument provider config.
96102
venue : Venue, default POLYMARKET_VENUE
97103
The venue for the client.
98104
private_key : str, optional
@@ -143,6 +149,7 @@ class PolymarketExecClientConfig(LiveExecClientConfig, frozen=True):
143149
144150
"""
145151

152+
instrument_config: PolymarketInstrumentProviderConfig | None = None
146153
venue: Venue = POLYMARKET_VENUE
147154
private_key: str | None = None
148155
signature_type: int = 0

nautilus_trader/adapters/polymarket/factories.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@
3131
from nautilus_trader.adapters.polymarket.data import PolymarketDataClient
3232
from nautilus_trader.adapters.polymarket.execution import PolymarketExecutionClient
3333
from nautilus_trader.adapters.polymarket.providers import PolymarketInstrumentProvider
34+
from nautilus_trader.adapters.polymarket.providers import PolymarketInstrumentProviderConfig
3435
from nautilus_trader.cache.cache import Cache
3536
from nautilus_trader.common.component import LiveClock
3637
from nautilus_trader.common.component import MessageBus
37-
from nautilus_trader.common.config import InstrumentProviderConfig
3838
from nautilus_trader.live.factories import LiveDataClientFactory
3939
from nautilus_trader.live.factories import LiveExecClientFactory
4040

@@ -100,7 +100,7 @@ def get_polymarket_http_client(
100100
def get_polymarket_instrument_provider(
101101
client: ClobClient,
102102
clock: LiveClock,
103-
config: InstrumentProviderConfig,
103+
config: PolymarketInstrumentProviderConfig | None,
104104
) -> PolymarketInstrumentProvider:
105105
"""
106106
Cache and return a Polymarket instrument provider.
@@ -113,7 +113,7 @@ def get_polymarket_instrument_provider(
113113
The client for the instrument provider.
114114
clock : LiveClock
115115
The clock for the instrument provider.
116-
config : InstrumentProviderConfig
116+
config : PolymarketInstrumentProviderConfig, optional
117117
The configuration for the instrument provider.
118118
119119
Returns
@@ -177,7 +177,7 @@ def create( # type: ignore
177177
provider = get_polymarket_instrument_provider(
178178
client=http_client,
179179
clock=clock,
180-
config=config.instrument_provider,
180+
config=config.instrument_config,
181181
)
182182
return PolymarketDataClient(
183183
loop=loop,
@@ -245,7 +245,7 @@ def create( # type: ignore
245245
provider = get_polymarket_instrument_provider(
246246
client=http_client,
247247
clock=clock,
248-
config=config.instrument_provider,
248+
config=config.instrument_config,
249249
)
250250
return PolymarketExecutionClient(
251251
loop=loop,

0 commit comments

Comments
 (0)