Add health check, backtest, correlation tracker, wallet setup, and skills registry
New scripts: - health_check.py: one-command session-start workflow (portfolio + live prices + drawdown + stop losses → GREEN/YELLOW/RED status) - backtest.py: performance analysis with live-readiness assessment against CLAUDE.md prerequisites (20+ trades, >55% win rate, Sharpe >0.5) - correlation_tracker.py: detects hidden correlated exposure in portfolio (e.g., 3 insider-trading bets = one cluster) - setup_wallet.py: burner wallet creation, env var verification, on-chain balance check for live trading setup Also adds: - .env.example template for live trading configuration - .well-known/skills/index.json for Agent Skills registry discovery - Updated SKILL.md files documenting new scripts - .gitignore entries for .env, .polymarket-live/, and key files Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
81f0c9965f
commit
22fcb4355b
@@ -0,0 +1,268 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Polymarket Live Trading — Wallet Setup & Verification
|
||||
|
||||
Creates a burner wallet OR verifies an existing configuration.
|
||||
Run this BEFORE your first live trade.
|
||||
|
||||
Usage:
|
||||
python setup_wallet.py --create # Generate new burner wallet
|
||||
python setup_wallet.py --verify # Check existing env vars
|
||||
python setup_wallet.py --check-balance # Verify on-chain USDC balance
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import stat
|
||||
from pathlib import Path
|
||||
|
||||
# Polygon USDC contract
|
||||
USDC_CONTRACT = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174"
|
||||
POLYGON_RPC = "https://polygon-rpc.com"
|
||||
|
||||
|
||||
def create_wallet():
|
||||
"""Generate a new burner wallet and output setup instructions."""
|
||||
try:
|
||||
from eth_account import Account
|
||||
except ImportError:
|
||||
print("ERROR: eth_account not installed.")
|
||||
print("Install with: pip install eth-account")
|
||||
print("")
|
||||
print("Alternative: use 'cast wallet new' (Foundry) or MetaMask.")
|
||||
sys.exit(1)
|
||||
|
||||
acct = Account.create()
|
||||
address = acct.address
|
||||
private_key = acct.key.hex()
|
||||
|
||||
print("=" * 60)
|
||||
print(" NEW BURNER WALLET CREATED")
|
||||
print("=" * 60)
|
||||
print(f" Address: {address}")
|
||||
print(f" Private Key: {private_key}")
|
||||
print("=" * 60)
|
||||
print("")
|
||||
print("SAVE THE PRIVATE KEY NOW — it cannot be recovered.")
|
||||
print("")
|
||||
print("Next steps:")
|
||||
print(f" 1. Fund {address} with USDC on Polygon")
|
||||
print(" - Start with $25 or less (First Time tier)")
|
||||
print(" - Send ~0.1 MATIC for gas fees")
|
||||
print(" 2. Set up your .env file:")
|
||||
print("")
|
||||
|
||||
env_path = Path(__file__).parent.parent / ".env"
|
||||
example_path = Path(__file__).parent.parent / ".env.example"
|
||||
|
||||
if not env_path.exists() and example_path.exists():
|
||||
print(f" cp {example_path} {env_path}")
|
||||
print(f" chmod 600 {env_path}")
|
||||
print(f" # Edit {env_path} and paste your private key")
|
||||
else:
|
||||
print(f" export POLYMARKET_PRIVATE_KEY={private_key}")
|
||||
print(" export POLYMARKET_CONFIRM=true")
|
||||
print(" export POLYMARKET_MAX_SIZE=5")
|
||||
print(" export POLYMARKET_DAILY_LOSS_LIMIT=10")
|
||||
|
||||
print("")
|
||||
print(" 3. Verify setup:")
|
||||
print(" python setup_wallet.py --verify")
|
||||
print("")
|
||||
print("SECURITY REMINDERS:")
|
||||
print(" - This is a BURNER wallet — only fund what you can lose")
|
||||
print(" - NEVER use your main wallet's private key")
|
||||
print(" - NEVER commit .env to git")
|
||||
print(" - NEVER paste the private key into chat")
|
||||
|
||||
|
||||
def verify_config():
|
||||
"""Check that all required env vars are set and valid."""
|
||||
print("=" * 60)
|
||||
print(" LIVE TRADING CONFIGURATION CHECK")
|
||||
print("=" * 60)
|
||||
print("")
|
||||
|
||||
checks = []
|
||||
|
||||
# Check POLYMARKET_PRIVATE_KEY
|
||||
pk = os.environ.get("POLYMARKET_PRIVATE_KEY", "")
|
||||
if not pk:
|
||||
checks.append(("POLYMARKET_PRIVATE_KEY", "MISSING", "Not set"))
|
||||
elif not pk.startswith("0x") or len(pk) != 66:
|
||||
checks.append(("POLYMARKET_PRIVATE_KEY", "INVALID", "Must be 0x + 64 hex chars"))
|
||||
else:
|
||||
masked = pk[:6] + "..." + pk[-4:]
|
||||
checks.append(("POLYMARKET_PRIVATE_KEY", "OK", f"Set ({masked})"))
|
||||
|
||||
# Check POLYMARKET_CONFIRM
|
||||
confirm = os.environ.get("POLYMARKET_CONFIRM", "")
|
||||
if confirm != "true":
|
||||
checks.append(("POLYMARKET_CONFIRM", "MISSING", f"Got '{confirm}', need 'true'"))
|
||||
else:
|
||||
checks.append(("POLYMARKET_CONFIRM", "OK", "Safety gate enabled"))
|
||||
|
||||
# Check POLYMARKET_MAX_SIZE
|
||||
max_size = os.environ.get("POLYMARKET_MAX_SIZE", "")
|
||||
if not max_size:
|
||||
checks.append(("POLYMARKET_MAX_SIZE", "DEFAULT", "Not set, will use $10 default"))
|
||||
else:
|
||||
try:
|
||||
val = float(max_size)
|
||||
tier = "First time" if val <= 5 else "Learning" if val <= 10 else "Experienced" if val <= 50 else "Advanced"
|
||||
checks.append(("POLYMARKET_MAX_SIZE", "OK", f"${val:.0f} per trade ({tier} tier)"))
|
||||
except ValueError:
|
||||
checks.append(("POLYMARKET_MAX_SIZE", "INVALID", f"Got '{max_size}', need a number"))
|
||||
|
||||
# Check POLYMARKET_DAILY_LOSS_LIMIT
|
||||
dll = os.environ.get("POLYMARKET_DAILY_LOSS_LIMIT", "")
|
||||
if not dll:
|
||||
checks.append(("POLYMARKET_DAILY_LOSS_LIMIT", "DEFAULT", "Not set, will use $50 default"))
|
||||
else:
|
||||
try:
|
||||
val = float(dll)
|
||||
checks.append(("POLYMARKET_DAILY_LOSS_LIMIT", "OK", f"${val:.0f} daily limit"))
|
||||
except ValueError:
|
||||
checks.append(("POLYMARKET_DAILY_LOSS_LIMIT", "INVALID", f"Got '{dll}', need a number"))
|
||||
|
||||
# Check .env file permissions
|
||||
env_path = Path(__file__).parent.parent / ".env"
|
||||
if env_path.exists():
|
||||
mode = oct(stat.S_IMODE(env_path.stat().st_mode))
|
||||
if mode == "0o600":
|
||||
checks.append((".env permissions", "OK", f"{mode} (owner read/write only)"))
|
||||
else:
|
||||
checks.append((".env permissions", "WARN", f"{mode} — should be 0o600. Run: chmod 600 {env_path}"))
|
||||
else:
|
||||
checks.append((".env file", "INFO", "No .env file found (using shell env vars)"))
|
||||
|
||||
# Check .gitignore
|
||||
gitignore_path = Path(__file__).parent.parent.parent / ".gitignore"
|
||||
if gitignore_path.exists():
|
||||
content = gitignore_path.read_text()
|
||||
if ".env" in content:
|
||||
checks.append((".gitignore", "OK", ".env is gitignored"))
|
||||
else:
|
||||
checks.append((".gitignore", "WARN", ".env NOT in .gitignore — add it!"))
|
||||
|
||||
# Print results
|
||||
all_ok = True
|
||||
for name, status, detail in checks:
|
||||
icon = {"OK": "+", "MISSING": "X", "INVALID": "X", "WARN": "!", "DEFAULT": "~", "INFO": "-"}
|
||||
print(f" [{icon.get(status, '?')}] {name}: {detail}")
|
||||
if status in ("MISSING", "INVALID"):
|
||||
all_ok = False
|
||||
|
||||
print("")
|
||||
if all_ok:
|
||||
print(" STATUS: READY for live trading")
|
||||
print("")
|
||||
print(" Before your first trade, also run:")
|
||||
print(" python setup_wallet.py --check-balance")
|
||||
print(" python check_positions.py --balance")
|
||||
else:
|
||||
print(" STATUS: NOT READY — fix the issues above")
|
||||
|
||||
return all_ok
|
||||
|
||||
|
||||
def check_balance():
|
||||
"""Query on-chain USDC balance for the configured wallet."""
|
||||
pk = os.environ.get("POLYMARKET_PRIVATE_KEY", "")
|
||||
if not pk or not pk.startswith("0x") or len(pk) != 66:
|
||||
print("ERROR: POLYMARKET_PRIVATE_KEY not set or invalid.")
|
||||
print("Run: python setup_wallet.py --verify")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
from eth_account import Account
|
||||
acct = Account.from_key(pk)
|
||||
address = acct.address
|
||||
except ImportError:
|
||||
print("ERROR: eth_account not installed. pip install eth-account")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
import requests
|
||||
except ImportError:
|
||||
print("ERROR: requests not installed. pip install requests")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Checking balance for: {address}")
|
||||
print("")
|
||||
|
||||
# Check MATIC balance
|
||||
payload = {
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_getBalance",
|
||||
"params": [address, "latest"],
|
||||
"id": 1,
|
||||
}
|
||||
try:
|
||||
resp = requests.post(POLYGON_RPC, json=payload, timeout=10)
|
||||
result = resp.json().get("result", "0x0")
|
||||
matic_wei = int(result, 16)
|
||||
matic = matic_wei / 1e18
|
||||
matic_status = "OK" if matic >= 0.01 else "LOW — need ~0.1 MATIC for gas"
|
||||
print(f" MATIC: {matic:.4f} ({matic_status})")
|
||||
except Exception as e:
|
||||
print(f" MATIC: ERROR fetching — {e}")
|
||||
|
||||
# Check USDC balance (ERC20 balanceOf)
|
||||
# balanceOf(address) selector = 0x70a08231
|
||||
padded_addr = address[2:].lower().zfill(64)
|
||||
payload = {
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_call",
|
||||
"params": [
|
||||
{"to": USDC_CONTRACT, "data": f"0x70a08231{padded_addr}"},
|
||||
"latest",
|
||||
],
|
||||
"id": 2,
|
||||
}
|
||||
try:
|
||||
resp = requests.post(POLYGON_RPC, json=payload, timeout=10)
|
||||
result = resp.json().get("result", "0x0")
|
||||
usdc_raw = int(result, 16)
|
||||
usdc = usdc_raw / 1e6 # USDC has 6 decimals
|
||||
tier = "First time" if usdc <= 25 else "Learning" if usdc <= 100 else "Experienced" if usdc <= 500 else "Advanced"
|
||||
print(f" USDC: ${usdc:.2f} ({tier} tier)")
|
||||
except Exception as e:
|
||||
print(f" USDC: ERROR fetching — {e}")
|
||||
|
||||
print("")
|
||||
print("If balance is zero, fund the wallet:")
|
||||
print(f" Send USDC (Polygon) to: {address}")
|
||||
print(" Send ~0.1 MATIC for gas fees")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Polymarket live trading wallet setup and verification"
|
||||
)
|
||||
group = parser.add_mutually_exclusive_group(required=True)
|
||||
group.add_argument(
|
||||
"--create", action="store_true", help="Generate a new burner wallet"
|
||||
)
|
||||
group.add_argument(
|
||||
"--verify", action="store_true", help="Verify existing env var configuration"
|
||||
)
|
||||
group.add_argument(
|
||||
"--check-balance",
|
||||
action="store_true",
|
||||
help="Check on-chain USDC and MATIC balance",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.create:
|
||||
create_wallet()
|
||||
elif args.verify:
|
||||
verify_config()
|
||||
elif args.check_balance:
|
||||
check_balance()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user