DEV Community

Benjamin-Cup
Benjamin-Cup

Posted on

Adaptive Position Sizing Under Probability Uncertainty: Building a Professional Polymarket Trading bot

Building a Polymarket Trading bot is not difficult because Python is difficult. The hard part is deciding how much to trade when your probability estimate is uncertain. A bot can identify an apparent edge and still lose money through poor sizing, stale prices, liquidity constraints, model uncertainty, or execution errors. My experience building and experimenting with automated prediction-market systems has led me to a simple principle: prediction and position sizing should be separate systems.

This article explains an adaptive position-sizing framework for a Polymarket Trading bot, with Python examples, practical engineering considerations, and a production-oriented architecture.

Important: This is an educational engineering guide, not financial advice. Prediction-market trading involves risk, and a backtest or simulated edge does not guarantee future performance.

Why probability uncertainty matters

A prediction market price can be interpreted as an implied probability. For example, if a Yes contract trades around $0.60, the market is broadly pricing the outcome at roughly 60%, before considering fees, spread, liquidity, and other trading costs. Polymarket's documentation describes outcome prices as implied probabilities.

Suppose my model estimates:

Market price:       0.60
Model probability:  0.68
Estimated edge:     0.08
Enter fullscreen mode Exit fullscreen mode

At first glance, this looks attractive.

But what if the model is uncertain?

Estimated probability: 0.68
Uncertainty:           ±0.07
Enter fullscreen mode Exit fullscreen mode

The actual probability could plausibly be much closer to 0.61 than 0.68.

This is where many automated strategies make a mistake.

They treat:

p = 0.68
Enter fullscreen mode Exit fullscreen mode

as if it were a known fact.

It isn't.

A better trading system treats probability as an estimate with uncertainty.


A better architecture: prediction → uncertainty → sizing → execution

A robust bot should not jump directly from a prediction to an order.

A better pipeline looks like this:

flowchart LR
    A[Market Data] --> B[Feature Engineering]
    B --> C[Probability Model]
    C --> D[Probability Uncertainty]
    D --> E[Edge Estimation]
    E --> F[Adaptive Position Sizing]
    F --> G[Risk Limits]
    G --> H[Execution Engine]
    H --> I[Order / Position Monitoring]
    I --> J[Performance & Calibration]
    J --> C
Enter fullscreen mode Exit fullscreen mode

The important architectural decision is that the model doesn't decide the position size directly.

Instead:

Market
   ↓
Model probability
   ↓
Uncertainty estimate
   ↓
Risk-adjusted edge
   ↓
Position sizing
   ↓
Risk controls
   ↓
Execution
Enter fullscreen mode Exit fullscreen mode

This separation makes the system easier to test and much safer to modify.


The basic edge calculation

For a binary outcome, let:

  • p = your estimated probability of Yes
  • q = market price
  • 1 - p = probability of No
  • 1 - q = corresponding complement

For a simple Yes position, the expected value per dollar before costs can be approximated as:

EV = p × (1 - q) - (1 - p) × q
Enter fullscreen mode Exit fullscreen mode

This simplifies to:

EV = p - q
Enter fullscreen mode Exit fullscreen mode

So if:

p = 0.68
q = 0.60
Enter fullscreen mode Exit fullscreen mode

then:

EV = 0.08
Enter fullscreen mode Exit fullscreen mode

But that is only a model estimate.

It doesn't account for:

  • spread
  • fees
  • slippage
  • latency
  • partial fills
  • market impact
  • model error
  • correlated positions
  • changing market conditions

That is why a professional system should distinguish raw model edge from tradable edge.


Adaptive Position Sizing Under Probability Uncertainty

A useful approach is to shrink the model's edge according to how uncertain the probability estimate is.

Suppose:

Estimated probability = 0.68
Market probability    = 0.60
Raw edge              = 0.08
Enter fullscreen mode Exit fullscreen mode

Now assume the model has an uncertainty estimate of:

σ = 0.05
Enter fullscreen mode Exit fullscreen mode

Instead of acting as though the edge is exactly 0.08, we can apply a confidence factor.

One simple framework is:

confidence = max(0, 1 - uncertainty / uncertainty_limit)

adjusted_edge = raw_edge × confidence
Enter fullscreen mode Exit fullscreen mode

For example:

uncertainty_limit = 0.10

confidence = 1 - 0.05 / 0.10
           = 0.50

adjusted_edge = 0.08 × 0.50
              = 0.04
Enter fullscreen mode Exit fullscreen mode

The bot now behaves as though it has a 4 percentage-point edge rather than blindly using the original 8-point estimate.

This is intentionally conservative.

The objective isn't to maximize the number of trades. The objective is to avoid allowing uncertain predictions to produce oversized positions.


Python implementation

Here is a deliberately simple sizing component that can sit between a prediction model and an execution engine:

from dataclasses import dataclass


@dataclass
class SizingConfig:
    bankroll: float = 1_000.0
    max_position_pct: float = 0.02
    min_edge: float = 0.02
    uncertainty_limit: float = 0.10


def adaptive_position_size(
    model_probability: float,
    market_price: float,
    probability_uncertainty: float,
    config: SizingConfig,
) -> float:
    """Return a conservative position size in dollars."""

    if not 0 < model_probability < 1:
        raise ValueError("model_probability must be between 0 and 1")

    if not 0 < market_price < 1:
        raise ValueError("market_price must be between 0 and 1")

    if probability_uncertainty < 0:
        raise ValueError("uncertainty cannot be negative")

    raw_edge = model_probability - market_price

    if raw_edge < config.min_edge:
        return 0.0

    confidence = max(
        0.0,
        1.0 - probability_uncertainty / config.uncertainty_limit
    )

    adjusted_edge = raw_edge * confidence

    # Conservative proportional sizing.
    # The cap prevents one prediction from dominating the portfolio.
    position_fraction = min(
        adjusted_edge,
        config.max_position_pct
    )

    return config.bankroll * position_fraction
Enter fullscreen mode Exit fullscreen mode

Example:

config = SizingConfig(
    bankroll=5_000,
    max_position_pct=0.02,
    min_edge=0.02,
    uncertainty_limit=0.10,
)

size = adaptive_position_size(
    model_probability=0.68,
    market_price=0.60,
    probability_uncertainty=0.05,
    config=config,
)

print(f"Suggested position size: ${size:.2f}")
Enter fullscreen mode Exit fullscreen mode

The important part is not the exact formula.

The important part is the architecture.

You should be able to replace the sizing model without rewriting the market-data collector, prediction model, or execution layer.


Why I prefer conservative sizing in automated trading

In manual trading, you can look at a situation and decide that your model might be wrong.

A bot cannot.

It will execute the rules you gave it.

That means uncertainty needs to be represented explicitly.

I generally prefer a system that says:

Strong edge + high confidence → larger allocation
Strong edge + low confidence  → smaller allocation
Weak edge                     → no trade
Bad liquidity                 → no trade
Risk limit exceeded           → no trade
Enter fullscreen mode Exit fullscreen mode

rather than:

model_probability > market_price → BUY
Enter fullscreen mode Exit fullscreen mode

That difference becomes significant when the system is running continuously.


Polymarket Trading bot architecture

Polymarket's current architecture separates market discovery/data from CLOB trading. The official documentation describes Gamma API for market/event discovery, Data API for positions and activity, and CLOB API for orderbooks, pricing, and trading operations.

A practical Python system can therefore be organized like this:

polymarket_bot/
│
├── config.py
├── market_data.py
├── features.py
├── model.py
├── uncertainty.py
├── sizing.py
├── risk.py
├── execution.py
├── portfolio.py
├── monitoring.py
└── main.py
Enter fullscreen mode Exit fullscreen mode

Each module should have one responsibility.

market_data.py

Responsible for:

  • discovering markets
  • retrieving prices
  • reading order books
  • checking market status
  • detecting stale data

model.py

Responsible for:

  • feature processing
  • probability prediction
  • model versioning
  • calibration

uncertainty.py

Responsible for estimating how reliable the probability prediction is.

Possible approaches include:

  • historical calibration error
  • ensemble variance
  • bootstrap estimates
  • Bayesian models
  • rolling out-of-sample error
  • confidence intervals

sizing.py

Responsible for translating:

probability + uncertainty + market price
Enter fullscreen mode Exit fullscreen mode

into:

maximum position
Enter fullscreen mode Exit fullscreen mode

risk.py

Responsible for hard limits such as:

max_position
max_market_exposure
max_daily_loss
max_open_positions
max_correlated_exposure
Enter fullscreen mode Exit fullscreen mode

execution.py

Responsible for:

  • order creation
  • order submission
  • cancellation
  • retries
  • fill tracking
  • execution state

Polymarket's official CLOB documentation recommends using its open-source clients for order signing, authentication, and submission. The current Python client is py-clob-client-v2.


Market data should come before trading logic

One of the practical lessons from building automated systems is that the strategy is only as good as the data pipeline underneath it.

Polymarket provides public market-data endpoints without requiring authentication. The documentation lists market discovery through the Gamma API and orderbook, price, midpoint, spread, and price-history access through the CLOB API.

A basic public-data client can look like:

from py_clob_client_v2 import ClobClient

client = ClobClient(
    host="https://clob.polymarket.com",
    chain_id=137,
)

markets = client.get_markets()

for market in markets:
    print(market)
Enter fullscreen mode Exit fullscreen mode

For production code, don't assume that every market has the same parameters. Polymarket exposes market-specific details such as minimum order size and minimum tick size, so the execution layer should validate those constraints before creating an order.

Read the official documentation before adapting examples to the current SDK version:

Official Polymarket Documentation


The GitHub implementation

For developers who want to see a practical Python implementation rather than only theory, I've published the project:

Benjam1nCup/Polymarket-trading-bot-python-V2 on GitHub

The repository is useful as a starting point for experimenting with automation, market selection, strategy logic, and execution architecture.

However, I would strongly recommend treating any trading-bot repository as engineering reference code rather than a guaranteed production strategy.

Before deploying real capital, validate:

  1. API behavior
  2. authentication
  3. order sizing
  4. tick-size constraints
  5. minimum order sizes
  6. partial fills
  7. cancellation behavior
  8. rate limits
  9. wallet security
  10. failure recovery

Polymarket's authentication model uses L1 wallet signing and L2 API credentials, and its documentation explicitly recommends keeping private keys out of source control.


Professional opinion on my earlier Polymarket tutorials

I've written simpler guides that approach the problem from the perspective of getting a working bot running quickly.

My earlier article, “How to Build a Polymarket Trading bot: 5-Minute Crypto Up/Down Market Trading Bot in Python,” is best viewed as an entry point for understanding the basic workflow: market data → strategy → Python automation → execution.

Read the 5-minute Polymarket Trading bot tutorial on DEV

I also published a broader guide covering automated strategies and professional system design:

Building a Professional Polymarket Trading System — 12 Automated Strategies

My professional view is that those tutorials are most valuable when used as progressive learning steps, not as promises of consistent profitability.

The next step after building a bot that can place trades is building a bot that knows when not to trade.

That means introducing:

  • probability calibration
  • uncertainty estimation
  • adaptive sizing
  • execution-aware edge
  • portfolio-level risk limits
  • observability
  • backtesting
  • paper trading
  • failure recovery

In other words:

Tutorial bot
     ↓
Automated strategy
     ↓
Risk-aware trading system
     ↓
Production engineering
Enter fullscreen mode Exit fullscreen mode

That progression is much more important than adding another indicator or another entry condition.


From fixed sizing to adaptive sizing

Consider two predictions:

Trade A

Market price:       0.55
Model probability:  0.65
Uncertainty:        0.02
Enter fullscreen mode Exit fullscreen mode

Trade B

Market price:       0.55
Model probability:  0.65
Uncertainty:        0.09
Enter fullscreen mode Exit fullscreen mode

Both have the same raw edge:

0.65 - 0.55 = 0.10
Enter fullscreen mode Exit fullscreen mode

But they should not necessarily receive the same position size.

Trade A has a relatively confident estimate.

Trade B has a much wider uncertainty range.

An adaptive system can therefore produce:

Trade A → higher allocation
Trade B → lower allocation
Enter fullscreen mode Exit fullscreen mode

This is a more realistic representation of model confidence.


Don't confuse edge with certainty

This is probably the most important lesson.

A model saying:

P(Yes) = 0.70
Enter fullscreen mode Exit fullscreen mode

doesn't mean the probability is actually 70%.

It means your current model estimates it at 70%.

Those are very different statements.

A mature system should therefore log something like:

{
  "market_price": 0.55,
  "model_probability": 0.70,
  "uncertainty": 0.06,
  "raw_edge": 0.15,
  "adjusted_edge": 0.06,
  "position_size": 42.50
}
Enter fullscreen mode Exit fullscreen mode

This makes the bot explainable.

When something goes wrong, you can ask:

  • Was the prediction wrong?
  • Was the probability poorly calibrated?
  • Was uncertainty underestimated?
  • Was the market too illiquid?
  • Was execution poor?
  • Was position sizing too aggressive?

Without these records, debugging a trading system becomes guesswork.


Risk controls should override the strategy

A strategy should never be able to bypass global risk controls.

For example:

def risk_check(
    requested_size: float,
    bankroll: float,
    current_exposure: float,
    max_exposure_pct: float = 0.10,
) -> float:

    max_exposure = bankroll * max_exposure_pct
    remaining_capacity = max(0.0, max_exposure - current_exposure)

    return min(requested_size, remaining_capacity)
Enter fullscreen mode Exit fullscreen mode

Then your pipeline becomes:

requested_size = adaptive_position_size(...)

approved_size = risk_check(
    requested_size=requested_size,
    bankroll=5_000,
    current_exposure=250,
)

if approved_size <= 0:
    print("Trade rejected by risk layer")
else:
    print(f"Trade approved: ${approved_size:.2f}")
Enter fullscreen mode Exit fullscreen mode

This separation is critical.

The strategy can say:

“I found an edge.”

The risk engine can still say:

“No.”

That is exactly what you want.


Production lessons: what I'd improve first

If I were taking a basic Polymarket bot and turning it into a more serious research system, I would prioritize these improvements:

1. Build a proper data recorder

Store:

timestamp
market_id
token_id
bid
ask
midpoint
spread
model_probability
uncertainty
position_size
execution_price
Enter fullscreen mode Exit fullscreen mode

Historical data is invaluable for understanding what actually happened.

2. Measure calibration

Don't only ask:

Did the bot make money?

Ask:

When the model said 70%, did those events actually happen approximately 70% of the time?

Calibration is fundamental when the strategy relies on probabilities.

3. Model execution costs

A theoretical 5% edge may disappear after:

spread
+ fees
+ slippage
+ latency
+ adverse selection
Enter fullscreen mode Exit fullscreen mode

The execution layer therefore needs to estimate net edge, not just model edge.

4. Add a kill switch

A production bot needs a mechanism to stop trading when:

API errors increase
data becomes stale
model output becomes invalid
unexpected fills occur
loss limits are reached
wallet state is inconsistent
Enter fullscreen mode Exit fullscreen mode

5. Paper trade before deploying capital

Run the entire pipeline without submitting live orders.

The goal is to discover bugs in:

market discovery
signal generation
sizing
risk controls
order lifecycle
position reconciliation
Enter fullscreen mode Exit fullscreen mode

before money is involved.


What I would not do

I would not build a system around:

if model_probability > market_price:
    buy()
Enter fullscreen mode Exit fullscreen mode

That is too simplistic.

I would also avoid:

  • unlimited martingale sizing
  • doubling after losses
  • assuming every market is liquid
  • ignoring orderbook depth
  • hardcoding market IDs
  • storing private keys in source code
  • assuming API responses never change
  • evaluating a strategy only by total profit
  • optimizing heavily on one historical period

A profitable backtest can still be a poorly engineered trading system.


FAQ

Is Polymarket algorithmic trading possible with Python?

Yes. Polymarket provides APIs and official client libraries for interacting with its market data and CLOB trading infrastructure. The current documentation lists Python support through py-clob-client-v2.

Does a higher predicted probability automatically mean a larger position?

No.

A probability estimate should be evaluated together with uncertainty, liquidity, portfolio exposure, and execution costs.

What is the most important part of a Polymarket Trading bot?

I would argue that it is not the entry signal.

The most important part is the combination of:

probability quality
+
risk management
+
execution reliability
Enter fullscreen mode Exit fullscreen mode

A mediocre signal with excellent risk controls can be studied and improved. A good signal with uncontrolled sizing can still destroy a portfolio.

Should I use Kelly Criterion?

Kelly-style sizing can be useful conceptually, but I would be cautious about applying full Kelly when your probability estimate is uncertain.

