A trading bot can detect the right signal and still lose the trade.
That sounds strange at first.
If the strategy correctly identifies an opportunity, shouldn't the bot simply place an order and profit from it?
In real Polymarket trading, the difficult part often starts after the signal is detected.
Between:
signal → order placement → order matching → fill → position management
the market can change.
The best price can disappear. Liquidity can move. Your order can be partially filled. The expected edge can disappear before the execution is complete.
This is one of the reasons building a production-grade Polymarket trading bot is much more complicated than implementing a trading strategy.
The basic mistake: treating execution as an afterthought
A simple trading bot might look like this:
Receive market data
↓
Calculate signal
↓
Signal = BUY
↓
Place order
↓
Done
This architecture is easy to understand.
It is also incomplete.
A more realistic execution flow looks like:
Market data
↓
Signal generation
↓
Validate market state
↓
Check liquidity
↓
Check spread
↓
Check current position
↓
Determine execution price
↓
Place order
↓
Monitor order
↓
Handle partial/full fill
↓
Reconcile position
↓
Update risk state
The execution engine needs to make decisions of its own.
The strategy answers:
Should I trade?
The execution engine answers:
How should I trade right now?
Those are different problems.
1. A correct signal does not guarantee a profitable fill
Imagine a bot detects a short-term opportunity.
At the moment the signal is generated:
Best bid: $0.47
Best ask: $0.49
The strategy calculates that buying around $0.49 makes sense.
The bot receives the signal and begins placing the order.
But before the order reaches the market:
Best bid: $0.47
Best ask: $0.52
The market has moved.
The original edge may no longer exist.
If the bot blindly executes anyway, it can turn a good signal into a bad trade.
That's why signal quality and execution quality need to be evaluated separately.
2. The order book is part of the strategy
A trading bot should not only ask:
Is the market giving me a signal?
It should also ask:
What does the order book look like right now?
Useful execution information can include:
- Best bid
- Best ask
- Spread
- Available liquidity
- Depth near the current price
- Recent order-book changes
- Price movement
- Existing position
- Open orders
- Expected fill price
For example, a strategy may identify a bullish signal.
But if the available liquidity near the desired entry price is extremely small, blindly entering the position may produce poor execution.
The strategy can be correct while the trade is still unattractive.
3. Limit order vs marketable execution
One of the most important decisions is how aggressively the bot should execute.
A passive limit order attempts to control the execution price.
An aggressive order prioritizes getting filled.
Neither is universally better.
It depends on the strategy.
Passive execution
The bot places an order at a specific price and waits.
Advantages:
- Better price control
- Potentially lower execution cost
- Useful when the strategy is not extremely time-sensitive
Disadvantages:
- The order may never fill
- The market may move away
- The opportunity may disappear
Aggressive execution
The bot attempts to get filled against available liquidity.
Advantages:
- Higher probability of immediate execution
- Useful when timing is more important than price improvement
Disadvantages:
- Can consume liquidity
- Can increase slippage
- Can result in worse average execution
The correct choice depends on the expected edge.
4. The signal can decay while the order is waiting
This is especially important for short-duration prediction markets.
Suppose the bot estimates:
Expected entry: 0.48
Expected value: 0.54
The strategy sees an attractive difference.
The bot places a limit order at 0.48.
But the order doesn't fill.
A few seconds later:
Market: 0.51
Estimated value: 0.53
The original opportunity is much smaller.
Should the bot continue waiting?
Not necessarily.
The execution engine needs rules for stale orders.
For example:
if order_age > max_age:
cancel order
if expected_edge < minimum_edge:
cancel order
if market_state_changed:
cancel or reprice order
The exact thresholds depend on the strategy.
The important concept is that an order should not live forever simply because the original signal was valid.
5. Partial fills create another problem
Suppose the bot wants to enter:
Target position: 1,000 contracts
But only part of the order gets filled.
The result might be:
Requested: 1,000
Filled: 350
Remaining: 650
Now the bot has a position.
But it doesn't have the position it originally intended to build.
That changes the execution problem.
The bot now needs to decide:
- Keep waiting?
- Cancel the remaining order?
- Reprice?
- Submit another order?
- Reduce the target?
- Exit the partial position?
- Continue according to the strategy?
A production bot needs explicit logic for this.
6. Position state must be reliable
Another common mistake is assuming:
“I submitted the order, therefore I have the position.”
That isn't necessarily true.
The bot needs to distinguish between states such as:
SIGNAL_DETECTED
↓
ORDER_SUBMITTED
↓
ORDER_OPEN
↓
PARTIALLY_FILLED
↓
FILLED
And it should also handle:
ORDER_CANCELLED
ORDER_REJECTED
ORDER_EXPIRED
UNKNOWN_STATE
The strategy should make decisions based on actual position state, not assumptions.
This becomes especially important when a bot is running continuously.
7. WebSocket data is not the same thing as execution state
Real-time market data is extremely useful for a trading bot.
But market data and account/order state are two different streams of information.
Conceptually:
Market WebSocket
↓
Order book / market state
↓
Strategy
↓
Execution engine
↓
Order management
↓
Position/account state
The bot needs to keep these states synchronized.
For example:
Market says:
"Opportunity detected"
But execution state says:
"Existing position already open"
The bot should not blindly submit another order.
This is why production trading systems need state management rather than just a signal function.
8. Execution latency matters
Consider a very short-duration strategy.
The process might look like:
Market update
↓
Data processing
↓
Signal calculation
↓
Risk checks
↓
Order construction
↓
Network request
↓
Matching
↓
Fill
Every step introduces some amount of delay.
The exact latency isn't the only problem.
What matters is:
What can change during that time?
A strategy that works with a 10-second execution window might behave completely differently if the opportunity disappears within one second.
This is why backtests that assume instantaneous execution can be misleading.
9. Backtesting needs an execution model
A common backtesting mistake looks like this:
Signal detected at 0.48
Backtest:
BUY at 0.48
Real execution may look more like:
Signal detected at 0.48
↓
Available liquidity checked
↓
Order submitted
↓
First fill: 0.49
↓
Second fill: 0.50
↓
Remaining order cancelled
The backtest and the real bot are now trading completely different conditions.
A more realistic simulation should consider factors such as:
- Spread
- Available liquidity
- Execution price
- Slippage
- Partial fills
- Order lifetime
- Position limits
- Fees
- Cancellation
- Market movement after signal generation
The closer the execution model is to reality, the more useful the backtest becomes.
10. Execution should have its own risk controls
A trading strategy can have risk management.
The execution engine should have risk management too.
For example:
Maximum order size
Maximum position
Maximum exposure
Maximum slippage
Maximum order lifetime
Maximum number of open orders
Maximum daily loss
Before submitting an order, the bot can validate:
Is the market still valid?
Is the price still acceptable?
Is enough liquidity available?
Is the position within limits?
Is the expected edge still large enough?
Is another order already active?
If the answer is no, the correct action may be:
Do nothing.
Not every detected opportunity should become a trade.
11. A better Polymarket bot architecture
For a more serious system, I prefer separating the components.
MARKET DATA
│
▼
┌─────────────────┐
│ Market State │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Signal Engine │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Risk Engine │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Execution Engine│
└────────┬────────┘
│
▼
┌─────────────────┐
│ Order Manager │
└────────┬────────┘
│
▼
POLYMARKET
│
▼
┌─────────────────┐
│ Position State │
└─────────────────┘
This separation makes the system much easier to test and extend.
For example, the same execution engine could potentially support different strategies:
Momentum Strategy ─────┐
Arbitrage Strategy ────┼──→ Risk Engine → Execution Engine
TWAP Strategy ─────────┤
Market Making ─────────┘
The strategy determines what it wants to do.
The execution engine determines how to execute it.
12. This is where TWAP becomes interesting
TWAP is often described simply as:
Split a large order into smaller orders over time.
But implementation is more complicated.
A useful TWAP system needs to consider:
- Target size
- Remaining size
- Time interval
- Current liquidity
- Current price
- Existing fills
- Failed orders
- Partial fills
- Market conditions
- Maximum acceptable execution price
A simple schedule might be:
Target: 1,000
Duration: 10 minutes
100 → 100 → 100 → 100 → ...
A more adaptive system might instead say:
If liquidity is healthy:
execute normally
If liquidity disappears:
slow down
If price moves outside tolerance:
pause
If order partially fills:
recalculate remaining quantity
That turns TWAP from a timer into an actual execution system.
13. The important lesson
Building a Polymarket trading bot is not simply:
if signal:
buy()
A real system needs to answer:
Is the signal still valid?
Is the market still liquid?
What price should I accept?
How much should I execute?
What happens if only part of the order fills?
What happens if the market moves?
When should I cancel?
What is my current position?
Is the trade still worth taking?
These execution decisions can determine whether a strategy that looks good on paper survives in a live market.
14. What I focus on when building trading bots
When I build automated trading systems, I don't treat the strategy as the entire product.
I look at the complete pipeline:
Market data → strategy → risk → execution → order management → position management → monitoring
For Polymarket specifically, that can involve:
- CLOB market data
- Real-time order-book monitoring
- WebSocket infrastructure
- Automated order execution
- Limit/marketable execution logic
- Partial-fill handling
- Position tracking
- TWAP execution
- Arbitrage logic
- Risk controls
- Monitoring and logging
- Backtesting
The goal isn't simply to make the bot generate signals.
The goal is to make the entire system behave correctly when the market does something unexpected.
Building a custom Polymarket trading bot?
If you already have a strategy and want to automate it, the strategy itself is only the starting point.
A proper implementation needs to define:
- What markets should be monitored?
- What creates an entry signal?
- What invalidates the signal?
- How should orders be executed?
- How much liquidity is required?
- How should partial fills be handled?
- What are the position limits?
- When should orders be cancelled?
- How should the bot recover from failures?
- What should be monitored after deployment?
I build custom Polymarket trading bots and automated execution systems around specific strategies and execution requirements.
My work focuses on the engineering side: real-time market data, order-book analysis, CLOB execution, TWAP, automated order management, risk controls and monitoring.
I've also been building a Polymarket TWAP trading bot and making the implementation available on GitHub:
If you have a Polymarket strategy you want automated, send me the strategy, target markets, expected position size and execution requirements.
The interesting part isn't just finding the trade. It's building the system that can actually execute it.
Top comments (1)
This is a good distinction between having a strategy and having a trading system.
The part that stood out to me is the execution state machine. ORDER_SUBMITTED should never be treated as POSITION_OPEN, especially with partial fills, cancellations, reconnects, and delayed exchange updates.
I’d also make reconciliation a first-class process rather than relying only on WebSocket events. After a disconnect or unexpected response, the local state can easily diverge from the exchange, so periodic reconciliation against actual open orders and positions is essential.
The same applies to backtesting. If the simulator assumes every signal gets filled at the observed price, the results can look great while saying very little about live execution.
Signal → risk → execution → reconciliation is really where the production complexity lives. Good write-up.