* fix(ingestor): align WebSocket subscribe + routing with live API
The Polymarket ws-live-data WebSocket requires `action: "subscribe"` in
the subscribe envelope. Without it the server accepts the connection but
never delivers trade events, causing the tracker to silently produce
zero alerts.
Additionally, incoming frames are shaped `{connection_id, payload:{...}}`
-- they do NOT echo the `topic`/`type` keys we sent. The previous routing
check matched nothing and every real trade was silently dropped.
Changes:
- Add `action: "subscribe"` to subscription message
- Route incoming messages by payload shape (transactionHash + proxyWallet)
- Add ratchet tests for payload routing edge cases
- Rewrite README as agent-first with <2min quickstart
- Add skill draft (docs/skill-tracking-prediction-market-flow.md)
Closes#89
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(lint): remove unused imports in test_pipeline_persistence
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* style: apply ruff formatting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The live pipeline was receiving trade data and populating Redis caches but
never persisting wallet profiles or funding transfers to Postgres. This
wires the repositories into the _on_trade flow: when a fresh wallet signal
is detected, the wallet profile is upserted to wallet_profiles and the
funding chain is traced and inserted into funding_transfers. Existing
Redis caching behavior is preserved.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: replace deprecated datetime.utcnow() and websockets.legacy APIs
- Replace datetime.utcnow() with datetime.now(UTC) in Orderbook model
- Use websockets.asyncio.client.connect instead of legacy websockets.connect
- Import ConnectionClosed from websockets.exceptions directly
- Update test mocks to patch the new import paths
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve ruff lint errors in alembic migration
- Replace typing.Union with X | Y syntax (UP007)
- Import Sequence from collections.abc instead of typing (UP035)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove deprecated version key from docker-compose.yml
The top-level 'version' key is obsolete in modern Docker Compose
and produces a warning.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: fix README to match actual project structure and tooling
- Replace pip commands with uv equivalents
- Fix run command from 'python -m src.main' to 'python -m polymarket_insider_tracker'
- Update project structure tree to reflect actual src/polymarket_insider_tracker/ layout
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Implement graceful shutdown handling for the async pipeline with proper
signal trapping and cleanup coordination.
Features:
- GracefulShutdown class with SIGTERM/SIGINT signal trapping
- Async event-based shutdown coordination
- Configurable shutdown timeout (default: 30 seconds)
- Cleanup callback registration (sync and async)
- Force exit on second signal
- Async context manager support
- Platform-specific signal handling (Unix/Windows)
Integration:
- Updated __main__.py to use GracefulShutdown wrapper
- Pipeline cleanup registered as shutdown callback
- Proper logging of shutdown stages
Tests: 25 new tests covering signal handling, timeouts, cleanup callbacks,
and context manager behavior.
Closes#56🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement the main CLI entry point for the Polymarket Insider Tracker.
Features:
- argparse-based CLI with version, config-check, dry-run, log-level flags
- Structured logging configuration with multiple formatters
- Configuration validation with friendly error messages
- Startup banner display
- Config check mode for validation without running
- Integration with Pipeline orchestrator
Tests: 20 new tests covering parser, logging, banner, config validation,
and integration scenarios.
Closes#55🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Pipeline class that wires together all detection components and
manages the event flow from trade ingestion to alerting.
Key features:
- Lifecycle management (start/stop) with proper cleanup
- Component initialization from Settings
- Parallel detector execution for fresh wallet and size anomaly
- Risk scoring with alert threshold
- Multi-channel alert dispatch (Discord/Telegram)
- Dry-run mode for testing without sending alerts
- Async context manager support
- Comprehensive test coverage (19 tests)
Pipeline flow: WebSocket → Profiler → Detectors → Scorer → Alerter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add pydantic-settings dependency
- Create centralized config.py with nested settings groups:
- DatabaseSettings: PostgreSQL connection validation
- RedisSettings: Redis connection with defaults
- PolygonSettings: RPC endpoints with fallback support
- PolymarketSettings: WebSocket URL and optional API key
- DiscordSettings: Optional webhook for alerts
- TelegramSettings: Optional bot token/chat ID for alerts
- Implement singleton pattern with get_settings() and LRU cache
- Add redacted_summary() for logging config without exposing secrets
- Support .env file loading via python-dotenv
- Add comprehensive test suite (26 tests)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
## Changes
### test_get_market_not_found
- Updated test to expect `RetryError` instead of `ClobClientError`
- The `get_market` method uses the `@with_retry()` decorator, so when
the underlying API call fails repeatedly, it raises `RetryError`
wrapping the original exception
- Removed unused `ClobClientError` import
### test_start_and_receive_trades
- Replaced `MagicMock` with a proper `MockWebSocket` class that
implements the async iterator protocol correctly
- `MagicMock` was passing `self` as an extra argument when calling
`__aiter__`, causing "takes 0 positional arguments but 1 was given"
- Removed unused `MagicMock` import
Closes#49🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Revert underscore-prefixed fixture parameters (breaks pytest discovery)
- Use # noqa: ARG002 comments instead
- Add aiosqlite to dev dependencies for SQLite-based tests
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use contextlib.suppress instead of try/except/pass (SIM105)
- Prefix unused fixture arguments with underscore (ARG002)
- Replace asyncio.TimeoutError with TimeoutError (UP041)
- Apply ruff formatting to all files
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add sniper cluster detection system that identifies wallets exhibiting
coordinated "sniper" behavior - consistently entering markets within
minutes of their creation.
Key features:
- SniperDetector class using DBSCAN clustering algorithm
- Tracks wallet entries across markets with timing analysis
- Feature vector: market hash, entry delta, log position size
- Identifies clusters of wallets with similar timing patterns
- Generates SniperClusterSignal for detected cluster members
- Configurable entry threshold (default 5 minutes), cluster size, DBSCAN params
- Confidence scoring based on cluster size, entry speed, market overlap
Also adds:
- SniperClusterSignal model to detector/models.py
- scikit-learn and numpy dependencies for ML clustering
- 27 comprehensive tests covering clustering logic and edge cases
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add FundingTracer class that traces USDC transfers backwards from a target
wallet to identify funding sources. Key features:
- Traces funding chain up to configurable max hops (default 3)
- Identifies terminal entities (CEX hot wallets, bridges) using EntityRegistry
- Parses ERC20 Transfer event logs from Polygon blockchain
- Calculates suspiciousness scores based on funding patterns
- Supports batch tracing multiple addresses concurrently
Also adds FundingTransfer and FundingChain dataclasses to models.py
for representing funding chain data.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add EntityType enum for classifying blockchain entities
- Add entity_data.py with Polygon CEX hot wallets, bridges, DEX contracts
- Add EntityRegistry class with classify/is_terminal methods
- Support custom entity additions and overrides
- Include 49 comprehensive unit tests
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add SQLAlchemy models for wallet profiles, funding transfers, and relationships
- Add WalletRepository, FundingRepository, RelationshipRepository with async support
- Add DatabaseManager for connection and session management
- Add Alembic migration for initial schema
- Include comprehensive test suite with 21 tests using in-memory SQLite
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add AlertHistory class for Redis-based alert tracking
- Add AlertRecord dataclass for serialization/deserialization
- Implement deduplication by wallet/market/hour combination
- Add time-based indexes for efficient querying
- Support user feedback tracking on alerts
- Include cleanup of old alerts beyond retention period
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements AlertDispatcher with multi-channel delivery support:
- DiscordChannel using webhook URL with embed formatting
- TelegramChannel using Bot API with MarkdownV2
- Rate limiting per channel (configurable)
- Circuit breaker pattern for failing channels
- Async delivery with retry and exponential backoff
- 23 comprehensive tests
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements AlertFormatter class that transforms RiskAssessment objects
into formatted messages for Discord (embeds), Telegram (markdown), and
plain text channels. Includes FormattedAlert dataclass, helper functions
for address truncation and risk level display, and comprehensive tests.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement RiskScorer that combines signals from multiple detectors into
a unified risk assessment with weighted scoring and deduplication.
Features:
- SignalBundle for collecting signals for a single trade
- RiskAssessment dataclass with complete scoring metadata
- Configurable weights for each signal type
- Multi-signal bonus (1.2x for 2 signals, 1.3x for 3+)
- Redis-based deduplication (1 hour window by default)
- Alert threshold configuration (default: 0.6)
- Batch assessment for processing multiple trades
- A/B testing support via dynamic weight updates
Default weights:
- fresh_wallet: 0.40
- size_anomaly: 0.35
- niche_market: 0.25
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement SizeAnomalyDetector for identifying trades with unusually
large position sizes relative to market liquidity.
Features:
- Volume impact analysis (trade size / 24h volume)
- Order book impact analysis (trade size / book depth)
- Niche market detection using category heuristics
- Confidence scoring with configurable thresholds
- Batch analysis for processing multiple trades
The detector gracefully handles missing volume/book data by falling
back to category-based heuristics for identifying niche markets
where large trades are more significant.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add FreshWalletDetector class that identifies trades from fresh wallets
and generates alert signals with confidence scores.
Features:
- FreshWalletSignal dataclass with trade/wallet data and confidence
- Configurable thresholds for nonce, age, and minimum trade size
- Confidence scoring based on wallet freshness and trade characteristics
- Batch analysis support with parallel processing
- Integration with WalletAnalyzer from profiler module
Confidence scoring:
- Base: 0.5 (fresh wallet detected)
- +0.2 if nonce == 0 (brand new)
- +0.1 if age < 2 hours (very young)
- +0.1 if trade size > $10,000 (large trade)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
- Add PolygonClient for blockchain data queries with rate limiting, retry logic, and Redis caching
- Implement Transaction and WalletInfo data models with unit conversions
- Add comprehensive test coverage (51 tests)
## Features
- Token bucket rate limiter to respect RPC provider limits
- Exponential backoff retry logic with configurable attempts
- Automatic failover to secondary RPC URL
- Redis caching with configurable TTL
- Methods: get_transaction_count, get_balance, get_token_balance, get_block, get_wallet_info
## Test plan
- [x] All 51 profiler tests pass
- [x] Ruff lint passes
- [x] Mypy type check passes
Closes#8🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements the HealthMonitor class for tracking connection health:
- Tracks connection states per stream (active, stale, disconnected)
- Records events and calculates throughput (events/second)
- Detects stale streams (no events for configurable threshold)
- Exposes Prometheus-compatible metrics endpoint (/metrics)
- Provides HTTP health endpoints (/health, /ready, /live)
Exports: HealthMonitor, HealthReport, HealthStatus, StreamHealth, StreamStatus
Tests: 47 comprehensive unit tests covering all functionality
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement EventPublisher class for publishing trade events to Redis
Streams, enabling decoupled downstream processing. Key features:
- EventPublisher wrapping Redis Streams XADD/XREADGROUP commands
- Single and batch publishing with configurable max stream length
- Consumer group management (create/ensure)
- Event reading with pending entry recovery
- Acknowledgment helpers for exactly-once semantics
- Stream info and trimming utilities
- Full TradeEvent serialization/deserialization
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement MarketMetadataSync class for background synchronization of
market metadata with Redis-based caching. Key features:
- MarketMetadata dataclass with derived category field
- Automatic category derivation from market title (politics, crypto,
sports, entertainment, finance, tech, science, other)
- Background sync loop with configurable interval (default: 5 min)
- Redis caching with TTL-based expiration (default: 10 min)
- Cache-first lookups via get_market() method
- State management with callbacks for monitoring
- Comprehensive test suite (29 tests)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add TradeEvent dataclass for trade data from WebSocket feed
- Implement TradeStreamHandler with async WebSocket streaming
- Add automatic reconnection with exponential backoff (1s-30s)
- Support event/market filtering for targeted subscriptions
- Include connection state management and statistics tracking
- Add websockets>=12.0 dependency
Acceptance Criteria:
- [x] TradeStreamHandler class using websockets library
- [x] Connects to Polymarket WSS endpoint
- [x] Subscribes to market trade channel on connection
- [x] Parses trade messages into TradeEvent dataclass
- [x] Implements heartbeat/ping-pong for connection health
- [x] Auto-reconnects on disconnect with exponential backoff
- [x] Emits events via callback pattern
- [x] Logs connection state changes
Closes#3🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ClobClient class wrapping py-clob-client library
- Implement rate limiting (10 requests/second) with token bucket
- Add retry logic with exponential backoff (3 retries)
- Load API key from POLYMARKET_API_KEY environment variable
- Create Market, Orderbook, Token dataclass models
- Add comprehensive unit tests with mocked responses
Acceptance Criteria:
- [x] ClobClient class that wraps py-clob-client
- [x] Loads POLYMARKET_API_KEY from environment
- [x] Implements get_markets() returning all active markets
- [x] Implements get_market(market_id) returning market details
- [x] Implements get_orderbook(market_id) returning current book
- [x] Rate limiting: max 10 requests/second with automatic throttling
- [x] Retry logic: 3 retries with exponential backoff on errors
- [x] Unit tests with mocked responses
- [x] Type hints for all public methods
Closes#2🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add pyproject.toml with core and dev dependencies
- Configure Ruff for linting and formatting
- Configure MyPy for strict type checking
- Configure pytest with asyncio support
- Create src/polymarket_insider_tracker package structure
- Add py.typed marker for PEP 561 compliance
- Add pre-commit hooks configuration
- Add comprehensive .gitignore
- Create test directory structure with basic tests
Closes#25🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>