Add 6 Polymarket trading skills with paper trading engine

Composable Agent Skills (SKILL.md format) for Polymarket prediction market
trading. Includes scanner, analyzer, monitor, paper trader, strategy advisor,
and live executor. All tested against live Polymarket APIs. Security audited
with all HIGH/MEDIUM findings resolved.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Polymarket Skills Builder
2026-02-26 07:25:07 +00:00
co-authored by Claude Opus 4.6
parent 6a03bbe2e5
commit 068b2adc75
35 changed files with 7842 additions and 1 deletions
+101
View File
@@ -0,0 +1,101 @@
---
name: polymarket-live-executor
description: >
Use this skill when the user wants to execute a real trade on Polymarket, place a live
order, go live, buy or sell on Polymarket, check real positions, or manage a live trading
wallet. Triggers: "execute trade", "live trade", "real trade", "go live",
"place order polymarket", "buy on polymarket", "sell on polymarket", "check positions",
"my balance", "cancel order", "live portfolio".
CRITICAL: This skill executes REAL trades with REAL money. Every trade requires explicit
human confirmation before execution. Never execute autonomously.
---
# Polymarket Live Executor
Execute real trades on Polymarket with mandatory human-in-the-loop confirmation.
This skill requires L2 authentication (wallet private key) and enforces strict
safety controls on every operation.
## SAFETY REQUIREMENTS
**Every trade requires explicit user confirmation.** The agent must:
1. Display full trade details (market, side, size, price, estimated cost)
2. Show current order book context (spread, depth at target price)
3. Wait for the user to type "yes" or "confirm" before proceeding
4. Never batch or auto-confirm trades
**Environment safeguards** (enforced by all scripts):
- `POLYMARKET_PRIVATE_KEY` must be set (burner wallet only -- NEVER a main wallet)
- `POLYMARKET_CONFIRM=true` must be set to enable any trade execution
- Position size hard-capped (default $10, configurable via `POLYMARKET_MAX_SIZE`)
- Daily loss limit tracked in `~/.polymarket-live/trades.log`
## Setup
Before using this skill, the user must:
1. Create a burner wallet (see `references/security.md`)
2. Fund it with a small amount of USDC on Polygon
3. Set environment variables:
```bash
export POLYMARKET_PRIVATE_KEY="0x..." # Burner wallet only!
export POLYMARKET_CONFIRM=true # Safety gate
export POLYMARKET_MAX_SIZE=10 # Max $ per trade (default: 10)
export POLYMARKET_DAILY_LOSS_LIMIT=50 # Max daily loss (default: 50)
```
4. Review the `references/live-trading-checklist.md` before any live trade
## Available Scripts
### 1. Execute Trade (`scripts/execute_live.py`)
Place a real order on Polymarket.
```bash
# Limit order: buy 5 YES shares at $0.60
python scripts/execute_live.py --token-id <ID> --side BUY --size 5 --price 0.60
# Market order: buy $5 worth at market price
python scripts/execute_live.py --token-id <ID> --side BUY --amount 5 --market
# Sell: sell 10 shares at $0.75
python scripts/execute_live.py --token-id <ID> --side SELL --size 10 --price 0.75
```
The script will display full trade details and require interactive confirmation.
### 2. Check Positions (`scripts/check_positions.py`)
View wallet balance, open orders, and trade history.
```bash
python scripts/check_positions.py # Summary
python scripts/check_positions.py --orders # Open orders
python scripts/check_positions.py --trades # Recent trades
python scripts/check_positions.py --balance # USDC balance
```
## Workflow
1. Run analysis with polymarket-analyzer scripts to find opportunities
2. Paper-trade the idea with polymarket-paper-trader first
3. Review `references/live-trading-checklist.md`
4. Set up environment variables and burner wallet
5. Use `check_positions.py` to verify wallet state
6. Execute trade with `execute_live.py` -- confirm when prompted
7. Monitor position with `check_positions.py`
## Risk Controls
- All trades logged to `~/.polymarket-live/trades.log`
- Daily P&L tracked and enforced against loss limit
- Position size caps prevent oversized trades
- No autonomous execution -- every trade needs human approval
## Important Disclaimers
- This skill executes REAL trades with REAL money
- Use only with burner wallets funded with money you can afford to lose
- Past analysis does not guarantee future results
- Not financial advice -- you are solely responsible for your trades
@@ -0,0 +1,68 @@
# Pre-Flight Checklist for Live Trading
Complete ALL items before executing your first live trade.
## Wallet Setup
- [ ] Created a dedicated burner wallet (NOT your main wallet)
- [ ] Funded with an amount you can afford to lose entirely
- [ ] Verified wallet has USDC on Polygon network
- [ ] Verified wallet has small MATIC balance for gas
- [ ] Private key stored in environment variable only (not in files or code)
## Environment Configuration
- [ ] `POLYMARKET_PRIVATE_KEY` is set to burner wallet key
- [ ] `POLYMARKET_CONFIRM=true` is set (required safety gate)
- [ ] `POLYMARKET_MAX_SIZE` is set to your per-trade limit (default: $10)
- [ ] `POLYMARKET_DAILY_LOSS_LIMIT` is set (default: $50)
- [ ] Verified configuration with `check_positions.py --balance`
## Analysis Completed
- [ ] Identified specific market and opportunity using polymarket-analyzer
- [ ] Reviewed order book depth with `analyze_orderbook.py`
- [ ] Confirmed sufficient liquidity at target price
- [ ] Understood the market's resolution criteria
- [ ] Checked market end date (not expiring imminently)
## Paper Trading Validation
- [ ] Tested the same strategy in paper trading mode first
- [ ] Paper trading results reviewed and acceptable
- [ ] Understand expected win rate and risk/reward ratio
- [ ] Strategy has shown positive expectancy in paper trades
## Risk Management
- [ ] Set maximum position size per trade
- [ ] Set daily loss limit
- [ ] Decided on exit strategy (when to take profit, when to cut loss)
- [ ] Understand that prediction markets can go to 0 or 1
- [ ] Accepted that all funds in burner wallet could be lost
- [ ] Not trading with money needed for bills, rent, or essentials
## Execution Plan
- [ ] Know the exact token ID for the trade
- [ ] Know the side (BUY or SELL)
- [ ] Know the size (number of shares or dollar amount)
- [ ] Know the price (limit) or willing to accept market price
- [ ] Reviewed current bid-ask spread
- [ ] Will carefully review the confirmation prompt before approving
## After the Trade
- [ ] Verified trade executed at expected price (check trades.log)
- [ ] Set a reminder to check position before market resolution
- [ ] Know how to cancel open limit orders if needed
- [ ] Plan for monitoring: will check at least daily
## Emergency Procedures
If something goes wrong:
1. Unset `POLYMARKET_CONFIRM` to prevent any further trades
2. Use `check_positions.py --orders` to see open orders
3. Cancel all open orders if needed
4. Transfer remaining funds out of burner wallet if compromised
5. Create a new burner wallet if the old one may be exposed
@@ -0,0 +1,123 @@
# Security Guide for Live Polymarket Trading
## Rule #1: NEVER Use Your Main Wallet
Always create a dedicated **burner wallet** for bot trading. This wallet should:
- Be a fresh address with no connection to your primary holdings
- Hold only the amount you are willing to lose entirely
- Never be used for any other purpose
If your private key is compromised (through env var leaks, log exposure, or
prompt injection attacks), only the burner wallet funds are at risk.
## Creating a Burner Wallet
### Option A: Using Python
```python
from eth_account import Account
acct = Account.create()
print(f"Address: {acct.address}")
print(f"Private Key: {acct.key.hex()}")
# SAVE THESE SECURELY. Fund address with USDC on Polygon.
```
### Option B: Using MetaMask
1. Create a new MetaMask profile (not just a new account in existing profile)
2. Create a new wallet
3. Export the private key (Settings > Security > Export Private Key)
4. Fund with USDC on Polygon network
### Option C: Using cast (Foundry)
```bash
cast wallet new
# Save the address and private key
```
## Funding the Burner Wallet
1. Bridge USDC to Polygon (use official Polygon bridge or a reputable DEX)
2. Send only your maximum acceptable loss to the burner address
3. Keep some MATIC for gas fees (~0.1 MATIC is usually sufficient)
## Setting Up L2 Authentication
The Polymarket CLOB API uses three-tier authentication:
- **L0**: No auth. Read-only market data.
- **L1**: Wallet signature. Can create/sign orders.
- **L2**: API key + secret + passphrase. Can post orders, manage positions.
To set up L2:
```python
from py_clob_client.client import ClobClient
# Initialize with L1 (private key)
client = ClobClient(
"https://clob.polymarket.com",
chain_id=137, # Polygon mainnet
key="0xYOUR_PRIVATE_KEY"
)
# Create API credentials (L2)
creds = client.create_or_derive_api_creds()
print(f"API Key: {creds.api_key}")
print(f"API Secret: {creds.api_secret}")
print(f"API Passphrase: {creds.api_passphrase}")
```
Store these credentials securely. The execute_live.py script handles this
automatically when POLYMARKET_PRIVATE_KEY is set.
## Private Key Handling Best Practices
### DO:
- Store the private key in an environment variable (`POLYMARKET_PRIVATE_KEY`)
- Use a `.env` file with strict permissions (`chmod 600 .env`)
- Unset the variable when not actively trading (`unset POLYMARKET_PRIVATE_KEY`)
- Rotate burner wallets periodically (create new wallet, transfer remaining funds)
### DO NOT:
- Hardcode private keys in any script or config file
- Commit `.env` files to version control
- Share private keys in chat, logs, or error reports
- Use the same key for testing and production
- Give the LLM/agent direct access to your private key in conversation
- Store keys in world-readable files
### Gitignore Template
Add to your `.gitignore`:
```
.env
.env.*
*.key
polymarket-live/
~/.polymarket-live/
```
## Prompt Injection Defense
When using AI agents for trading, be aware of prompt injection risks:
1. **Never paste untrusted content into agent context** when live trading is enabled
2. **Market descriptions could contain malicious instructions** -- the agent should
never execute trades based on text found in market descriptions
3. **The POLYMARKET_CONFIRM=true env var** acts as a safety gate -- without it,
no trade can execute regardless of what the agent is told to do
4. **Review every trade confirmation** before approving -- the agent must show you
the exact parameters before execution
## Maximum Funding Recommendations
| Experience Level | Max Wallet Fund | Max Per Trade | Daily Loss Limit |
|------------------|-----------------|---------------|------------------|
| First time | $25 | $5 | $10 |
| Learning | $100 | $10 | $25 |
| Experienced | $500 | $50 | $100 |
| Advanced | $2,000+ | $200 | $500 |
Start small. You can always add more funds later.
+201
View File
@@ -0,0 +1,201 @@
#!/usr/bin/env python3
"""Check Polymarket positions, balances, and trade history.
Requires environment variable:
POLYMARKET_PRIVATE_KEY - Wallet private key for authenticated access
Displays: wallet address, USDC balance, open orders, recent trades.
"""
import argparse
import json
import os
import sys
from datetime import datetime, timezone
from pathlib import Path
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import (
ApiCreds,
BalanceAllowanceParams,
OpenOrderParams,
TradeParams,
)
CLOB_HOST = "https://clob.polymarket.com"
CHAIN_ID = 137
LOG_FILE = Path.home() / ".polymarket-live" / "trades.log"
def create_authenticated_client() -> ClobClient:
"""Create an L2-authenticated ClobClient."""
key = os.environ.get("POLYMARKET_PRIVATE_KEY", "")
if not key:
print(
"POLYMARKET_PRIVATE_KEY not set.\n"
"Set it to your wallet private key to view positions.",
file=sys.stderr,
)
sys.exit(1)
client = ClobClient(CLOB_HOST, chain_id=CHAIN_ID, key=key)
creds = client.create_or_derive_api_creds()
client.set_api_creds(creds)
return client
def show_balance(client: ClobClient):
"""Display USDC balance and allowance."""
address = client.get_address()
print(f"Wallet Address: {address}")
print()
try:
params = BalanceAllowanceParams(asset_type="COLLATERAL")
result = client.get_balance_allowance(params)
print("USDC Balance & Allowance:")
print(json.dumps(result, indent=2, default=str))
except Exception as e:
print(f"Error fetching balance: {e}", file=sys.stderr)
def show_orders(client: ClobClient):
"""Display open orders."""
print("Open Orders:")
print("-" * 70)
try:
orders = client.get_orders()
if not orders:
print(" No open orders.")
return
for order in orders:
print(json.dumps(order, indent=2, default=str))
print()
except Exception as e:
print(f"Error fetching orders: {e}", file=sys.stderr)
def show_trades(client: ClobClient):
"""Display recent trade history."""
print("Recent Trades:")
print("-" * 70)
try:
trades = client.get_trades()
if not trades:
print(" No trades found.")
return
for trade in trades[:20]: # Show last 20
print(json.dumps(trade, indent=2, default=str))
print()
except Exception as e:
print(f"Error fetching trades: {e}", file=sys.stderr)
def show_local_log():
"""Display local trade log."""
print("Local Trade Log (~/.polymarket-live/trades.log):")
print("-" * 70)
if not LOG_FILE.exists():
print(" No local trade log found.")
return
lines = LOG_FILE.read_text().splitlines()
if not lines:
print(" Trade log is empty.")
return
# Show last 20 entries
for line in lines[-20:]:
try:
entry = json.loads(line)
ts = entry.get("timestamp", "?")[:19]
status = entry.get("status", "?")
side = entry.get("side", "?")
token = entry.get("token_id", "?")[:20]
cost = entry.get("cost_usd", "?")
print(f" {ts} {status:<10} {side:<5} ${cost} {token}...")
except json.JSONDecodeError:
print(f" {line[:80]}")
# Show today's summary
today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
daily_total = 0.0
daily_count = 0
for line in lines:
try:
entry = json.loads(line)
if entry.get("timestamp", "").startswith(today) and entry.get("status") == "EXECUTED":
daily_total += float(entry.get("cost_usd", 0))
daily_count += 1
except (json.JSONDecodeError, ValueError):
continue
print()
print(f" Today ({today}): {daily_count} trades, ${daily_total:.2f} total spent")
def show_summary(client: ClobClient):
"""Display a comprehensive summary."""
address = client.get_address()
print(f"Polymarket Position Summary")
print(f"Wallet: {address}")
print("=" * 60)
# Balance
print()
show_balance(client)
# Open orders
print()
show_orders(client)
# Local log summary
print()
show_local_log()
# Safety status
print()
print("Safety Status:")
confirm = os.environ.get("POLYMARKET_CONFIRM", "")
max_size = os.environ.get("POLYMARKET_MAX_SIZE", "10")
daily_limit = os.environ.get("POLYMARKET_DAILY_LOSS_LIMIT", "50")
print(f" POLYMARKET_CONFIRM: {'ENABLED' if confirm == 'true' else 'DISABLED (trades blocked)'}")
print(f" POLYMARKET_MAX_SIZE: ${max_size}")
print(f" POLYMARKET_DAILY_LOSS_LIMIT: ${daily_limit}")
def main():
parser = argparse.ArgumentParser(
description="Check Polymarket positions and balances"
)
parser.add_argument("--balance", action="store_true", help="Show USDC balance only")
parser.add_argument("--orders", action="store_true", help="Show open orders only")
parser.add_argument("--trades", action="store_true", help="Show trade history only")
parser.add_argument("--log", action="store_true", help="Show local trade log only")
args = parser.parse_args()
# Local log doesn't need authentication
if args.log:
show_local_log()
return
client = create_authenticated_client()
if args.balance:
show_balance(client)
elif args.orders:
show_orders(client)
elif args.trades:
show_trades(client)
else:
show_summary(client)
if __name__ == "__main__":
main()
+390
View File
@@ -0,0 +1,390 @@
#!/usr/bin/env python3
"""Execute live trades on Polymarket with mandatory human confirmation.
SAFETY: Every trade requires interactive confirmation. No autonomous execution.
Requires environment variables:
POLYMARKET_PRIVATE_KEY - Burner wallet private key (NEVER main wallet)
POLYMARKET_CONFIRM=true - Safety gate (must be exactly "true")
Optional environment variables:
POLYMARKET_MAX_SIZE - Max $ per trade (default: 10)
POLYMARKET_DAILY_LOSS_LIMIT - Max daily loss in $ (default: 50)
All trades are logged to ~/.polymarket-live/trades.log
"""
import argparse
import json
import os
import sys
from datetime import datetime, timezone
from pathlib import Path
from py_clob_client.client import ClobClient
from py_clob_client.clob_types import (
ApiCreds,
OrderArgs,
MarketOrderArgs,
OrderType,
)
CLOB_HOST = "https://clob.polymarket.com"
CHAIN_ID = 137 # Polygon mainnet
LOG_DIR = Path.home() / ".polymarket-live"
LOG_FILE = LOG_DIR / "trades.log"
def check_safety_gates() -> tuple[bool, str]:
"""Verify all safety gates are in place. Returns (ok, message)."""
key = os.environ.get("POLYMARKET_PRIVATE_KEY", "")
if not key:
return False, (
"POLYMARKET_PRIVATE_KEY not set.\n"
"Set it to your BURNER wallet private key (never your main wallet).\n"
"See references/security.md for setup instructions."
)
confirm = os.environ.get("POLYMARKET_CONFIRM", "")
if confirm != "true":
return False, (
"POLYMARKET_CONFIRM is not set to 'true'.\n"
"This safety gate prevents accidental trade execution.\n"
"Set POLYMARKET_CONFIRM=true when you are ready for live trading."
)
return True, "OK"
def get_max_size() -> float:
"""Get maximum position size from env or default."""
try:
return float(os.environ.get("POLYMARKET_MAX_SIZE", "10"))
except ValueError:
return 10.0
def get_daily_loss_limit() -> float:
"""Get daily loss limit from env or default."""
try:
return float(os.environ.get("POLYMARKET_DAILY_LOSS_LIMIT", "50"))
except ValueError:
return 50.0
def get_daily_spending() -> float:
"""Calculate total spending today from the trade log."""
if not LOG_FILE.exists():
return 0.0
today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
total = 0.0
for line in LOG_FILE.read_text().splitlines():
try:
entry = json.loads(line)
if entry.get("timestamp", "").startswith(today) and entry.get("status") == "EXECUTED":
total += float(entry.get("cost_usd", 0))
except (json.JSONDecodeError, ValueError):
continue
return total
def log_trade(entry: dict):
"""Append a trade entry to the log file."""
LOG_DIR.mkdir(parents=True, exist_ok=True)
with open(LOG_FILE, "a") as f:
f.write(json.dumps(entry) + "\n")
def create_authenticated_client() -> ClobClient:
"""Create an L2-authenticated ClobClient."""
key = os.environ["POLYMARKET_PRIVATE_KEY"]
# Initialize L1 client
client = ClobClient(CLOB_HOST, chain_id=CHAIN_ID, key=key)
# Derive L2 API credentials
creds = client.create_or_derive_api_creds()
client.set_api_creds(creds)
return client
def get_orderbook_context(client: ClobClient, token_id: str) -> dict:
"""Fetch order book context for display."""
try:
book = client.get_order_book(token_id)
bids = [(float(b.price), float(b.size)) for b in (book.bids or [])]
asks = [(float(a.price), float(a.size)) for a in (book.asks or [])]
bids.sort(key=lambda x: x[0], reverse=True)
asks.sort(key=lambda x: x[0])
return {
"best_bid": bids[0] if bids else None,
"best_ask": asks[0] if asks else None,
"bid_depth_5": sum(s for _, s in bids[:5]),
"ask_depth_5": sum(s for _, s in asks[:5]),
"spread": (asks[0][0] - bids[0][0]) if (bids and asks) else None,
}
except Exception as e:
return {"error": str(e)}
def display_trade_confirmation(
side: str,
token_id: str,
size: float | None,
amount: float | None,
price: float | None,
is_market: bool,
context: dict,
max_size: float,
daily_spent: float,
daily_limit: float,
) -> str:
"""Display full trade details and return confirmation prompt text."""
lines = []
lines.append("")
lines.append("=" * 60)
lines.append(" LIVE TRADE CONFIRMATION REQUIRED")
lines.append("=" * 60)
lines.append("")
lines.append(f" Side: {side}")
lines.append(f" Token ID: {token_id[:40]}...")
if is_market:
lines.append(f" Order Type: MARKET (Fill-or-Kill)")
lines.append(f" Amount: ${amount:.2f} USD")
else:
lines.append(f" Order Type: LIMIT (Good-til-Cancelled)")
lines.append(f" Size: {size:.2f} shares")
lines.append(f" Price: ${price:.4f} per share")
est_cost = size * price
lines.append(f" Est. Cost: ${est_cost:.2f} USD")
lines.append("")
lines.append(" Order Book Context:")
if "error" in context:
lines.append(f" ERROR: {context['error']}")
else:
bb = context.get("best_bid")
ba = context.get("best_ask")
lines.append(f" Best Bid: ${bb[0]:.4f} ({bb[1]:.0f} shares)" if bb else " Best Bid: N/A")
lines.append(f" Best Ask: ${ba[0]:.4f} ({ba[1]:.0f} shares)" if ba else " Best Ask: N/A")
spread = context.get("spread")
lines.append(f" Spread: ${spread:.4f}" if spread is not None else " Spread: N/A")
lines.append(f" Bid Depth (5 lvls): {context.get('bid_depth_5', 0):,.0f} shares")
lines.append(f" Ask Depth (5 lvls): {context.get('ask_depth_5', 0):,.0f} shares")
lines.append("")
lines.append(" Risk Controls:")
lines.append(f" Max trade size: ${max_size:.2f}")
lines.append(f" Daily spent: ${daily_spent:.2f} / ${daily_limit:.2f}")
remaining = daily_limit - daily_spent
trade_cost = amount if is_market else (size * price if size and price else 0)
if trade_cost > remaining:
lines.append(f" WARNING: Trade (${trade_cost:.2f}) exceeds remaining daily budget (${remaining:.2f})")
lines.append("")
lines.append("=" * 60)
return "\n".join(lines)
def execute_limit_order(
client: ClobClient,
token_id: str,
side: str,
size: float,
price: float,
) -> dict:
"""Create and post a limit order."""
order_args = OrderArgs(
token_id=token_id,
price=price,
size=size,
side=side,
)
signed_order = client.create_order(order_args)
result = client.post_order(signed_order, orderType=OrderType.GTC)
return result
def execute_market_order(
client: ClobClient,
token_id: str,
side: str,
amount: float,
) -> dict:
"""Create and post a market order."""
order_args = MarketOrderArgs(
token_id=token_id,
amount=amount,
side=side,
)
signed_order = client.create_market_order(order_args)
result = client.post_order(signed_order, orderType=OrderType.FOK)
return result
def main():
parser = argparse.ArgumentParser(
description="Execute a live trade on Polymarket (requires confirmation)"
)
parser.add_argument("--token-id", required=True, help="CLOB token ID")
parser.add_argument(
"--side", required=True, choices=["BUY", "SELL"],
help="Trade side: BUY or SELL"
)
parser.add_argument("--size", type=float, help="Number of shares (for limit orders)")
parser.add_argument("--price", type=float, help="Limit price per share")
parser.add_argument("--amount", type=float, help="USD amount (for market orders)")
parser.add_argument("--market", action="store_true", help="Market order (FOK)")
args = parser.parse_args()
# Validate arguments
if args.market:
if not args.amount:
print("ERROR: --amount required for market orders", file=sys.stderr)
sys.exit(1)
else:
if not args.size or not args.price:
print("ERROR: --size and --price required for limit orders", file=sys.stderr)
sys.exit(1)
# Check safety gates
ok, msg = check_safety_gates()
if not ok:
print(f"SAFETY GATE FAILED:\n{msg}", file=sys.stderr)
sys.exit(1)
# Check position size limits
max_size = get_max_size()
trade_cost = args.amount if args.market else (args.size * args.price)
if trade_cost > max_size:
print(
f"BLOCKED: Trade cost ${trade_cost:.2f} exceeds max size ${max_size:.2f}.\n"
f"Increase POLYMARKET_MAX_SIZE if intentional.",
file=sys.stderr,
)
sys.exit(1)
# Check daily loss limit
daily_limit = get_daily_loss_limit()
daily_spent = get_daily_spending()
if daily_spent + trade_cost > daily_limit:
print(
f"BLOCKED: Daily spending ${daily_spent:.2f} + this trade ${trade_cost:.2f} "
f"= ${daily_spent + trade_cost:.2f} exceeds daily limit ${daily_limit:.2f}.\n"
f"Increase POLYMARKET_DAILY_LOSS_LIMIT or wait until tomorrow.",
file=sys.stderr,
)
sys.exit(1)
# Create authenticated client
try:
client = create_authenticated_client()
except Exception as e:
print(f"ERROR creating authenticated client: {e}", file=sys.stderr)
print("Check POLYMARKET_PRIVATE_KEY and network connectivity.", file=sys.stderr)
sys.exit(1)
# Get order book context
context = get_orderbook_context(client, args.token_id)
# Display confirmation
confirmation = display_trade_confirmation(
side=args.side,
token_id=args.token_id,
size=args.size,
amount=args.amount,
price=args.price,
is_market=args.market,
context=context,
max_size=max_size,
daily_spent=daily_spent,
daily_limit=daily_limit,
)
print(confirmation)
# Ask for confirmation
try:
response = input("\n Type 'yes' to execute this trade: ").strip().lower()
except (EOFError, KeyboardInterrupt):
print("\nTrade cancelled.")
log_trade({
"timestamp": datetime.now(timezone.utc).isoformat(),
"status": "CANCELLED",
"reason": "User did not confirm",
"token_id": args.token_id,
"side": args.side,
"size": args.size,
"price": args.price,
"amount": args.amount,
"is_market": args.market,
})
sys.exit(0)
if response != "yes":
print("Trade cancelled. You must type exactly 'yes' to confirm.")
log_trade({
"timestamp": datetime.now(timezone.utc).isoformat(),
"status": "CANCELLED",
"reason": f"User typed: {response!r}",
"token_id": args.token_id,
"side": args.side,
"size": args.size,
"price": args.price,
"amount": args.amount,
"is_market": args.market,
})
sys.exit(0)
# Execute the trade
print("\nExecuting trade...")
try:
if args.market:
result = execute_market_order(client, args.token_id, args.side, args.amount)
else:
result = execute_limit_order(client, args.token_id, args.side, args.size, args.price)
print(f"\nTrade submitted successfully!")
print(json.dumps(result, indent=2, default=str))
log_trade({
"timestamp": datetime.now(timezone.utc).isoformat(),
"status": "EXECUTED",
"token_id": args.token_id,
"side": args.side,
"size": args.size,
"price": args.price,
"amount": args.amount,
"is_market": args.market,
"cost_usd": trade_cost,
"result": result,
})
except Exception as e:
print(f"\nTrade FAILED: {e}", file=sys.stderr)
log_trade({
"timestamp": datetime.now(timezone.utc).isoformat(),
"status": "FAILED",
"error": str(e),
"token_id": args.token_id,
"side": args.side,
"size": args.size,
"price": args.price,
"amount": args.amount,
"is_market": args.market,
"cost_usd": trade_cost,
})
sys.exit(1)
if __name__ == "__main__":
main()