068b2adc75
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>
202 lines
5.6 KiB
Python
Executable File
202 lines
5.6 KiB
Python
Executable File
#!/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()
|