Skip to content

Claude/polymarket trading bot o r ioe#233

Open
50thycal wants to merge 5 commits intoPolymarket:mainfrom
50thycal:claude/polymarket-trading-bot-oRIoe
Open

Claude/polymarket trading bot o r ioe#233
50thycal wants to merge 5 commits intoPolymarket:mainfrom
50thycal:claude/polymarket-trading-bot-oRIoe

Conversation

@50thycal
Copy link
Copy Markdown

@50thycal 50thycal commented Dec 30, 2025

Overview

Description

Testing instructions

Types of changes

  • Refactor/enhancement
  • Bug fix/behavior correction
  • New feature
  • Breaking change
  • Other, additional

Notes

Status

  • Prefix PR title with [WIP] if necessary (changes not yet made).
  • Add tests to cover changes as needed.
  • Update documentation/changelog as needed.
  • Verify all tests run correctly in CI and pass.
  • Ready for review/merge.

Note

Introduces a complete directional trading bot for Polymarket with an HTTP control plane and basic web UI.

  • Adds main.py FastAPI server with auth-protected endpoints (/status, /pause, /resume, /mode/{paper|live}, /risk, /markets, /cancel-all) and /ui web panel; starts background trading loop
  • Implements bot/execution.py execution engine wrapping py-clob-client for order placement/cancellation, midpoints/order book, and balance queries with env-based initialization
  • Adds thread-safe global state in bot/state.py (paused/mode, risk limits, uptime, last actions, exposure tracking)
  • Provides bot/strategy.py scaffold for signal generation/validation and market summaries
  • Adds BOT_README.md with setup/deployment (Codespaces/Railway) and updates requirements.txt/bot_requirements.txt for FastAPI/uvicorn/pydantic

Written by Cursor Bugbot for commit fcb9d3d. This will update automatically on new commits. Configure here.

- main.py: Entry point with FastAPI server and trading loop
- bot/state.py: Thread-safe shared state (paused, mode, risk limits)
- bot/execution.py: Wrapper around py-clob-client for order execution
- bot/strategy.py: Placeholder for directional trading signals
- bot_requirements.txt: Dependencies including FastAPI and uvicorn
- BOT_README.md: Setup instructions for Codespaces and Railway

Features:
- HTTP API for phone-based control via curl
- Paper/live trading modes
- Risk limits (max order size, max exposure)
- Bearer token authentication
- Starts paused and in paper mode for safety
- GET /ui serves a single-page control panel
- Token stored in localStorage after first login
- Auto-refreshes status every 5 seconds
- Mobile-first responsive design
- Controls: pause/resume, paper/live mode, risk limits
- Emergency cancel all orders button
- Buttons disabled when action not applicable
- Dark theme with clear status badges
- Validate API secret is valid base64
- Check for accidental quotes in environment variables
- Test API credentials by calling get_api_keys endpoint
- Log clearer error message when credentials don't match wallet
@50thycal 50thycal requested a review from a team as a code owner December 30, 2025 18:42
Comment thread bot/execution.py
result = self.client.get_midpoint(token_id)
if result and hasattr(result, 'mid'):
return float(result.mid)
return None
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dictionary accessed as object attributes always returns None

The get_midpoint method checks hasattr(result, 'mid') but the py-clob-client's get_midpoint() returns a dictionary (raw JSON from resp.json()), not an object with attributes. Dictionaries in Python don't have attribute access, so hasattr() always returns False, causing this method to always return None. The same pattern affects get_collateral_balance() and get_token_balance() which check hasattr(result, 'balance'). The correct approach would use dictionary key access like result.get('mid') or 'mid' in result. This completely breaks the bot's ability to fetch market prices and account balances.

Additional Locations (2)

Fix in Cursor Fix in Web

Comment thread bot/execution.py
logger.info("=== CLOB Client Initialization ===")
logger.info(f"Host: {host}")
logger.info(f"POLY_PRIVATE_KEY: {'SET' if private_key else 'MISSING'} (len={len(private_key)})")
logger.info(f"POLY_API_KEY: {'SET' if api_key else 'MISSING'} (len={len(api_key)}, starts={api_key[:8] if len(api_key) > 8 else 'N/A'}...)")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API key prefix logged exposes partial credential

The initialization code logs the first 8 characters of POLY_API_KEY to application logs with the message starts={api_key[:8]}.... The comment claims this is "without exposing secrets" but partial API keys are sensitive information that can help attackers narrow down valid credentials. Logs are often accessible to multiple team members, stored in log aggregation services, or exposed in error reports. Credential prefixes should never be logged.

Fix in Cursor Fix in Web

Comment thread bot/execution.py
# Update exposure tracking
order_value = price * size
if side.upper() == "BUY":
state.add_exposure(token_id, order_value)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SELL orders never reduce exposure tracking

The reduce_exposure method is defined in bot/state.py but is never called anywhere in the codebase. When place_order executes a SELL order, it does not reduce the tracked exposure. This means exposure only ever increases (on BUY orders), causing the tracked exposure to accumulate over time. Eventually, all markets will appear to have reached their max_exposure_per_market limit, blocking legitimate BUY orders even when actual positions have been sold. The bot would effectively stop trading after enough BUY/SELL cycles.

Additional Locations (1)

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants