Real-time arbitrage detection system for prediction markets: Polymarket vs Opinion.
Polyscan monitors and compares prediction markets from Polymarket and Opinion to identify arbitrage opportunities where you can guarantee profit regardless of the outcome.
The arbitrage opportunity exists when:
Price_YES (Platform A) + Price_NO (Platform B) < $1.00
Example:
- Buy YES on Polymarket for $0.65
- Buy NO on Opinion for $0.32
- Total cost: $0.97
- Guaranteed payout: $1.00
- Profit: $0.03 (3.09%)
-
4 Interactive Tabs:
- π Polymarket Markets - All active markets from Polymarket
- π Opinion Markets - All active markets from Opinion
- π Matched Events - Markets matched between platforms using fuzzy matching
- π° Arbitrage Opportunities - Detected arbitrage with profit calculations
-
Real-time Updates - Data refreshes every 30 seconds
-
Smart Matching - Fuzzy matching algorithm to find equivalent events
-
Profit Calculations - Automatic profit percentage and volume analysis
-
Modern UI - React + Tailwind CSS responsive interface
- Node.js + TypeScript
- Express - REST API server
- Axios - HTTP client for external APIs
- Redis - Caching layer
- Winston - Logging
- React + TypeScript
- Vite - Build tool
- Tailwind CSS - Styling
- Axios - API client
- Node.js 18+
- Redis (optional, for caching)
- Opinion API Key (get from https://docs.opinion.trade/)
- Clone and install backend:
cd polyscan
npm install- Install frontend:
cd frontend
npm install- Configure environment:
cp .env.example .envEdit .env and add your Opinion API key:
OPINION_API_KEY=your_api_key_here
REDIS_HOST=localhost
REDIS_PORT=6379
PORT=3001Option 1: Run everything together
npm run devOption 2: Run separately
Terminal 1 - Backend:
npm run dev:backendTerminal 2 - Frontend:
cd frontend
npm run dev# Build backend
npm run build:backend
# Build frontend
cd frontend
npm run build
# Start server
npm startGET /api/health- Health checkGET /api/polymarket/markets- Get all Polymarket marketsGET /api/opinion/markets- Get all Opinion marketsGET /api/matches?confidence=high- Get matched marketsGET /api/arbitrage?minProfit=1&minVolume=100- Get arbitrage opportunitiesGET /api/stats- Get overall statisticsPOST /api/refresh- Force data refresh
polyscan/
βββ src/
β βββ api/ # API clients
β β βββ polymarket.client.ts
β β βββ opinion.client.ts
β βββ services/ # Business logic
β β βββ markets.service.ts
β β βββ matching.service.ts
β β βββ arbitrage.service.ts
β βββ types/ # TypeScript types
β β βββ market.types.ts
β β βββ arbitrage.types.ts
β βββ utils/ # Utilities
β β βββ cache.ts
β β βββ logger.ts
β βββ index.ts # Server entry point
βββ frontend/
β βββ src/
β β βββ components/ # React components
β β βββ hooks/ # Custom hooks
β β βββ services/ # API service
β β βββ types/ # TypeScript types
β βββ index.html
βββ README.md
Markets are matched using string similarity with weighted scoring:
- Title similarity: 70% weight
- Category similarity: 30% weight
- Threshold: 85% minimum match
Uses Jaro-Winkler distance via string-similarity library.
For each matched outcome:
- Check if
YES_ASK_A + NO_ASK_B < 1.0 - Check if
NO_ASK_A + YES_ASK_B < 1.0 - Calculate profit percentage:
(1.0 - total_cost) / total_cost * 100 - Filter opportunities above minimum profit threshold
Environment variables in .env:
# Server
PORT=3001
NODE_ENV=development
# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
# API Keys
OPINION_API_KEY=your_key
# Cache
CACHE_TTL=60
UPDATE_INTERVAL=30000
# Arbitrage
MIN_PROFIT_THRESHOLD=0.01
SIMILARITY_THRESHOLD=0.85Logs are written to:
logs/error.log- Error logslogs/combined.log- All logs- Console (development mode)
-
New API endpoint:
- Add route in
src/index.ts - Implement logic in services
- Add route in
-
New UI tab:
- Create component in
frontend/src/components/ - Add tab to
App.tsx
- Create component in
npm testIssue: Redis connection error
- Make sure Redis is running:
redis-server - Or disable Redis (app works without cache)
Issue: Opinion API errors
- Check API key is valid
- Verify rate limits (15 req/sec)
Issue: No arbitrage found
- This is normal - arbitrage is rare
- Try adjusting
MIN_PROFIT_THRESHOLDin.env
- Backend: ~100ms response time
- API calls: Cached for 30-60 seconds
- Update interval: 30 seconds default
- Concurrent users: Supports 100+
- Never commit
.envfile - Use environment variables for secrets
- API keys stored securely
- CORS configured for production
- WebSocket for real-time updates
- Email/SMS alerts for arbitrage
- Historical data tracking
- Advanced filtering options
- Mobile responsive improvements
- Trade execution integration
MIT
For issues and questions:
- GitHub Issues
- Documentation: See technical spec document
Built with β€οΈ for the prediction markets community
