◈   ⌘ api · Intermediate

Uniswap V3 SDK Python: Build DeFi Trading Bots Like a Pro

Learn how to use the Uniswap V3 SDK in Python to query pool data, automate swaps, and build DeFi bots. Covers fees, API setup, and real trading examples.

Uncle Solieditor · voc · 06.05.2026 ·views 13
◈   Contents
  1. → Uniswap V3 Explained: What Makes It Different
  2. → Setting Up the Uniswap V3 Python SDK
  3. → Using the Uniswap V3 API in Python to Fetch Pool Data
  4. → Understanding Uniswap V3 Fees and How to Factor Them Into Code
  5. → Building a Real-Time Price Monitor and Signal Layer
  6. → Executing Swaps Programmatically with the Python SDK
  7. → Frequently Asked Questions
  8. → Where to Go From Here

Uniswap V3 changed the game for decentralized trading — and Python gives you the keys to interact with it programmatically. Whether you want to monitor pool prices, automate swaps, or build a full liquidity management system, the Uniswap V3 SDK in Python is your entry point. Centralized exchanges like Binance and Coinbase offer clean REST APIs, but DeFi operates differently — you talk directly to smart contracts on-chain. That shift in mental model is what this guide is here to bridge.

Uniswap V3 Explained: What Makes It Different

If you've used Uniswap V2 or traded on platforms like Bybit or OKX, you're used to straightforward price execution. Uniswap V3 introduced a concept called concentrated liquidity — and it fundamentally changes how the protocol works under the hood.

In V2, liquidity was spread uniformly across all possible prices from zero to infinity. In V3, liquidity providers pick a price range — say ETH between $2,800 and $3,200 — and their capital only works within that range. This means that when the price is inside your range, you earn fees much more efficiently than V2. When the price moves outside, you stop earning and hold a single asset (the cheaper one).

Think of it like a market maker on Binance who only quotes prices between two specific levels instead of maintaining a ladder across the entire order book. More capital efficiency, more precision, more complexity.

Key Takeaway: Uniswap V3's concentrated liquidity makes it more capital-efficient, but also more technically complex. If you want to automate interactions, Python is one of the best tools available — but you need to understand ticks, fee tiers, and pool math before writing your first script.

Setting Up the Uniswap V3 Python SDK

There are two main libraries Python developers use to interact with Uniswap V3: the community-built `uniswap-python` package, and a lower-level approach using `web3.py` directly with Uniswap's ABI. For most use cases — reading prices, executing swaps, querying pool state — `uniswap-python` is the faster path.

# Install dependencies
pip install uniswap-python web3 python-dotenv requests

You'll also need access to an Ethereum node. You have a few options: Infura, Alchemy, or your own node. Alchemy's free tier gives you 300 million compute units per month, which is plenty for monitoring and light automation. Once you have your node URL, set it as an environment variable — never hardcode API keys.

import os
from web3 import Web3
from uniswap import Uniswap
from dotenv import load_dotenv

load_dotenv()

WEB3_PROVIDER = os.getenv("WEB3_PROVIDER_URL")  # e.g. Alchemy or Infura
PRIVATE_KEY = os.getenv("PRIVATE_KEY")
WALLET_ADDRESS = os.getenv("WALLET_ADDRESS")

w3 = Web3(Web3.HTTPProvider(WEB3_PROVIDER))

# Connect to Uniswap V3
uniswap = Uniswap(
    address=WALLET_ADDRESS,
    private_key=PRIVATE_KEY,
    web3=w3,
    version=3
)

print("Connected:", w3.is_connected())

The `version=3` parameter is critical — without it, the library defaults to V2 logic and your calculations will be wrong. Once connected, you can start reading pool data, checking prices, and eventually executing swaps programmatically.

Key Takeaway: Always use environment variables for your private key and RPC URL. Never commit credentials to GitHub. Use a dedicated hot wallet with limited funds for automation — not your main portfolio wallet.

Using the Uniswap V3 API in Python to Fetch Pool Data

The Uniswap V3 API in Python can mean two things: querying on-chain contract data directly via web3.py, or hitting the Uniswap subgraph on The Graph protocol. The subgraph approach is much faster for historical data and analytics. Direct contract calls are better for real-time execution.

For price monitoring, the subgraph is ideal. You send a GraphQL query and get back pool data including current price, volume, TVL, and fee income — no need to decode raw contract state.

import requests

SUBGRAPH_URL = "https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3"

def get_pool_data(pool_address: str) -> dict:
    query = """
    {
      pool(id: "%s") {
        token0 { symbol }
        token1 { symbol }
        feeTier
        liquidity
        token0Price
        token1Price
        volumeUSD
        totalValueLockedUSD
      }
    }
    """ % pool_address.lower()

    response = requests.post(
        SUBGRAPH_URL,
        json={"query": query},
        timeout=10
    )
    return response.json()["data"]["pool"]

# ETH/USDC 0.05% pool
pool = get_pool_data("0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640")
print(f"{pool['token0']['symbol']}/{pool['token1']['symbol']}")
print(f"Price: {pool['token0Price']}")
print(f"TVL: ${float(pool['totalValueLockedUSD']):,.0f}")

For real-time swap price quotes without executing a transaction, use the `quoter` contract. This simulates the swap and tells you exactly how many tokens you'd receive, accounting for current liquidity distribution across ticks.

from web3 import Web3

# Uniswap V3 Quoter contract address (Ethereum mainnet)
QUOTER_ADDRESS = "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6"

QUOTER_ABI = [
    {
        "inputs": [
            {"name": "tokenIn", "type": "address"},
            {"name": "tokenOut", "type": "address"},
            {"name": "fee", "type": "uint24"},
            {"name": "amountIn", "type": "uint256"},
            {"name": "sqrtPriceLimitX96", "type": "uint160"}
        ],
        "name": "quoteExactInputSingle",
        "outputs": [{"name": "amountOut", "type": "uint256"}],
        "type": "function",
        "stateMutability": "nonpayable"
    }
]

WETH = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"

quoter = w3.eth.contract(address=QUOTER_ADDRESS, abi=QUOTER_ABI)

# Quote 1 ETH -> USDC at 0.05% fee tier
amount_in = w3.to_wei(1, "ether")
fee = 500  # 0.05% = 500 basis points in Uniswap fee units

amount_out = quoter.functions.quoteExactInputSingle(
    WETH, USDC, fee, amount_in, 0
).call()

print(f"1 ETH = {amount_out / 1e6:.2f} USDC")

This is far more accurate than using a simple price feed because it accounts for actual liquidity depth at each tick. If you're building arbitrage detection between Uniswap V3 and centralized books on OKX or Coinbase, this is the correct price to compare against.

Understanding Uniswap V3 Fees and How to Factor Them Into Code

Uniswap V3 fees are one of the most important variables to get right in any trading bot. Get them wrong and your profitability calculations will be off — sometimes drastically.

Uniswap V3 has four fee tiers, and each maps to a different use case. Unlike Binance's flat maker/taker model or Bybit's VIP tiers, Uniswap fees go entirely to liquidity providers in the specific pool — Uniswap Labs takes a small protocol cut on some pairs through a fee switch.

Uniswap V3 Fee Tiers
Fee TierBasis PointsBest For
0.01%100Stablecoin pairs (USDC/USDT, DAI/USDC)
0.05%500Correlated pairs (ETH/WBTC, stETH/ETH)
0.3%3000Standard pairs (ETH/USDC, ETH/DAI)
1%10000Exotic or low-liquidity tokens

In Python, you need to pick the right fee tier when querying or routing swaps. If you try to interact with the ETH/USDC 0.3% pool when most liquidity has migrated to the 0.05% pool, you'll get worse prices. Always check TVL across fee tiers before hardcoding one.

FEE_TIERS = [100, 500, 3000, 10000]

def find_best_fee_tier(token0: str, token1: str, amount_in: int) -> tuple:
    """Find the fee tier with best output for a given swap."""
    best_out = 0
    best_fee = None

    for fee in FEE_TIERS:
        try:
            amount_out = quoter.functions.quoteExactInputSingle(
                token0, token1, fee, amount_in, 0
            ).call()
            if amount_out > best_out:
                best_out = amount_out
                best_fee = fee
        except Exception:
            continue  # Pool may not exist at this tier

    return best_fee, best_out

