xu-agent-sdk 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,47 @@
1
+ """
2
+ xu-agent-sdk: Python SDK for 1xu Trading Signals
3
+ =================================================
4
+ Connect your autonomous agent to 1xu's whale intelligence signals.
5
+
6
+ Installation:
7
+ pip install xu-agent-sdk
8
+
9
+ Quick Start:
10
+ from xu_agent_sdk import XuAgent
11
+
12
+ agent = XuAgent(api_key="1xu_your_key_here")
13
+
14
+ # Get signals
15
+ signals = await agent.get_signals(limit=10)
16
+
17
+ # Report trade
18
+ await agent.report_trade(
19
+ signal_id=signals[0]['id'],
20
+ market_id=signals[0]['market_id'],
21
+ direction='yes',
22
+ size_usd=100,
23
+ entry_price=0.65
24
+ )
25
+
26
+ Documentation: https://1xu.app/docs/sdk
27
+ """
28
+
29
+ __version__ = "0.1.0"
30
+ __author__ = "1xu Team"
31
+
32
+ from .client import XuAgent, XuSignal
33
+ from .exceptions import (
34
+ XuError,
35
+ XuAuthError,
36
+ XuRateLimitError,
37
+ XuPaymentRequiredError,
38
+ )
39
+
40
+ __all__ = [
41
+ "XuAgent",
42
+ "XuSignal",
43
+ "XuError",
44
+ "XuAuthError",
45
+ "XuRateLimitError",
46
+ "XuPaymentRequiredError",
47
+ ]
xu_agent_sdk/client.py ADDED
@@ -0,0 +1,593 @@
1
+ """
2
+ xu-agent-sdk Client
3
+ ===================
4
+ Main client for interacting with 1xu Trading Signals API.
5
+ """
6
+
7
+ import asyncio
8
+ import aiohttp
9
+ import logging
10
+ from datetime import datetime, timezone
11
+ from typing import Optional, Dict, Any, List, Callable, Awaitable
12
+ from dataclasses import dataclass
13
+ from enum import Enum
14
+
15
+ from .exceptions import (
16
+ XuError,
17
+ XuAuthError,
18
+ XuRateLimitError,
19
+ XuPaymentRequiredError,
20
+ XuSignalLimitError,
21
+ XuConnectionError,
22
+ XuValidationError,
23
+ )
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+
28
+ # =============================================================================
29
+ # Data Models
30
+ # =============================================================================
31
+
32
+ @dataclass
33
+ class XuSignal:
34
+ """Represents a trading signal from 1xu"""
35
+ id: str
36
+ market_id: str
37
+ market: str # Human readable market name
38
+ direction: str # 'yes' or 'no'
39
+ confidence: float # 0-1
40
+ entry_price: float
41
+ suggested_size: str # e.g., "$50-100"
42
+ whale_score: float
43
+ timestamp: datetime
44
+ expires_at: Optional[datetime] = None
45
+
46
+ # Additional context
47
+ whale_activity: Optional[Dict] = None
48
+ market_stats: Optional[Dict] = None
49
+
50
+ @classmethod
51
+ def from_dict(cls, data: Dict) -> 'XuSignal':
52
+ return cls(
53
+ id=data.get('id', data.get('_id', data.get('signal_id', ''))),
54
+ market_id=data.get('market_id', data.get('condition_id', '')),
55
+ market=data.get('market', data.get('question', '')),
56
+ direction=data.get('direction', data.get('action', 'yes')),
57
+ confidence=float(data.get('confidence', data.get('whale_score', 0.5))),
58
+ entry_price=float(data.get('entry_price', data.get('price', 0))),
59
+ suggested_size=data.get('suggested_size', '$50-100'),
60
+ whale_score=float(data.get('whale_score', 0.5)),
61
+ timestamp=datetime.fromisoformat(data['timestamp'].replace('Z', '+00:00')) if data.get('timestamp') else datetime.now(timezone.utc),
62
+ expires_at=datetime.fromisoformat(data['expires_at'].replace('Z', '+00:00')) if data.get('expires_at') else None,
63
+ whale_activity=data.get('whale_activity'),
64
+ market_stats=data.get('market_stats')
65
+ )
66
+
67
+ def to_dict(self) -> Dict:
68
+ return {
69
+ 'id': self.id,
70
+ 'market_id': self.market_id,
71
+ 'market': self.market,
72
+ 'direction': self.direction,
73
+ 'confidence': self.confidence,
74
+ 'entry_price': self.entry_price,
75
+ 'suggested_size': self.suggested_size,
76
+ 'whale_score': self.whale_score,
77
+ 'timestamp': self.timestamp.isoformat(),
78
+ 'expires_at': self.expires_at.isoformat() if self.expires_at else None
79
+ }
80
+
81
+
82
+ class TradeStatus(Enum):
83
+ SKIPPED = 'skipped'
84
+ EXECUTED = 'executed'
85
+ FAILED = 'failed'
86
+ CLOSED = 'closed'
87
+
88
+
89
+ # =============================================================================
90
+ # Main Client
91
+ # =============================================================================
92
+
93
+ class XuAgent:
94
+ """
95
+ Client for 1xu Trading Signals API.
96
+
97
+ Example:
98
+ agent = XuAgent(api_key="1xu_your_key")
99
+
100
+ # Get latest signals
101
+ signals = await agent.get_signals(limit=10)
102
+
103
+ # Stream signals in real-time
104
+ async for signal in agent.stream_signals():
105
+ print(f"New signal: {signal.market} -> {signal.direction}")
106
+ """
107
+
108
+ BASE_URL = "https://1xu.app"
109
+
110
+ def __init__(
111
+ self,
112
+ api_key: str,
113
+ base_url: str = None,
114
+ timeout: int = 30,
115
+ auto_ack: bool = True,
116
+ ):
117
+ """
118
+ Initialize the 1xu Agent client.
119
+
120
+ Args:
121
+ api_key: Your 1xu API key (get one at https://1xu.app/agent-dashboard)
122
+ base_url: Override the base URL (for testing)
123
+ timeout: Request timeout in seconds
124
+ auto_ack: Automatically acknowledge signals when received
125
+ """
126
+ if not api_key or not api_key.startswith('1xu_'):
127
+ raise XuValidationError("Invalid API key format. Expected '1xu_...'")
128
+
129
+ self.api_key = api_key
130
+ self.base_url = (base_url or self.BASE_URL).rstrip('/')
131
+ self.timeout = timeout
132
+ self.auto_ack = auto_ack
133
+
134
+ self._session: Optional[aiohttp.ClientSession] = None
135
+ self._agent_id: Optional[str] = None
136
+ self._tier: Optional[str] = None
137
+
138
+ # Callbacks
139
+ self._on_signal: Optional[Callable[[XuSignal], Awaitable[None]]] = None
140
+ self._on_error: Optional[Callable[[Exception], Awaitable[None]]] = None
141
+
142
+ async def _get_session(self) -> aiohttp.ClientSession:
143
+ """Get or create HTTP session"""
144
+ if self._session is None or self._session.closed:
145
+ self._session = aiohttp.ClientSession(
146
+ timeout=aiohttp.ClientTimeout(total=self.timeout),
147
+ headers={
148
+ 'X-API-Key': self.api_key,
149
+ 'User-Agent': f'xu-agent-sdk/0.1.0',
150
+ 'Content-Type': 'application/json'
151
+ }
152
+ )
153
+ return self._session
154
+
155
+ async def close(self):
156
+ """Close the client session"""
157
+ if self._session and not self._session.closed:
158
+ await self._session.close()
159
+
160
+ async def __aenter__(self):
161
+ return self
162
+
163
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
164
+ await self.close()
165
+
166
+ # ============ CORE API METHODS ============
167
+
168
+ async def _request(self, method: str, endpoint: str,
169
+ data: Dict = None, params: Dict = None) -> Dict:
170
+ """Make an API request"""
171
+ session = await self._get_session()
172
+ url = f"{self.base_url}{endpoint}"
173
+
174
+ try:
175
+ async with session.request(method, url, json=data, params=params) as resp:
176
+ result = await resp.json()
177
+
178
+ # Handle errors
179
+ if resp.status == 401:
180
+ raise XuAuthError(
181
+ result.get('error', 'Authentication failed'),
182
+ status_code=401,
183
+ response=result
184
+ )
185
+ elif resp.status == 402:
186
+ raise XuPaymentRequiredError(
187
+ result.get('error', 'Payment required'),
188
+ pricing=result.get('pricing'),
189
+ status_code=402,
190
+ response=result
191
+ )
192
+ elif resp.status == 429:
193
+ raise XuRateLimitError(
194
+ result.get('error', 'Rate limit exceeded'),
195
+ retry_after=int(result.get('retry_after', 60)),
196
+ status_code=429,
197
+ response=result
198
+ )
199
+ elif resp.status >= 400:
200
+ # Check if it's a daily limit error
201
+ if 'limit' in result.get('error', '').lower():
202
+ raise XuSignalLimitError(
203
+ result.get('error'),
204
+ resets_in_seconds=result.get('resets_in_seconds', 0),
205
+ status_code=resp.status,
206
+ response=result
207
+ )
208
+ raise XuError(
209
+ result.get('error', f'Request failed with status {resp.status}'),
210
+ status_code=resp.status,
211
+ response=result
212
+ )
213
+
214
+ return result
215
+
216
+ except aiohttp.ClientError as e:
217
+ raise XuConnectionError(f"Connection error: {e}")
218
+
219
+ # ============ AUTHENTICATION ============
220
+
221
+ async def verify_connection(self) -> Dict:
222
+ """
223
+ Verify API key and get account information.
224
+
225
+ Returns:
226
+ Dict with wallet, tier, features, and limits
227
+ """
228
+ result = await self._request('GET', '/api/a2a/access', params={'api_key': self.api_key})
229
+
230
+ self._agent_id = result.get('wallet')
231
+ self._tier = result.get('tier')
232
+
233
+ return result
234
+
235
+ async def refresh_balance(self) -> Dict:
236
+ """
237
+ Refresh token balance and update tier if changed.
238
+
239
+ Returns:
240
+ Dict with updated tier information
241
+ """
242
+ return await self._request('POST', '/api/a2a/refresh-balance', params={'api_key': self.api_key})
243
+
244
+ @property
245
+ def agent_id(self) -> Optional[str]:
246
+ """Get the agent ID (wallet address)"""
247
+ return self._agent_id
248
+
249
+ @property
250
+ def tier(self) -> Optional[str]:
251
+ """Get the current tier"""
252
+ return self._tier
253
+
254
+ # ============ SIGNALS ============
255
+
256
+ async def get_signals(
257
+ self,
258
+ limit: int = 10,
259
+ min_confidence: float = 0.5,
260
+ direction: str = None,
261
+ ) -> List[XuSignal]:
262
+ """
263
+ Get latest trading signals.
264
+
265
+ Args:
266
+ limit: Maximum number of signals to return
267
+ min_confidence: Minimum confidence score (0-1)
268
+ direction: Filter by direction ('yes' or 'no')
269
+
270
+ Returns:
271
+ List of XuSignal objects
272
+ """
273
+ params = {
274
+ 'api_key': self.api_key,
275
+ 'limit': limit,
276
+ 'min_confidence': min_confidence,
277
+ }
278
+ if direction:
279
+ params['direction'] = direction
280
+
281
+ result = await self._request('GET', '/api/v1/signals', params=params)
282
+
283
+ signals = []
284
+ for s in result.get('signals', []):
285
+ signal = XuSignal.from_dict(s)
286
+ signals.append(signal)
287
+
288
+ # Auto acknowledge
289
+ if self.auto_ack and self._agent_id:
290
+ try:
291
+ await self.acknowledge_signal(signal.id, s.get('broadcast_time'))
292
+ except Exception as e:
293
+ logger.warning(f"Failed to ack signal {signal.id}: {e}")
294
+
295
+ return signals
296
+
297
+ async def get_trial_signals(self) -> List[XuSignal]:
298
+ """
299
+ Get free trial signals (limited, delayed).
300
+
301
+ Returns:
302
+ List of XuSignal objects
303
+ """
304
+ result = await self._request('GET', '/api/v1/signals/trial')
305
+ return [XuSignal.from_dict(s) for s in result.get('signals', [])]
306
+
307
+ async def stream_signals(
308
+ self,
309
+ callback: Callable[[XuSignal], Awaitable[None]] = None,
310
+ min_confidence: float = 0.5,
311
+ ):
312
+ """
313
+ Stream signals in real-time (for Pro+ tiers with webhooks).
314
+
315
+ This is a long-polling implementation. For true real-time,
316
+ register a webhook endpoint.
317
+
318
+ Args:
319
+ callback: Async function to call for each signal
320
+ min_confidence: Minimum confidence filter
321
+
322
+ Yields:
323
+ XuSignal objects as they arrive
324
+ """
325
+ last_signal_id = None
326
+
327
+ while True:
328
+ try:
329
+ signals = await self.get_signals(limit=5, min_confidence=min_confidence)
330
+
331
+ for signal in signals:
332
+ if last_signal_id and signal.id == last_signal_id:
333
+ break
334
+
335
+ if callback:
336
+ await callback(signal)
337
+ else:
338
+ yield signal
339
+
340
+ if signals:
341
+ last_signal_id = signals[0].id
342
+
343
+ await asyncio.sleep(10) # Poll every 10 seconds
344
+
345
+ except XuRateLimitError as e:
346
+ await asyncio.sleep(e.retry_after)
347
+ except Exception as e:
348
+ if self._on_error:
349
+ await self._on_error(e)
350
+ else:
351
+ logger.error(f"Stream error: {e}")
352
+ await asyncio.sleep(30)
353
+
354
+ # ============ TRADE REPORTING ============
355
+
356
+ async def acknowledge_signal(
357
+ self,
358
+ signal_id: str,
359
+ broadcast_time: str = None
360
+ ) -> Dict:
361
+ """
362
+ Acknowledge receipt of a signal.
363
+
364
+ Args:
365
+ signal_id: The signal ID
366
+ broadcast_time: When the signal was broadcast (ISO format)
367
+
368
+ Returns:
369
+ Dict with latency information
370
+ """
371
+ return await self._request('POST', '/api/a2a/report/ack', data={
372
+ 'agent_id': self._agent_id or self.api_key,
373
+ 'signal_id': signal_id,
374
+ 'broadcast_time': broadcast_time
375
+ })
376
+
377
+ async def report_skip(
378
+ self,
379
+ signal_id: str,
380
+ reason: str,
381
+ market_id: str = None
382
+ ) -> Dict:
383
+ """
384
+ Report that a signal was intentionally skipped.
385
+
386
+ Args:
387
+ signal_id: The signal ID
388
+ reason: Why you skipped (e.g., "below_threshold", "no_liquidity")
389
+ market_id: The market ID (optional)
390
+
391
+ Returns:
392
+ Dict with success status
393
+ """
394
+ return await self._request('POST', '/api/a2a/report/skip', data={
395
+ 'agent_id': self._agent_id or self.api_key,
396
+ 'signal_id': signal_id,
397
+ 'reason': reason,
398
+ 'market_id': market_id
399
+ })
400
+
401
+ async def report_failure(
402
+ self,
403
+ signal_id: str,
404
+ reason: str,
405
+ market_id: str = None
406
+ ) -> Dict:
407
+ """
408
+ Report that trade execution failed.
409
+
410
+ Args:
411
+ signal_id: The signal ID
412
+ reason: Failure reason (e.g., "insufficient_funds", "slippage")
413
+ market_id: The market ID (optional)
414
+
415
+ Returns:
416
+ Dict with success status
417
+ """
418
+ return await self._request('POST', '/api/a2a/report/failure', data={
419
+ 'agent_id': self._agent_id or self.api_key,
420
+ 'signal_id': signal_id,
421
+ 'reason': reason,
422
+ 'market_id': market_id
423
+ })
424
+
425
+ async def report_trade(
426
+ self,
427
+ signal_id: str,
428
+ market_id: str,
429
+ direction: str,
430
+ size_usd: float,
431
+ entry_price: float,
432
+ tx_hash: str = None,
433
+ executed_at: datetime = None
434
+ ) -> Dict:
435
+ """
436
+ Report a successful trade execution.
437
+
438
+ Args:
439
+ signal_id: The signal ID that triggered this trade
440
+ market_id: The Polymarket condition ID
441
+ direction: 'yes' or 'no'
442
+ size_usd: Position size in USD
443
+ entry_price: Entry price (0-1)
444
+ tx_hash: Transaction hash for on-chain verification (optional)
445
+ executed_at: Execution timestamp (optional)
446
+
447
+ Returns:
448
+ Dict with trade_id and verification status
449
+ """
450
+ data = {
451
+ 'agent_id': self._agent_id or self.api_key,
452
+ 'signal_id': signal_id,
453
+ 'market_id': market_id,
454
+ 'direction': direction,
455
+ 'size_usd': size_usd,
456
+ 'entry_price': entry_price,
457
+ }
458
+
459
+ if tx_hash:
460
+ data['tx_hash'] = tx_hash
461
+ if executed_at:
462
+ data['executed_at'] = executed_at.isoformat()
463
+
464
+ return await self._request('POST', '/api/a2a/report/trade', data=data)
465
+
466
+ async def report_close(
467
+ self,
468
+ trade_id: str,
469
+ exit_price: float,
470
+ pnl_usd: float,
471
+ tx_hash: str = None
472
+ ) -> Dict:
473
+ """
474
+ Report closing a position.
475
+
476
+ Args:
477
+ trade_id: The trade ID from report_trade response
478
+ exit_price: Exit price (0-1)
479
+ pnl_usd: Realized profit/loss in USD
480
+ tx_hash: Close transaction hash (optional)
481
+
482
+ Returns:
483
+ Dict with success status and is_winner flag
484
+ """
485
+ return await self._request('POST', '/api/a2a/report/close', data={
486
+ 'agent_id': self._agent_id or self.api_key,
487
+ 'trade_id': trade_id,
488
+ 'exit_price': exit_price,
489
+ 'pnl_usd': pnl_usd,
490
+ 'tx_hash': tx_hash
491
+ })
492
+
493
+ # ============ STATS ============
494
+
495
+ async def get_my_stats(self) -> Dict:
496
+ """
497
+ Get your agent's performance statistics.
498
+
499
+ Returns:
500
+ Dict with win_rate, total_pnl, trade counts, etc.
501
+ """
502
+ agent_id = self._agent_id or self.api_key
503
+ return await self._request('GET', f'/api/a2a/stats/{agent_id}')
504
+
505
+ async def get_my_trades(self, limit: int = 50, status: str = None) -> List[Dict]:
506
+ """
507
+ Get your trade history.
508
+
509
+ Args:
510
+ limit: Maximum number of trades
511
+ status: Filter by status ('executed', 'closed', 'skipped', 'failed')
512
+
513
+ Returns:
514
+ List of trade records
515
+ """
516
+ agent_id = self._agent_id or self.api_key
517
+ params = {'limit': limit}
518
+ if status:
519
+ params['status'] = status
520
+
521
+ result = await self._request('GET', f'/api/a2a/trades/{agent_id}', params=params)
522
+ return result.get('trades', [])
523
+
524
+ async def get_leaderboard(self, metric: str = 'total_pnl_usd', limit: int = 20) -> List[Dict]:
525
+ """
526
+ Get the agent leaderboard.
527
+
528
+ Args:
529
+ metric: Ranking metric ('total_pnl_usd', 'win_rate', 'verification_rate')
530
+ limit: Number of entries
531
+
532
+ Returns:
533
+ List of leaderboard entries with rank
534
+ """
535
+ result = await self._request('GET', '/api/a2a/leaderboard', params={
536
+ 'metric': metric,
537
+ 'limit': limit
538
+ })
539
+ return result.get('leaderboard', [])
540
+
541
+ # ============ USAGE ============
542
+
543
+ async def get_usage(self) -> Dict:
544
+ """
545
+ Get current API usage and limits.
546
+
547
+ Returns:
548
+ Dict with signals_used, remaining, rate_limits, etc.
549
+ """
550
+ return await self._request('GET', '/api/v1/usage', params={'api_key': self.api_key})
551
+
552
+ async def get_pricing(self) -> Dict:
553
+ """
554
+ Get current pricing tiers and token requirements.
555
+
556
+ Returns:
557
+ Dict with tiers, thresholds, and beta information
558
+ """
559
+ return await self._request('GET', '/api/a2a/tiers')
560
+
561
+ # ============ WEBHOOKS ============
562
+
563
+ async def register_webhook(self, url: str) -> Dict:
564
+ """
565
+ Register a webhook URL for real-time signal delivery.
566
+
567
+ Args:
568
+ url: Your webhook endpoint URL
569
+
570
+ Returns:
571
+ Dict with success status
572
+ """
573
+ return await self._request('POST', '/api/v1/webhook', data={
574
+ 'api_key': self.api_key,
575
+ 'url': url
576
+ })
577
+
578
+
579
+ # =============================================================================
580
+ # Convenience Functions
581
+ # =============================================================================
582
+
583
+ async def quick_start(api_key: str) -> XuAgent:
584
+ """
585
+ Quick start helper - creates and verifies an agent.
586
+
587
+ Example:
588
+ agent = await quick_start("1xu_your_key")
589
+ signals = await agent.get_signals()
590
+ """
591
+ agent = XuAgent(api_key)
592
+ await agent.verify_connection()
593
+ return agent
@@ -0,0 +1,48 @@
1
+ """
2
+ xu-agent-sdk Exceptions
3
+ """
4
+
5
+
6
+ class XuError(Exception):
7
+ """Base exception for xu-agent-sdk"""
8
+ def __init__(self, message: str, status_code: int = None, response: dict = None):
9
+ super().__init__(message)
10
+ self.message = message
11
+ self.status_code = status_code
12
+ self.response = response or {}
13
+
14
+
15
+ class XuAuthError(XuError):
16
+ """Authentication failed - invalid or missing API key"""
17
+ pass
18
+
19
+
20
+ class XuRateLimitError(XuError):
21
+ """Rate limit exceeded - too many requests"""
22
+ def __init__(self, message: str, retry_after: int = 60, **kwargs):
23
+ super().__init__(message, **kwargs)
24
+ self.retry_after = retry_after
25
+
26
+
27
+ class XuPaymentRequiredError(XuError):
28
+ """Payment required - need to upgrade tier or add funds"""
29
+ def __init__(self, message: str, pricing: dict = None, **kwargs):
30
+ super().__init__(message, **kwargs)
31
+ self.pricing = pricing or {}
32
+
33
+
34
+ class XuSignalLimitError(XuError):
35
+ """Daily signal limit exceeded"""
36
+ def __init__(self, message: str, resets_in_seconds: int = 0, **kwargs):
37
+ super().__init__(message, **kwargs)
38
+ self.resets_in_seconds = resets_in_seconds
39
+
40
+
41
+ class XuConnectionError(XuError):
42
+ """Network connection error"""
43
+ pass
44
+
45
+
46
+ class XuValidationError(XuError):
47
+ """Invalid input parameters"""
48
+ pass
@@ -0,0 +1,231 @@
1
+ Metadata-Version: 2.4
2
+ Name: xu-agent-sdk
3
+ Version: 0.1.0
4
+ Summary: Python SDK for 1xu Trading Signals - Connect your autonomous agent to whale intelligence
5
+ Author-email: 1xu Team <dev@1xu.app>
6
+ License: MIT
7
+ Project-URL: Homepage, https://1xu.app
8
+ Project-URL: Documentation, https://1xu.app/docs/sdk
9
+ Project-URL: Repository, https://github.com/1xu-project/xu-agent-sdk
10
+ Project-URL: Changelog, https://github.com/1xu-project/xu-agent-sdk/releases
11
+ Keywords: trading,polymarket,signals,crypto,autonomous-agent,whale-tracking
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Office/Business :: Financial :: Investment
21
+ Classifier: Framework :: AsyncIO
22
+ Requires-Python: >=3.9
23
+ Description-Content-Type: text/markdown
24
+ Requires-Dist: aiohttp>=3.8.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=7.0; extra == "dev"
27
+ Requires-Dist: pytest-asyncio>=0.20; extra == "dev"
28
+ Requires-Dist: black; extra == "dev"
29
+ Requires-Dist: mypy; extra == "dev"
30
+
31
+ # xu-agent-sdk
32
+
33
+ Python SDK for connecting autonomous trading agents to 1xu's whale intelligence signals.
34
+
35
+ ## Features
36
+
37
+ - 🐋 **Whale Intelligence** - Access signals from tracking 500+ whale wallets
38
+ - ⚡ **Real-time Delivery** - Get signals as they happen (Pro+ tiers)
39
+ - 📊 **Performance Tracking** - Report trades and track your P&L
40
+ - 🏆 **Leaderboard** - Compete with other agents
41
+ - ✅ **On-chain Verification** - Prove your trades on-chain
42
+
43
+ ## Installation
44
+
45
+ ```bash
46
+ pip install xu-agent-sdk
47
+ ```
48
+
49
+ ## Quick Start
50
+
51
+ ```python
52
+ import asyncio
53
+ from xu_agent_sdk import XuAgent
54
+
55
+ async def main():
56
+ # Initialize with your API key
57
+ agent = XuAgent(api_key="1xu_your_api_key_here")
58
+
59
+ # Verify connection and get tier info
60
+ info = await agent.verify_connection()
61
+ print(f"Connected! Tier: {info['tier']}")
62
+
63
+ # Get latest signals
64
+ signals = await agent.get_signals(limit=5, min_confidence=0.6)
65
+
66
+ for signal in signals:
67
+ print(f"Signal: {signal.market}")
68
+ print(f" Direction: {signal.direction}")
69
+ print(f" Confidence: {signal.confidence:.1%}")
70
+ print(f" Entry: {signal.entry_price:.3f}")
71
+ print()
72
+
73
+ await agent.close()
74
+
75
+ asyncio.run(main())
76
+ ```
77
+
78
+ ## Getting an API Key
79
+
80
+ 1. **With $1XU tokens**: Hold tokens and verify at https://1xu.app/agent-dashboard
81
+ 2. **With USDC**: Pay via our x402 payment endpoint
82
+ 3. **Free trial**: Get 10 signals/day with delayed delivery
83
+
84
+ ### Token Holder Tiers
85
+
86
+ | Tier | Tokens | Signals/Day | Delay | Webhooks |
87
+ |------|--------|-------------|-------|----------|
88
+ | Diamond | 10M+ | Unlimited | 0s | ✅ |
89
+ | Gold | 1M+ | Unlimited | 0s | ✅ |
90
+ | Silver | 100K+ | 500 | 30s | ✅ |
91
+ | Bronze | 10K+ | 100 | 60s | ❌ |
92
+ | Free | 0 | 10 | 5min | ❌ |
93
+
94
+ **🎉 Beta Special**: Any token holder gets Gold-tier access FREE for 30 days!
95
+
96
+ ## Usage Examples
97
+
98
+ ### Get Signals
99
+
100
+ ```python
101
+ # Get latest signals
102
+ signals = await agent.get_signals(limit=10)
103
+
104
+ # Filter by confidence
105
+ signals = await agent.get_signals(min_confidence=0.7)
106
+
107
+ # Filter by direction
108
+ signals = await agent.get_signals(direction='yes')
109
+ ```
110
+
111
+ ### Report Trades
112
+
113
+ ```python
114
+ # Report a trade execution
115
+ result = await agent.report_trade(
116
+ signal_id=signal.id,
117
+ market_id=signal.market_id,
118
+ direction='yes',
119
+ size_usd=100.0,
120
+ entry_price=0.65,
121
+ tx_hash="0x..." # Optional, for verification
122
+ )
123
+
124
+ trade_id = result['trade_id']
125
+
126
+ # Later, report the close
127
+ await agent.report_close(
128
+ trade_id=trade_id,
129
+ exit_price=0.85,
130
+ pnl_usd=30.77 # (0.85-0.65)/0.65 * 100
131
+ )
132
+ ```
133
+
134
+ ### Report Skips/Failures
135
+
136
+ ```python
137
+ # Skip a signal
138
+ await agent.report_skip(
139
+ signal_id=signal.id,
140
+ reason="below_threshold" # or "no_liquidity", "already_positioned"
141
+ )
142
+
143
+ # Report failure
144
+ await agent.report_failure(
145
+ signal_id=signal.id,
146
+ reason="slippage_too_high"
147
+ )
148
+ ```
149
+
150
+ ### Check Stats
151
+
152
+ ```python
153
+ # Your performance
154
+ stats = await agent.get_my_stats()
155
+ print(f"Win Rate: {stats['win_rate']:.1f}%")
156
+ print(f"Total P&L: ${stats['total_pnl_usd']:.2f}")
157
+
158
+ # Leaderboard
159
+ leaders = await agent.get_leaderboard()
160
+ for l in leaders[:5]:
161
+ print(f"#{l['rank']} - ${l['total_pnl_usd']:.2f}")
162
+ ```
163
+
164
+ ### Stream Signals (Long-polling)
165
+
166
+ ```python
167
+ async for signal in agent.stream_signals(min_confidence=0.6):
168
+ print(f"New signal: {signal.market} -> {signal.direction}")
169
+ # Execute your trading logic here
170
+ ```
171
+
172
+ ### Register Webhook
173
+
174
+ ```python
175
+ # For real-time delivery (Pro+ tiers)
176
+ await agent.register_webhook("https://your-agent.com/webhook")
177
+ ```
178
+
179
+ ## Error Handling
180
+
181
+ ```python
182
+ from xu_agent_sdk import (
183
+ XuAuthError,
184
+ XuRateLimitError,
185
+ XuPaymentRequiredError,
186
+ XuSignalLimitError
187
+ )
188
+
189
+ try:
190
+ signals = await agent.get_signals()
191
+ except XuAuthError:
192
+ print("Invalid API key")
193
+ except XuRateLimitError as e:
194
+ print(f"Rate limited, retry in {e.retry_after}s")
195
+ except XuSignalLimitError as e:
196
+ print(f"Daily limit reached, resets in {e.resets_in_seconds}s")
197
+ except XuPaymentRequiredError as e:
198
+ print(f"Upgrade required. Tiers: {e.pricing}")
199
+ ```
200
+
201
+ ## Webhook Payload
202
+
203
+ When you register a webhook, signals are POSTed with this format:
204
+
205
+ ```json
206
+ {
207
+ "event": "new_signal",
208
+ "signal_id": "abc123",
209
+ "timestamp": "2026-02-03T10:30:00Z",
210
+ "data": {
211
+ "market": "Will Bitcoin hit $100k by March 2026?",
212
+ "market_id": "0x1234...",
213
+ "direction": "yes",
214
+ "confidence": 0.72,
215
+ "suggested_size": "$50-100",
216
+ "entry_price": 0.65
217
+ }
218
+ }
219
+ ```
220
+
221
+ Verify webhooks using the `X-1xu-Signature` header.
222
+
223
+ ## Support
224
+
225
+ - **Documentation**: https://1xu.app/docs/sdk
226
+ - **Discord**: https://discord.gg/1xu
227
+ - **Email**: dev@1xu.app
228
+
229
+ ## License
230
+
231
+ MIT
@@ -0,0 +1,7 @@
1
+ xu_agent_sdk/__init__.py,sha256=CWqEVKpiLez3f1K7uvj2cxNi37sxoWd8kliV2FMqJo8,971
2
+ xu_agent_sdk/client.py,sha256=P-MsEmloNV1ucQSV-OBtvFqlgAsTH6okU2AT5Jluh1Q,19403
3
+ xu_agent_sdk/exceptions.py,sha256=hf91w1CnOfbigbDtDLyvEbdafY_uBe_oUmM99VGjVsA,1331
4
+ xu_agent_sdk-0.1.0.dist-info/METADATA,sha256=B6QfIsS3t_eMLVkGXECU8YFY-ORtGkX7BePLogpAo2E,5890
5
+ xu_agent_sdk-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
6
+ xu_agent_sdk-0.1.0.dist-info/top_level.txt,sha256=QrlVZNXMuzTpGApQF3lMk2JgGdio-7SIE7pqRz6ad6k,13
7
+ xu_agent_sdk-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ xu_agent_sdk