nothing-ever-happens Polymarket Bot

repository·main·Indexed 21 days ago

https://github.com/sterlingcrispin/nothing-ever-happens

An asynchronous Python bot for Polymarket that automatically executes 'No' trades on standalone non-sports yes/no markets when prices fall below a specific threshold. It features a runtime supervisor for managing trading strategies, recovery workers, and fund redeemers, with support for both paper trading and live mode deployment on Heroku.

Tokens
1.6K
Snippets
5
Records
11
Agent score
26%

What's inside nothing-ever-happens

  1. Enable live trading mode

    main

    The bot defaults to using PaperExchangeClient for safety. To enable real order transmission, you must satisfy two conditions:

    1. Required Runtime Flags

    You must set all three of the following environment variables:

    • BOT_MODE=live
    • LIVE_TRADING_ENABLED=true
    • DRY_RUN=false

    2. Required Secrets and Infrastructure

    Once live mode is enabled, the following variables are also required:

    • PRIVATE_KEY: For signing transactions.
    • FUNDER_ADDRESS: Required for signature types 1 and 2.
    • DATABASE_URL: For state persistence.
    • POLYGON_RPC_URL: Required for proxy-wallet approvals and redemptions.
  2. Deploy to Heroku

    main

    To deploy the bot to Heroku, follow these steps to configure the environment and push the code.

    1. Set Runtime and Secret Configs

    Use the Heroku CLI to set the necessary environment variables for live trading:

    # Set trading flags
    heroku config:set BOT_MODE=live DRY_RUN=false LIVE_TRADING_ENABLED=true -a "$HEROKU_APP_NAME"
    
    # Set secrets
    heroku config:set PRIVATE_KEY=<key> FUNDER_ADDRESS=<addr> POLYGON_RPC_URL=<url> DATABASE_URL=<url> -a "$HEROKU_APP_NAME"

    2. Deploy and Scale

    Push your branch to Heroku and scale only the web dyno. The worker dyno should remain at 0 to prevent accidental execution.

    git push heroku <branch>:main
    heroku ps:scale web=1 worker=0 -a "$HEROKU_APP_NAME"
  3. Configure live trading and recovery requirements

    main

    When running in live mode (exchange_cfg.live_send_enabled is true), the runtime enforces several strict requirements:

    1. Database Requirement: A DATABASE_URL must be provided. The bot uses this to initialize the trade ledger via init_db.
    2. Durable Recovery: If live_send_enabled is true, the LiveRecoveryCoordinator must be enabled. If it is not enabled, the runtime will raise a RuntimeError.
    3. Wallet Derivation: The wallet address is derived based on the signature_type:
      • If signature_type is 1 or 2, it uses exchange_cfg.funder_address.
      • If signature_type is 0, it derives the address from exchange_cfg.private_key using eth_account.
    4. Redeemer Requirements: For the Redeemer to run, you must provide a POLYGON_RPC_URL and ensure the configuration includes a private_key, funder_address, and signature_type == 2.
  4. How the nothing-happens runtime supervisor works

    main

    The run() function in bot/main.py acts as an async supervisor that manages the lifecycle of several key components through asyncio.Task objects.

    Managed Tasks

    • strategy: The core nothing_happens.run loop that executes trading logic.
    • ambiguous_recovery: (Live mode only) A LiveRecoveryCoordinator worker to handle state recovery.
    • redeemer: (If configured) A task to handle fund redemption.
    • dashboard: (If PORT or DASHBOARD_PORT is set) A web server for monitoring.
    • heartbeat: A periodic task that logs the current state of the PortfolioState and NothingHappensControlState every 60 seconds.
    • supervisor: A management task that monitors other tasks. If a task crashes, the supervisor attempts to restart it up to 1,000 times within a health_reset_sec (3600s) window.

    Lifecycle & Shutdown

    When a shutdown signal (SIGINT or SIGTERM) is received, the supervisor triggers a graceful shutdown sequence:

    1. The shutdown event is set.
    2. The strategy task is given a 5-second window to finish before being cancelled.
    3. All other tasks are cancelled.
    4. The ThreadPoolExecutor used for background tasks is shut down.
  5. Configure the bot runtime

    main

    The bot uses two separate files for configuration:

    1. config.json: Used for non-secret runtime settings. These settings are located under the strategies.nothing_happens key. You can override the default config location by setting the CONFIG_PATH environment variable.
    2. .env: Used for secrets and runtime flags.

    config.json is intended to be kept local and should not be committed to version control.

    # Example: Pointing to a custom config file
    export CONFIG_PATH=/path/to/config.json
  6. Run the nothing-happens bot

    main

    The bot is executed by calling the main() function in bot/main.py. This initializes the environment, loads configurations, sets up logging, patches HTTP timeouts, and starts the asynchronous supervisor loop. The supervisor manages several concurrent tasks including the strategy engine, recovery workers, redeemers, and an optional dashboard.

    To run the bot, ensure your environment variables (like DATABASE_URL, PRIVATE_KEY, etc.) are configured, then execute the script.

    python -m bot.main
  7. Use operational helper scripts

    main

    The repository includes several scripts for managing deployed instances and inspecting data:

    ScriptPurpose
    scripts/db_stats.pyInspect live database table counts and recent activity
    scripts/export_db.pyExport live tables from DATABASE_URL or a Heroku app
    scripts/wallet_history.pyPull positions, trades, and balances for the configured wallet
    scripts/parse_logs.pyConvert Heroku JSON logs into readable terminal or HTML output

    For Heroku-specific helpers (like ./alive.sh, ./logs.sh, ./kill.sh), ensure HEROKU_APP_NAME is exported in your shell.

  8. Reference: Runtime Environment Variables

    main

    The following environment variables are used by the bot/main.py entrypoint to configure the runtime behavior:

    VariableDescription
    LOG_LEVELSets the logging level (defaults to INFO).
    DATABASE_URLRequired for live trading to enable the trade ledger and recovery.
    PM_BACKGROUND_EXECUTOR_WORKERSNumber of workers for the ThreadPoolExecutor (defaults to 8).
    POLYGON_RPC_URLRequired for the Redeemer in live mode.
    PORT or DASHBOARD_PORTThe port on which the DashboardServer will run.
    dotenvThe bot calls load_dotenv() to load variables from a .env file.