best_fee, best_out = find_best_fee_tier(WETH, USDC, w3.to_wei(1, "ether"))
print(f"Best fee tier: {best_fee / 10000:.2f}% → {best_out / 1e6:.2f} USDC")
Key Takeaway: Never assume which fee tier has the best liquidity. Always iterate over all fee tiers and compare output amounts before executing a swap. The difference between the wrong and right fee tier can be 0.5% or more on a single trade.

Building a Real-Time Price Monitor and Signal Layer

Once you can fetch prices and pool data, the next step is turning that into something actionable. A simple price monitor polls Uniswap V3 every few seconds and compares the on-chain price to a reference — either another DEX, a CEX like Coinbase or Gate.io, or a signal from a platform like VoiceOfChain.

VoiceOfChain provides real-time trading signals across major crypto assets. By cross-referencing a VoiceOfChain signal with the live Uniswap V3 pool price, you can build a system that triggers an on-chain swap only when both conditions align — the signal says buy AND the DEX price is within your acceptable range.

import time
from datetime import datetime

def get_eth_usdc_price() -> float:
    amount_in = w3.to_wei(1, "ether")
    amount_out = quoter.functions.quoteExactInputSingle(
        WETH, USDC, 500, amount_in, 0
    ).call()
    return amount_out / 1e6

def monitor_price(interval_seconds: int = 10, threshold_pct: float = 0.5):
    print("Starting Uniswap V3 price monitor...")
    last_price = get_eth_usdc_price()

    while True:
        time.sleep(interval_seconds)
        current_price = get_eth_usdc_price()
        change_pct = abs(current_price - last_price) / last_price * 100

        timestamp = datetime.now().strftime("%H:%M:%S")
        print(f"[{timestamp}] ETH/USDC: ${current_price:,.2f} | Δ {change_pct:.3f}%")

        if change_pct >= threshold_pct:
            print(f"  ⚡ Price moved {change_pct:.2f}% — alerting system")
            # Hook into VoiceOfChain signal or your alert logic here

        last_price = current_price

monitor_price(interval_seconds=15, threshold_pct=0.3)

This loop runs indefinitely and flags any price move above your threshold. You can extend it to push alerts to Telegram, compare against Binance spot price for arbitrage detection, or feed data into a trading strategy. Keep in mind Ethereum mainnet is slow compared to querying Binance's REST API — plan your polling intervals accordingly and consider caching block data.

For more advanced setups, subscribe to pending transactions via a WebSocket node connection. This lets you detect large swaps before they're confirmed — useful for front-run protection or MEV awareness, though that's a whole other territory.

Executing Swaps Programmatically with the Python SDK

Reading data is safe. Executing swaps moves real money on-chain. Before automating swaps, understand slippage tolerance, gas estimation, and transaction confirmation. Unlike clicking 'Swap' on the Uniswap UI where the interface handles this, in Python you're responsible for every parameter.

from uniswap import Uniswap

# Re-initialize with version=3
uniswap = Uniswap(
    address=WALLET_ADDRESS,
    private_key=PRIVATE_KEY,
    web3=w3,
    version=3
)

def swap_eth_for_usdc(eth_amount_eth: float, slippage: float = 0.005):
    """
    Swap ETH for USDC on Uniswap V3.
    slippage: acceptable slippage as a decimal (0.005 = 0.5%)
    """
    amount_in_wei = w3.to_wei(eth_amount_eth, "ether")

    # Get expected output
    expected_out = quoter.functions.quoteExactInputSingle(
        WETH, USDC, 500, amount_in_wei, 0
    ).call()

    # Apply slippage tolerance
    min_amount_out = int(expected_out * (1 - slippage))

    print(f"Swapping {eth_amount_eth} ETH")
    print(f"Expected: {expected_out / 1e6:.2f} USDC")
    print(f"Min acceptable: {min_amount_out / 1e6:.2f} USDC")

    # Execute swap (use small amounts for testing)
    tx = uniswap.make_trade(
        input_token=WETH,
        output_token=USDC,
        qty=amount_in_wei,
        fee=500
    )

    print(f"TX hash: {tx.hex()}")
    receipt = w3.eth.wait_for_transaction_receipt(tx)
    print(f"Confirmed in block: {receipt['blockNumber']}")
    return receipt

