### Example Environment Variables Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-plan.md This file provides example environment variables required for the Polymarket trader, including API keys and dry-run settings. Ensure sensitive information is kept secure. ```env POLYMARKET_PK=0xYOUR_PRIVATE_KEY POLYMARKET_API_KEY=your-api-key POLYMARKET_API_SECRET=your-api-secret POLYMARKET_API_PASSPHRASE=your-api-passphrase BUILDER_KEY=your-builder-key BUILDER_SECRET=your-builder-secret BUILDER_PASSPHRASE=your-builder-passphrase TRADER_DRY_RUN=true ``` -------------------------------- ### Configure Client-Level Defaults for Signing Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/README.md Demonstrates setting client-level defaults for order signing, including signature type, nonce, funder address, and salt generation. This example configures these defaults and then builds a signable order. ```go client := polymarket.NewClient() authClient := client.CLOB. WithAuth(signer, nil). WithSignatureType(auth.SignatureProxy). WithAuthNonce(1). WithSaltGenerator(func() (*big.Int, error) { return big.NewInt(42), nil }) // Optional: explicit funder address for proxy/safe signatures authClient = authClient.WithFunder(common.HexToAddress("0xFunder...")) builder := clob.NewOrderBuilder(authClient, signer). TokenID("TOKEN_ID_HERE"). Side("BUY"). Price(0.5). Size(10). TickSize("0.01"). FeeRateBps(0) signable, _ := builder.BuildSignableWithContext(ctx) fmt.Println("Maker:", signable.Order.Maker.Hex()) ``` -------------------------------- ### Initialize Polymarket Trader Application Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-plan.md This Go code initializes the main entry point for the polymarket-trader application. It loads configuration, sets up the SDK client with authentication, initializes risk management and trading strategy components, and starts a trading loop that subscribes to order book updates. ```go // cmd/trader/main.go package main import ( "context" "flag" "fmt" "log" "os" "os/signal" "strings" "syscall" "time" polymarket "github.com/GoPolymarket/polymarket-go-sdk" "github.com/GoPolymarket/polymarket-go-sdk/pkg/auth" "github.com/GoPolymarket/polymarket-go-sdk/pkg/clob" "github.com/GoPolymarket/polymarket-go-sdk/pkg/clob/clobtypes" "github.com/GoPolymarket/polymarket-trader/internal/config" "github.com/GoPolymarket/polymarket-trader/internal/feed" "github.com/GoPolymarket/polymarket-trader/internal/risk" "github.com/GoPolymarket/polymarket-trader/internal/strategy" ) func main() { cfgPath := flag.String("config", "config.yaml", "path to config file") flag.Parse() // Load config cfg, err := config.LoadFile(*cfgPath) if err != nil { log.Printf("warning: config file: %v, using defaults", err) cfg = config.Default() } cfg.ApplyEnv() if cfg.PrivateKey == "" || cfg.APIKey == "" { log.Fatal("POLYMARKET_PK and POLYMARKET_API_KEY are required") } log.Printf("polymarket-trader starting (dry_run=%t)", cfg.DryRun) // Init SDK client signer, err := auth.NewPrivateKeySigner(strings.TrimSpace(cfg.PrivateKey), 137) if err != nil { log.Fatalf("signer: %v", err) } apiKey := &auth.APIKey{ Key: strings.TrimSpace(cfg.APIKey), Secret: strings.TrimSpace(cfg.APISecret), Passphrase: strings.TrimSpace(cfg.APIPassphrase), } sdkClient := polymarket.NewClient() clobClient := sdkClient.CLOB.WithAuth(signer, apiKey) // Attach Builder Code if configured if cfg.BuilderKey != "" && cfg.BuilderSecret != "" { clobClient = clobClient.WithBuilderConfig(&auth.BuilderConfig{ Local: &auth.BuilderCredentials{ Key: strings.TrimSpace(cfg.BuilderKey), Secret: strings.TrimSpace(cfg.BuilderSecret), Passphrase: strings.TrimSpace(cfg.BuilderPassphrase), }, }) log.Println("builder attribution enabled") } // Init WS + authenticate wsClient := sdkClient.CLOBWS.Authenticate(signer, apiKey) // Init components books := feed.NewBookSnapshot() riskMgr := risk.New(risk.Config{ MaxOpenOrders: cfg.Risk.MaxOpenOrders, MaxDailyLossUSDC: cfg.Risk.MaxDailyLossUSDC, MaxPositionPerMarket: cfg.Risk.MaxPositionPerMarket, }) maker := strategy.NewMaker(strategy.MakerConfig{ MinSpreadBps: cfg.Maker.MinSpreadBps, SpreadMultiplier: cfg.Maker.SpreadMultiplier, OrderSizeUSDC: cfg.Maker.OrderSizeUSDC, MaxOrdersPerMarket: cfg.Maker.MaxOrdersPerMarket, }) taker := strategy.NewTaker(strategy.TakerConfig{ MinImbalance: cfg.Taker.MinImbalance, DepthLevels: cfg.Taker.DepthLevels, AmountUSDC: cfg.Taker.AmountUSDC, MaxSlippageBps: cfg.Taker.MaxSlippageBps, Cooldown: cfg.Taker.Cooldown, }) // Context for graceful shutdown ctx, cancel := context.WithCancel(context.Background()) defer cancel() sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) // Select markets assetIDs := cfg.Maker.Markets if len(assetIDs) == 0 { log.Println("auto-selecting markets...") assetIDs, err = autoSelectMarkets(ctx, clobClient, cfg.Maker.AutoSelectTop) if err != nil { log.Fatalf("market selection: %v", err) } } if len(assetIDs) == 0 { log.Fatal("no markets selected") } log.Printf("monitoring %d assets: %v", len(assetIDs), assetIDs) // Subscribe to orderbook WS bookCh, err := wsClient.SubscribeOrderbook(ctx, assetIDs) if err != nil { log.Fatalf("ws subscribe: %v", err) } // Track active maker orders for cancel-replace activeOrders := make(map[string][]string) // assetID → []orderID log.Println("trading loop started") // Stats var totalOrders, totalFills int for { select { case <-sigCh: log.Println("shutdown signal received") goto shutdown case event, ok := <-bookCh: if !ok { log.Println("book channel closed, reconnecting...") time.Sleep(2 * time.Second) bookCh, err = wsClient.SubscribeOrderbook(ctx, assetIDs) if err != nil { log.Printf("reconnect failed: %v", err) goto shutdown } continue } books.Update(event) // --- Maker --- if cfg.Maker.Enabled { quote, err := maker.ComputeQuote(event) if err != nil { continue } // Cancel old orders for this asset if old, ok := activeOrders[event.AssetID]; ok && len(old) > 0 { _, _ = clobClient.CancelOrders(ctx, &clobtypes.CancelOrdersRequest{OrderIDs: old}) delete(activeOrders, event.AssetID) } if !cfg.DryRun { if err := riskMgr.Allow(event.AssetID, quote.Size); err != nil { continue } // Place buy buyResp := placeLimit(ctx, clobClient, signer, event.AssetID, "BUY", quote.BuyPrice, quote.Size) if buyResp.ID != "" { ``` -------------------------------- ### Linting Commands Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/CONTRIBUTING.md Commands to install and execute the project linter. ```bash # Install golangci-lint make lint-install # Run linter make lint ``` -------------------------------- ### Conventional Commit Examples Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/CONTRIBUTING.md Examples of commit messages following the conventional commits specification. ```text feat: add new order type support fix: resolve WebSocket reconnection issue docs: update API documentation test: add benchmark tests for order builder refactor: simplify error handling logic ``` -------------------------------- ### Query Balance and Allowances with Signature Type Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/README.md Fetches balance and allowance information for a specific token ID, supporting different signature types (EOA, Proxy, Safe). This example sets the signature type on the CLOB client and then queries user rewards. Replace "TOKEN_ID_HERE" with a valid token ID. ```go // Set a default signature type on the CLOB client (0=EOA, 1=Proxy, 2=Safe) clobClient := client.CLOB.WithSignatureType(auth.SignatureProxy) bal, err := clobClient.BalanceAllowance(ctx, &clobtypes.BalanceAllowanceRequest{ AssetType: clobtypes.AssetTypeConditional, TokenID: "TOKEN_ID_HERE", }) if err != nil { log.Fatal(err) } fmt.Println("Balance:", bal.Balance) fmt.Println("Allowances:", bal.Allowances) rewards, err := clobClient.UserRewardsByMarket(ctx, &clobtypes.UserRewardsByMarketRequest{ Date: "2026-01-01", OrderBy: "date", NoCompetition: true, }) if err != nil { log.Fatal(err) } fmt.Printf("User rewards: %d entries\n", len(rewards)) ``` -------------------------------- ### Clone and Initialize Repository Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/CONTRIBUTING.md Initial steps to set up the local development environment. ```bash # Fork and clone the repository git clone https://github.com/GoPolymarket/polymarket-go-sdk.git cd polymarket-go-sdk # Install dependencies go mod download # Run tests go test ./... ``` -------------------------------- ### Initialize Go Module and Project Directory Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-plan.md Sets up the project directory and initializes a Go module. Ensure you are in the desired parent directory before running. ```bash mkdir -p /Users/dongowu/code/project/project_ploymarket/polymarket-trader cd /Users/dongowu/code/project/project_ploymarket/polymarket-trader git init go mod init github.com/GoPolymarket/polymarket-trader ``` -------------------------------- ### GET /v1/leaderboard Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/api-research-report.md Retrieves the leaderboard data. ```APIDOC ## GET /v1/leaderboard ### Description Retrieves the leaderboard for a specific category and time period. ### Method GET ### Endpoint /v1/leaderboard ### Parameters #### Query Parameters - **category** (string) - Optional - **timePeriod** (string) - Optional - **orderBy** (string) - Optional - **limit** (integer) - Optional - 1-50 - **offset** (integer) - Optional - 0-1000 - **user** (string) - Optional - **userName** (string) - Optional ``` -------------------------------- ### Implement Configuration Logic Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-plan.md Core implementation of the configuration structures, default values, YAML loading, and environment variable application. ```go // internal/config/config.go package config import ( "os" "strings" "time" "gopkg.in/yaml.v3" ) type Config struct { // Auth PrivateKey string `yaml:"private_key"` APIKey string `yaml:"api_key"` APISecret string `yaml:"api_secret"` APIPassphrase string `yaml:"api_passphrase"` BuilderKey string `yaml:"builder_key"` BuilderSecret string `yaml:"builder_secret"` BuilderPassphrase string `yaml:"builder_passphrase"` // General ScanInterval time.Duration `yaml:"scan_interval"` DryRun bool `yaml:"dry_run"` LogLevel string `yaml:"log_level"` Maker MakerConfig `yaml:"maker"` Taker TakerConfig `yaml:"taker"` Risk RiskConfig `yaml:"risk"` } type MakerConfig struct { Enabled bool `yaml:"enabled"` Markets []string `yaml:"markets"` AutoSelectTop int `yaml:"auto_select_top"` MinSpreadBps float64 `yaml:"min_spread_bps"` SpreadMultiplier float64 `yaml:"spread_multiplier"` OrderSizeUSDC float64 `yaml:"order_size_usdc"` RefreshInterval time.Duration `yaml:"refresh_interval"` MaxOrdersPerMarket int `yaml:"max_orders_per_market"` } type TakerConfig struct { Enabled bool `yaml:"enabled"` Markets []string `yaml:"markets"` MinImbalance float64 `yaml:"min_imbalance"` DepthLevels int `yaml:"depth_levels"` AmountUSDC float64 `yaml:"amount_usdc"` MaxSlippageBps float64 `yaml:"max_slippage_bps"` Cooldown time.Duration `yaml:"cooldown"` MinConfidenceBps float64 `yaml:"min_confidence_bps"` } type RiskConfig struct { MaxOpenOrders int `yaml:"max_open_orders"` MaxDailyLossUSDC float64 `yaml:"max_daily_loss_usdc"` MaxPositionPerMarket float64 `yaml:"max_position_per_market"` EmergencyStop bool `yaml:"emergency_stop"` } func Default() Config { return Config{ ScanInterval: 10 * time.Second, DryRun: true, LogLevel: "info", Maker: MakerConfig{ Enabled: true, AutoSelectTop: 5, MinSpreadBps: 20, SpreadMultiplier: 1.5, OrderSizeUSDC: 25, RefreshInterval: 5 * time.Second, MaxOrdersPerMarket: 2, }, Taker: TakerConfig{ Enabled: true, MinImbalance: 0.15, DepthLevels: 3, AmountUSDC: 20, MaxSlippageBps: 30, Cooldown: 60 * time.Second, MinConfidenceBps: 25, }, Risk: RiskConfig{ MaxOpenOrders: 20, MaxDailyLossUSDC: 100, MaxPositionPerMarket: 50, }, } } func LoadFile(path string) (Config, error) { cfg := Default() data, err := os.ReadFile(path) if err != nil { return cfg, err } if err := yaml.Unmarshal(data, &cfg); err != nil { return cfg, err } return cfg, nil } func (c *Config) ApplyEnv() { if v := os.Getenv("POLYMARKET_PK"); v != "" { c.PrivateKey = v } if v := os.Getenv("POLYMARKET_API_KEY"); v != "" { c.APIKey = v } if v := os.Getenv("POLYMARKET_API_SECRET"); v != "" { c.APISecret = v } if v := os.Getenv("POLYMARKET_API_PASSPHRASE"); v != "" { c.APIPassphrase = v } ``` -------------------------------- ### GET /positions Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/api-research-report.md Retrieves the user's current positions. ```APIDOC ## GET /positions ### Description Retrieves the current positions for a specific user. ### Method GET ### Endpoint /positions ### Parameters #### Query Parameters - **user** (string) - Required - The user address - **market** (string) - Optional - Market identifier - **eventId** (string) - Optional - Event identifier - **sizeThreshold** (number) - Optional - Minimum size threshold - **redeemable** (boolean) - Optional - Filter by redeemable status - **mergeable** (boolean) - Optional - Filter by mergeable status - **limit** (integer) - Optional - 0-500 - **offset** (integer) - Optional - 0-10000 - **sortBy** (string) - Optional - Field to sort by - **sortDirection** (string) - Optional - Sort direction - **title** (string) - Optional - Filter by title ``` -------------------------------- ### Initialize Polymarket Client with Builder Configuration Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-design.md Go code snippet demonstrating how to initialize a Polymarket client and configure it for builder attribution. This involves providing authentication credentials and builder-specific configuration. ```go client := polymarket.NewClient().CLOB. WithAuth(signer, apiKey). WithBuilderConfig(&auth.BuilderConfig{ Local: &auth.BuilderCredentials{ Key: cfg.Builder.Key, Secret: cfg.Builder.Secret, Passphrase: cfg.Builder.Passphrase, }, }) // All subsequent CreateOrder calls auto-include builder attribution headers ``` -------------------------------- ### GET /markets Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/api-research-report.md Retrieves a list of markets with extensive filtering options. ```APIDOC ## GET /markets ### Description Retrieves a list of markets based on various criteria including status, tags, and market metrics. ### Method GET ### Endpoint /markets ### Parameters #### Query Parameters - **limit** (integer) - Optional - Number of results to return - **offset** (integer) - Optional - Number of results to skip - **order** (string) - Optional - Field to order by - **ascending** (boolean) - Optional - Sort order - **slug** (string) - Optional - Filter by slug - **slug[]** (array) - Optional - Filter by slugs - **id[]** (array) - Optional - Filter by market IDs - **clob_token_ids[]** (array) - Optional - Filter by CLOB token IDs - **condition_ids[]** (array) - Optional - Filter by condition IDs - **market_maker_address[]** (array) - Optional - Filter by market maker addresses - **active** (boolean) - Optional - Filter by active status - **closed** (boolean) - Optional - Filter by closed status - **tag_id** (integer) - Optional - Filter by tag ID - **tag_slug** (string) - Optional - Filter by tag slug - **related_tags** (boolean) - Optional - Include related tags - **cyom** (boolean) - Optional - Filter by CYOM status - **uma_resolution_status** (string) - Optional - Filter by UMA resolution status - **game_id** (string) - Optional - Filter by game ID - **sports_market_types[]** (array) - Optional - Filter by sports market types - **volume_min/max** (number) - Optional - Filter by volume range - **liquidity_min/max** (number) - Optional - Filter by liquidity range - **start_date_min/max** (string) - Optional - Filter by start date range - **end_date_min/max** (string) - Optional - Filter by end date range ``` -------------------------------- ### Initialize Polymarket Go SDK Client Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/README.md Initializes the Polymarket SDK client with optional WebSocket and RTDS configurations. It demonstrates setting up a private key signer and API credentials. Ensure environment variables POLYMARKET_PK, POLY_API_KEY, POLY_API_SECRET, and POLY_API_PASSPHRASE are set. ```go package main import ( "context" "fmt" "log" "os" "time" "github.com/GoPolymarket/polymarket-go-sdk" "github.com/GoPolymarket/polymarket-go-sdk/pkg/auth" "github.com/GoPolymarket/polymarket-go-sdk/pkg/clob" "github.com/GoPolymarket/polymarket-go-sdk/pkg/clob/clobtypes" "github.com/GoPolymarket/polymarket-go-sdk/pkg/clob/ws" "github.com/GoPolymarket/polymarket-go-sdk/pkg/rtds" ) func main() { // 1. Initialize Signer (Private Key or KMS) pk := os.Getenv("POLYMARKET_PK") signer, err := auth.NewPrivateKeySigner(pk, 137) // 137 = Polygon Mainnet if err != nil { log.Fatal(err) } // 2. Initialize Credentials creds := &auth.APIKey{ Key: os.Getenv("POLY_API_KEY"), Secret: os.Getenv("POLY_API_SECRET"), Passphrase: os.Getenv("POLY_API_PASSPHRASE"), } // 3. Optional: Explicit WS/RTDS runtime config (instead of env vars) wsCfg := ws.DefaultClientConfig() wsCfg.ReconnectMax = 10 wsCfg.HeartbeatInterval = 5 * time.Second rtdsCfg := rtds.DefaultClientConfig() rtdsCfg.PingInterval = 3 * time.Second // 4. Create Client (strict constructor returns init errors) client, err := polymarket.NewClientE( polymarket.WithCLOBWSConfig(wsCfg), polymarket.WithRTDSConfig(rtdsCfg), ) if err != nil { log.Printf("client initialized with partial failures: %v", err) } client = client.WithAuth(signer, creds) // 5. Check System Status status, _ := client.CLOB.Health(context.Background()) fmt.Println("System Status:", status) } ``` -------------------------------- ### GET /data/order/{orderID} Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/api-research-report.md Retrieves details for a specific order by its ID. ```APIDOC ## GET /data/order/{orderID} ### Description Retrieves details for a specific order by its ID. ### Method GET ### Endpoint /data/order/{orderID} ### Parameters #### Path Parameters - **orderID** (string) - Required - The unique identifier of the order. ``` -------------------------------- ### GET /events Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/api-research-report.md Retrieves a list of events based on various filter parameters. ```APIDOC ## GET /events ### Description Retrieves a list of events with support for pagination, ordering, and filtering by tags, status, and metrics. ### Method GET ### Endpoint /events ### Parameters #### Query Parameters - **limit** (integer) - Optional - Number of results to return - **offset** (integer) - Optional - Number of results to skip - **order** (string) - Optional - Field to order by - **ascending** (boolean) - Optional - Sort order - **id[]** (array) - Optional - Filter by event IDs - **tag_id** (integer) - Optional - Filter by tag ID - **exclude_tag_id[]** (array) - Optional - Exclude specific tag IDs - **slug[]** (array) - Optional - Filter by slugs - **tag_slug** (string) - Optional - Filter by tag slug - **related_tags** (boolean) - Optional - Include related tags - **active** (boolean) - Optional - Filter by active status - **archived** (boolean) - Optional - Filter by archived status - **featured** (boolean) - Optional - Filter by featured status - **cyom** (boolean) - Optional - Filter by CYOM status - **closed** (boolean) - Optional - Filter by closed status - **liquidity_min/max** (number) - Optional - Filter by liquidity range - **volume_min/max** (number) - Optional - Filter by volume range - **start_date_min/max** (string) - Optional - Filter by start date range - **end_date_min/max** (string) - Optional - Filter by end date range ``` -------------------------------- ### GET /v1/market-trades-events/{id} Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/api-research-report.md Retrieves recent trade events for a specific market. ```APIDOC ## GET /v1/market-trades-events/{id} ### Description Retrieves recent trade events for a specific market. ### Method GET ### Endpoint /v1/market-trades-events/{id} ### Parameters #### Path Parameters - **id** (string) - Required - The market ID. ``` -------------------------------- ### Initialize Configuration from Environment Variables Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-plan.md Reads configuration values from environment variables to populate the configuration struct. ```go if v := os.Getenv("BUILDER_KEY"); v != "" { c.BuilderKey = v } if v := os.Getenv("BUILDER_SECRET"); v != "" { c.BuilderSecret = v } if v := os.Getenv("BUILDER_PASSPHRASE"); v != "" { c.BuilderPassphrase = v } if v := os.Getenv("TRADER_DRY_RUN"); v != "" { c.DryRun = strings.EqualFold(v, "true") || v == "1" } } ``` -------------------------------- ### Create Builder API Key in Go Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/BUILDER_GUIDE.md Initializes the Polymarket client and signer, derives an L2 API key, and then creates a Builder API key. Ensure your PRIVATE_KEY environment variable is set. Save the returned credentials securely as they are only provided once. ```go package main import ( "context" "fmt" "log" "os" polymarket "github.com/GoPolymarket/polymarket-go-sdk" "github.com/GoPolymarket/polymarket-go-sdk/pkg/auth" ) func main() { // 1. Initialize Client & Signer pk := os.Getenv("PRIVATE_KEY") signer, _ := auth.NewPrivateKeySigner(pk, 137) client := polymarket.NewClient(polymarket.WithUseServerTime(true)) // 2. Derive L2 API Key (Standard Auth) l2Client := client.CLOB.WithAuth(signer, nil) apiKeyResp, _ := l2Client.DeriveAPIKey(context.Background()) apiKey := &auth.APIKey{ Key: apiKeyResp.APIKey, Secret: apiKeyResp.Secret, Passphrase: apiKeyResp.Passphrase, } // 3. Create Builder API Key // IMPORTANT: Save these credentials! You only get them once. authClient := client.CLOB.WithAuth(signer, apiKey) builderResp, err := authClient.CreateBuilderAPIKey(context.Background()) if err != nil { log.Fatal(err) } fmt.Printf("Builder Key: %s\n", builderResp.APIKey) fmt.Printf("Builder Secret: %s\n", builderResp.Secret) fmt.Printf("Builder Passphrase: %s\n", builderResp.Passphrase) } ``` -------------------------------- ### Docker Compose Configuration Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-design.md Docker Compose setup for running the trader application and an optional remote signer service. It includes service definitions, build contexts, restart policies, environment file usage, and volume mounts. ```yaml services: trader: build: . restart: unless-stopped env_file: .env volumes: - ./config.yaml:/config.yaml signer: build: context: ../go-polymarket-sdk dockerfile: cmd/signer-server/Dockerfile env_file: .env.signer ``` -------------------------------- ### Place an Order with Polymarket SDK Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/README.md Places an order using the SDK, which automatically handles EIP-712 hashing and signing. Ensure the client is initialized and authenticated. Replace "TOKEN_ID_HERE" with a valid token ID. ```go ctx := context.Background() // Create an order builder resp, err := client.CLOB.CreateOrder(ctx, clob.NewOrderBuilder(client.CLOB, signer). TokenID("TOKEN_ID_HERE"). Side("BUY"). Price(0.50). Size(100.0). OrderType(clobtypes.OrderTypeGTC). Build(), ) if err != nil { log.Fatal("Order failed:", err) } fmt.Printf("Order Placed: %s\n", resp.ID) ``` -------------------------------- ### Configure Client with Builder Credentials in Go Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/BUILDER_GUIDE.md Applies your created Builder API Key credentials to the client. All subsequent orders made using the 'tradingClient' will be attributed to your builder account. Replace placeholders with your actual Builder Key, Secret, and Passphrase. ```go // ... inside main ... // Create a Builder Config with your credentials myBuilderConfig := &auth.BuilderConfig{ Local: &auth.BuilderCredentials{ Key: "YOUR_BUILDER_KEY", Secret: "YOUR_BUILDER_SECRET", Passphrase: "YOUR_BUILDER_PASSPHRASE", }, } // Apply the config to the client // All subsequent orders created with 'tradingClient' will be attributed to you. tradingClient := authClient.WithBuilderConfig(myBuilderConfig) // Example: Create an order resp, err := tradingClient.CreateOrder(ctx, &clobtypes.Order{ TokenID: "...", Price: 0.5, Size: 100, Side: clobtypes.Buy, OrderType: clobtypes.Limit, }) ``` -------------------------------- ### Run Tests and Benchmarks Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/CONTRIBUTING.md Commands for executing the test suite and performance benchmarks. ```bash # Run all tests make test # Run with coverage make coverage # Run benchmarks go test -bench=. ./pkg/clob/... ``` -------------------------------- ### Add SDK and YAML Dependencies Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-plan.md Fetches the latest version of the Polymarket Go SDK and the YAML v3 library, essential for project dependencies. ```bash go get github.com/GoPolymarket/polymarket-go-sdk@latest go get gopkg.in/yaml.v3 ``` -------------------------------- ### Run Configuration Tests Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-plan.md Command to execute unit tests for the configuration package. ```bash go test ./internal/config/ -v ``` -------------------------------- ### Run Polymarket Bot with Live Execution and Skip Confirmation Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/examples/bot/README.md Execute the Polymarket Bot with live order placement and skip the manual confirmation prompt. Use with caution. ```bash go run ./cmd/polymarket-bot --execute --yes ``` -------------------------------- ### Implement production-ready error handling in Go Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/ERROR_HANDLING.md Demonstrates a retry loop with exponential backoff for rate limits and immediate termination for terminal error states. ```go // Example: Production-ready error handling func placeOrder(ctx context.Context, client clob.Client, order *clobtypes.Order) (*clobtypes.OrderResponse, error) { maxRetries := 3 for i := 0; i < maxRetries; i++ { resp, err := client.CreateOrder(ctx, order) if err == nil { return resp, nil } switch { case errors.Is(err, sdkerrors.ErrRateLimitExceeded): time.Sleep(time.Duration(i+1) * time.Second) continue case errors.Is(err, sdkerrors.ErrInsufficientFunds), errors.Is(err, sdkerrors.ErrMarketClosed), errors.Is(err, sdkerrors.ErrGeoblocked): return nil, err default: return nil, err } } return nil, fmt.Errorf("failed after %d retries: %w", maxRetries, err) } ``` -------------------------------- ### Configure Remote Signing for Builder Attribution in Go Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/BUILDER_GUIDE.md Sets up the client to use a remote signing service for builder attribution. This is useful for platforms where users trade via your UI and you don't want to expose their private keys. The SDK will send the order payload to the specified host for signing. ```go remoteConfig := &auth.BuilderConfig{ Remote: &auth.BuilderRemoteConfig{ Host: "https://your-signer-service.com", // The SDK will send the order payload to this host to get the builder signature }, } client := client.WithBuilderConfig(remoteConfig) ``` -------------------------------- ### Run Polymarket Bot with Live Execution Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/examples/bot/README.md Execute the Polymarket Bot with live order placement enabled. This requires manual confirmation before trades are sent. ```bash go run ./cmd/polymarket-bot --execute ``` -------------------------------- ### Implement Maker Strategy Logic Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-plan.md Core implementation for calculating dynamic spreads and generating quotes based on orderbook data. ```go // internal/strategy/maker.go package strategy import ( "fmt" "math" "strconv" "github.com/GoPolymarket/polymarket-go-sdk/pkg/clob/ws" ) type MakerConfig struct { MinSpreadBps float64 SpreadMultiplier float64 OrderSizeUSDC float64 MaxOrdersPerMarket int } type Quote struct { AssetID string BuyPrice float64 SellPrice float64 Size float64 } type Maker struct { cfg MakerConfig } func NewMaker(cfg MakerConfig) *Maker { return &Maker{cfg: cfg} } func (m *Maker) ComputeQuote(book ws.OrderbookEvent) (Quote, error) { if len(book.Bids) == 0 || len(book.Asks) == 0 { return Quote{}, fmt.Errorf("empty book for %s", book.AssetID) } bestBid, err := strconv.ParseFloat(book.Bids[0].Price, 64) if err != nil { return Quote{}, fmt.Errorf("bad bid price: %w", err) } bestAsk, err := strconv.ParseFloat(book.Asks[0].Price, 64) if err != nil { return Quote{}, fmt.Errorf("bad ask price: %w", err) } if bestAsk <= bestBid { return Quote{}, fmt.Errorf("crossed book: bid=%f ask=%f", bestBid, bestAsk) } mid := (bestBid + bestAsk) / 2 marketSpreadBps := (bestAsk - bestBid) / mid * 10000 // Dynamic half spread: use market spread * multiplier, but enforce minimum halfSpreadBps := math.Max(m.cfg.MinSpreadBps/2, marketSpreadBps*m.cfg.SpreadMultiplier/2) halfSpread := mid * halfSpreadBps / 10000 buyPrice := mid - halfSpread sellPrice := mid + halfSpread // Clamp to valid range if buyPrice <= 0 { buyPrice = 0.01 } if sellPrice >= 1 { sellPrice = 0.99 } return Quote{ AssetID: book.AssetID, BuyPrice: buyPrice, SellPrice: sellPrice, Size: m.cfg.OrderSizeUSDC, }, nil } ``` -------------------------------- ### Compile the Trader Application Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-plan.md Compiles the Go application. This command should execute without errors if the project is set up correctly. ```bash go build ./cmd/trader/ ``` -------------------------------- ### Test Configuration Loading and Overrides Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-plan.md Unit tests for verifying default configuration values, YAML file parsing, and environment variable overrides. ```go // internal/config/config_test.go package config import ( "os" "testing" "time" ) func TestLoadDefaults(t *testing.T) { cfg := Default() if cfg.Maker.MinSpreadBps <= 0 { t.Fatal("expected positive min spread bps") } if cfg.Risk.MaxOpenOrders <= 0 { t.Fatal("expected positive max open orders") } if cfg.ScanInterval <= 0 { t.Fatal("expected positive scan interval") } } func TestLoadFromYAML(t *testing.T) { yaml := ` scan_interval: 30s maker: enabled: false order_size_usdc: 50 taker: min_imbalance: 0.2 risk: max_daily_loss_usdc: 200 ` f, err := os.CreateTemp("", "config-*.yaml") if err != nil { t.Fatal(err) } defer os.Remove(f.Name()) f.Write([]byte(yaml)) f.Close() cfg, err := LoadFile(f.Name()) if err != nil { t.Fatal(err) } if cfg.Maker.Enabled { t.Fatal("expected maker disabled") } if cfg.Maker.OrderSizeUSDC != 50 { t.Fatalf("expected order size 50, got %f", cfg.Maker.OrderSizeUSDC) } if cfg.Taker.MinImbalance != 0.2 { t.Fatalf("expected min imbalance 0.2, got %f", cfg.Taker.MinImbalance) } if cfg.Risk.MaxDailyLossUSDC != 200 { t.Fatalf("expected max daily loss 200, got %f", cfg.Risk.MaxDailyLossUSDC) } if cfg.ScanInterval != 30*time.Second { t.Fatalf("expected 30s scan interval, got %v", cfg.ScanInterval) } } func TestEnvOverride(t *testing.T) { t.Setenv("TRADER_DRY_RUN", "false") cfg := Default() cfg.ApplyEnv() if cfg.DryRun { t.Fatal("expected dry run false from env") } } ``` -------------------------------- ### Switch to Builder Mode After Auth in Go Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/BUILDER_GUIDE.md If an authenticated client already exists and heartbeats are active, use `PromoteToBuilder`. This applies builder headers immediately and restarts heartbeats with the new attribution configuration without re-initializing the client. ```go builderClient := authClient.PromoteToBuilder(myBuilderConfig) ``` -------------------------------- ### Dockerfile for Polymarket Trader Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-plan.md This Dockerfile builds a multi-stage Go application. It first compiles the trader binary and then creates a lean final image containing only the binary and configuration file. ```dockerfile FROM golang:1.24-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 go build -o /trader ./cmd/trader/ FROM alpine:3.19 RUN apk add --no-cache ca-certificates COPY --from=builder /trader /trader COPY config.yaml /config.yaml ENTRYPOINT ["/trader"] ``` -------------------------------- ### Docker Build Command Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-plan.md This command builds the Docker image for the Polymarket trader, tagging it as 'polymarket-trader'. Ensure this command executes successfully. ```bash docker build -t polymarket-trader . ``` -------------------------------- ### Commit Initial Project Scaffold Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-plan.md Stages all new and modified files and commits them with a descriptive message. This is a standard practice for version control. ```bash git add -A git commit -m "feat: scaffold polymarket-trader project" ``` -------------------------------- ### Run Go Tests Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/SECURITY_AUDIT.md Execute all Go tests to validate correctness and regression coverage. Ensure all dependencies are available. ```bash go test ./... ``` -------------------------------- ### Dockerfile for Trader Application Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-design.md A multi-stage Dockerfile to build a lean Go application. It uses a Go Alpine image for building and a minimal Alpine image for the final runtime, resulting in a small final image size. ```dockerfile FROM golang:1.24-alpine AS builder COPY . . RUN CGO_ENABLED=0 go build -o /trader ./cmd/trader/ FROM alpine:3.19 COPY --from=builder /trader /trader COPY config.yaml /config.yaml ENTRYPOINT ["/trader"] ``` -------------------------------- ### Run Unit Tests Command Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-plan.md This command executes all unit tests for the project with verbose output, race detection, and without caching. All tests should pass. ```bash go test ./... -v -race -count=1 ``` -------------------------------- ### Project Directory Structure Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/CONTRIBUTING.md Overview of the repository file organization. ```text polymarket-go-sdk/ ├── cmd/ # CLI tools ├── docs/ # Documentation ├── examples/ # Usage examples ├── pkg/ │ ├── auth/ # Authentication (signing, keys) │ ├── bot/ # Trading bot utilities │ ├── bridge/ # Cross-chain bridging │ ├── clob/ # CLOB API client │ │ └── ws/ # WebSocket client │ ├── ctf/ # Conditional Token Framework │ ├── data/ # Data API client │ ├── errors/ # Error definitions │ ├── gamma/ # Gamma API client │ ├── rtds/ # Real-time data streaming │ ├── transport/ # HTTP transport layer │ └── types/ # Shared types ``` -------------------------------- ### Makefile for Trader Project Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-plan.md Provides common build, run, test, and clean commands for the Polymarket trader application. Use 'make build' to compile and 'make run' to execute. ```makefile .PHONY: build run test clean build: go build -o bin/trader ./cmd/trader/ run: go run ./cmd/trader/ test: go test ./... -v -race -count=1 clean: rm -rf bin/ ``` -------------------------------- ### Run Polymarket Bot Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/examples/bot/README.md Execute the Polymarket Bot for market scanning and analysis. Ensure required environment variables are set. ```bash go run ./cmd/polymarket-bot ``` -------------------------------- ### Minimal main.go for Polymarket Trader Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-plan.md A basic Go program that prints a startup message and exits. This serves as the entry point for the trader application. ```go // cmd/trader/main.go package main import ( "fmt" "os" ) func main() { fmt.Println("polymarket-trader starting...") os.Exit(0) } ``` -------------------------------- ### Initialize AWS KMS Signer for Polymarket SDK Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/SECURITY.md Integrates AWS KMS for signing EIP-712 orders without exporting private keys. Ensure AWS credentials and KMS key alias are correctly configured. ```go import "github.com/GoPolymarket/polymarket-go-sdk/pkg/auth/kms" // 1. Initialize AWS KMS Client cfg, _ := config.LoadDefaultConfig(ctx) kmsClient := kms.NewFromConfig(cfg) // 2. Create the Signer // The SDK automatically fetches the public key to verify the signature recovery ID (V). signer, _ := kms.NewAWSSigner(ctx, kmsClient, "alias/my-trading-key", 137) // 3. Use it client := polymarket.NewClient().WithAuth(signer, apiKey) ``` -------------------------------- ### Default YAML Configuration Template Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-plan.md Template file defining default settings for maker, taker, and risk management parameters. ```yaml # config.yaml — polymarket-trader default configuration scan_interval: 10s dry_run: true log_level: info maker: enabled: true markets: [] # empty = auto-select auto_select_top: 5 min_spread_bps: 20 spread_multiplier: 1.5 order_size_usdc: 25 refresh_interval: 5s max_orders_per_market: 2 taker: enabled: true markets: [] min_imbalance: 0.15 depth_levels: 3 amount_usdc: 20 max_slippage_bps: 30 cooldown: 60s min_confidence_bps: 25 risk: max_open_orders: 20 max_daily_loss_usdc: 100 max_position_per_market: 50 emergency_stop: false ``` -------------------------------- ### Fetch All Markets with Auto-Pagination Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/README.md Retrieves all active markets using the SDK's auto-pagination feature, eliminating the need for manual cursor handling. Ensure the client is initialized and authenticated. ```go // Automatically iterates through all pages allMarkets, err := client.CLOB.MarketsAll(ctx, &clobtypes.MarketsRequest{ Active: boolPtr(true), }) if err != nil { log.Fatal(err) } fmt.Printf("Fetched %d active markets\n", len(allMarkets)) ``` -------------------------------- ### Trading Loop Implementation Source: https://github.com/gopolymarket/polymarket-go-sdk/blob/main/docs/plans/2026-02-24-polymarket-trader-plan.md This code implements the main trading loop, handling maker and taker strategies, order management, and shutdown procedures. It logs trading activity and PnL. ```go func main() { // ... other setup ... for { select { case <-ctx.Done(): goto shutdown case event := <-eventStream: // --- Maker --- if cfg.Maker.Enabled { quote, err := maker.Evaluate(event) if err != nil || quote == nil { continue } if !cfg.DryRun { // Place buy buyResp := placeLimit(ctx, clobClient, signer, event.AssetID, "BUY", quote.BuyPrice, quote.Size) if buyResp.ID != "" { acti veOrders[event.AssetID] = append(activeOrders[event.AssetID], buyResp.ID) totalOrders++ } // Place sell sellResp := placeLimit(ctx, clobClient, signer, event.AssetID, "SELL", quote.SellPrice, quote.Size) if sellResp.ID != "" { acti veOrders[event.AssetID] = append(activeOrders[event.AssetID], sellResp.ID) totalOrders++ } } else { log.Printf("[DRY] maker %s: buy=%.4f sell=%.4f size=%.2f", event.AssetID, quote.BuyPrice, quote.SellPrice, quote.Size) } } // --- Taker --- if cfg.Taker.Enabled { sig, err := taker.Evaluate(event) if err != nil || sig == nil { continue } if !cfg.DryRun { if err := riskMgr.Allow(event.AssetID, sig.AmountUSDC); err != nil { continue } resp := placeMarket(ctx, clobClient, signer, sig.AssetID, sig.Side, sig.AmountUSDC, sig.MaxPrice) if resp.ID != "" { taker.RecordTrade(sig.AssetID) totalFills++ } } else { log.Printf("[DRY] taker %s: side=%s amount=%.2f imbalance=%.4f", sig.AssetID, sig.Side, sig.AmountUSDC, sig.Imbalance) } } } } shutdown: log.Println("shutting down...") if !cfg.DryRun { log.Println("cancelling all open orders...") resp, err := clobClient.CancelAll(ctx) if err != nil { log.Printf("cancel all error: %v", err) } else { log.Printf("cancelled %d orders", resp.Count) } } _ = wsClient.Close() log.Printf("session complete: orders=%d fills=%d pnl=%.2f", totalOrders, totalFills, riskMgr.DailyPnL()) } ```