Probability estimation error can make aggressive Kelly sizing extremely sensitive to model mistakes.

A fractional or capped approach is generally easier to reason about.

Do I need API credentials to read Polymarket market data?

Not necessarily. Polymarket's public market-data endpoints can be accessed without authentication. Trading operations require the appropriate authentication flow.

Is the GitHub bot production-ready?

The repository should be treated as a learning and development resource. Before real-money deployment, independently verify the current Polymarket API, SDK behavior, authentication, order constraints, risk controls, and operational failure modes.

Can adaptive sizing guarantee better returns?

No.

Adaptive sizing does not create an edge.

It attempts to allocate risk more intelligently when the estimated edge and confidence vary. If the underlying probability model is poorly calibrated, better sizing cannot magically make it accurate.


Final thoughts

Building a Polymarket Trading bot taught me that the difficult part is not sending an order through an API.

The difficult part is building a system that can answer four questions consistently:

1. What does the model believe?
2. How uncertain is that belief?
3. Is the edge large enough after costs?
4. How much risk should the portfolio take?
Enter fullscreen mode Exit fullscreen mode

That is why I view Adaptive Position Sizing Under Probability Uncertainty as an important step beyond a basic trading-bot tutorial.

A simple bot can detect a difference between model probability and market price.

A more professional system understands that the model itself can be wrong.

The architecture I would aim for is:

Data
  ↓
Prediction
  ↓
Calibration
  ↓
Uncertainty
  ↓
Net Edge
  ↓
Adaptive Position Sizing
  ↓
Portfolio Risk
  ↓
Execution
  ↓
Monitoring
  ↓
Feedback
Enter fullscreen mode Exit fullscreen mode

The goal isn't to build a bot that trades more.

The goal is to build a bot that knows when its own prediction is uncertain—and reduces risk accordingly.

For developers who want to continue from the implementation side, start with the official Polymarket documentation, explore my Polymarket trading bot Python repository, and then compare it with my 5-minute Polymarket Trading bot tutorial and the broader professional Polymarket trading system guide.

🤝 Collaboration & Contact
If you’re interested in building trading bots, buy trading bots, collaborating, exploring strategy improvements, or discussing about this system, feel free to reach out.

I’m especially open to connecting with:

Quant traders
Engineers building trading infrastructure
Researchers in prediction markets
Investors interested in market inefficiencies

📌 GitHub Repository

This repo has some Polymarket several bots in this system.
You can explore the full implementation, strategy logic, and ongoing updates about 5 min crypto market here:

GitHub logo Benjam1nCup / Polymarket-trading-bot-python-V2

polymarket trading bot polymarket arbitrage bot polymarket bot polymarket trading bot polymarket arbitrage bot polymarket bot polymarket trading bot polymarket arbitrage bot polymarket bot polymarket trading bot polymarket arbitrage bot polymarket bot polymarket trading bot polymarket arbitrage bot polymarket bot polymarket trading bot

Polymarket Trading Bot | Polymarket Arbitrage Bot

An open-source and Strong Strategy collection of Polymarket trading bot and Polymarket arbitrage bot in Python for high-performance automated trading on polymarket crypto 5min markets.

Polymarket benjamincup bot dashboard

Features

  • Explosive growth of Polymarket with surging trading volume and new short-term markets

  • Increasing dominance of automated bots and AI in 5-minute crypto prediction markets

  • Higher profitability potential through advanced arbitrage and market-making strategies

  • Stronger edge for Python-based bots with real-time orderbook intelligence and low-latency execution

  • Continuous evolution of sniper, ladder, stair, momentum, and copy trading strategies

  • Scalable daily profits as prediction markets move toward hundreds of billions in annual volume

  • Full future-proof architecture for new features, contracts, and high-frequency trading environments

Included Trading Bots

Designed for arbitrage, directional strategies, and ultra-short-term markets (including 5-minute rounds), this bot framework provides a robust foundation for building and scaling automated trading strategies on Polymarket .

Demo Video

Polymarket Benjamin trading Bot video

Documentation

Throughout this…

💬 Get in Touch

If you have ideas, questions, or would like to collaborate or want these trading bots, don’t hesitate to reach out directly.

Feedback on your repo (based on your description & strategy)

Contact Info

Telegram
https://t.me/BenjaminCup

Top comments (0)