# Test with 0.001 ETH first — always start small
# swap_eth_for_usdc(0.001)
Key Takeaway: Always test swaps with the smallest possible amount before scaling up automation. On mainnet, failed transactions still cost gas. Use a fork of mainnet (via Hardhat or Anvil) to simulate full swap flows before going live with real funds.

Gas management is the hidden cost that eats into DeFi automation profitability. Unlike paying trading fees on KuCoin or Bitget where costs are predictable, Ethereum gas fluctuates with network congestion. Fetch the current base fee and add your priority fee (tip) dynamically — don't hardcode gas prices.

def get_gas_params() -> dict:
    """Get current EIP-1559 gas parameters."""
    latest = w3.eth.get_block("latest")
    base_fee = latest["baseFeePerGas"]
    priority_fee = w3.to_wei(1.5, "gwei")  # tip to validator
    max_fee = base_fee * 2 + priority_fee

    return {
        "maxFeePerGas": max_fee,
        "maxPriorityFeePerGas": priority_fee,
        "type": 2  # EIP-1559
    }

gas = get_gas_params()
base_gwei = gas["maxFeePerGas"] / 1e9
print(f"Max gas: {base_gwei:.1f} gwei")

Frequently Asked Questions

What is the best Python library for Uniswap V3?
The `uniswap-python` library is the most popular starting point — it wraps the V3 router and quoter contracts with a clean Python interface. For more control, use `web3.py` directly with Uniswap's published ABIs. Most production bots combine both: high-level methods for simple swaps, raw web3 calls for advanced routing.
How do I get token prices from Uniswap V3 without executing a swap?
Use the Quoter contract's `quoteExactInputSingle` function — it simulates a swap and returns the output amount without actually moving funds. Alternatively, query the Uniswap V3 subgraph on The Graph for historical and near-real-time price data via GraphQL. The Quoter approach gives you execution-accurate prices; the subgraph is better for analytics.
What are Uniswap V3 fees and which fee tier should I use?
Uniswap V3 has four fee tiers: 0.01% for stablecoins, 0.05% for correlated assets like ETH/stETH, 0.3% for standard pairs, and 1% for exotic tokens. In Python, iterate over all tiers using the Quoter contract and pick the one that returns the highest output amount for your trade. Never hardcode a fee tier without checking current TVL.
Is it possible to interact with Uniswap V3 on networks other than Ethereum?
Yes — Uniswap V3 is deployed on Polygon, Arbitrum, Optimism, Base, and BNB Chain. The contract addresses differ per network, so update your Web3 provider URL and contract addresses accordingly. Arbitrum and Base are popular for bot development due to lower gas costs while keeping Ethereum-compatible security.
How do I handle slippage in Uniswap V3 Python scripts?
Calculate slippage as a percentage of expected output from the Quoter contract. Set `amountOutMinimum` to `expected * (1 - slippage_decimal)` when constructing your swap transaction. A 0.5% slippage is common for ETH/USDC; for exotic tokens with thin liquidity you may need 1-2%. Never set slippage to zero unless you're okay with the transaction reverting.
Can I use the Uniswap V3 API in Python without a private key?
For read-only operations — fetching prices, pool data, liquidity depth — yes, no private key needed. You only need a wallet and private key to sign and broadcast swap transactions. For monitoring bots, analytics scripts, and price feeds, a simple Alchemy or Infura RPC URL is all you need.

Where to Go From Here

The Uniswap V3 SDK in Python opens up a range of possibilities: arbitrage detection between Uniswap and centralized books on Binance or Coinbase, automated LP rebalancing, price alert systems, and full execution bots. The building blocks covered here — connecting via web3.py, querying the subgraph, using the Quoter contract, and executing swaps with proper slippage and gas handling — are the foundation for all of them.

The DeFi space moves fast. Pool compositions shift, fee tier preferences migrate, and new V3 deployments appear on new chains. Pair your on-chain Python tooling with a real-time signal layer like VoiceOfChain to stay ahead of market moves — knowing when to interact with a pool matters just as much as knowing how. Start small, test on testnets or with tiny amounts on mainnet, and build up from there. The infrastructure is already there waiting — Python just gives you the wheel.

◈   more on this topic
◉ basics Mastering the ccxt library documentation for crypto traders ⌂ exchanges Mastering the Binance CCXT Library for Crypto Traders ⌬ bots Best Crypto Trading Bots 2025: Profitable AI-Powered Strategies