An automated Polymarket trading bot requests 100.
Only 40 actually fill.
What should happen next?
A simple bot might treat the order as completed.
A production-oriented trading system cannot.
The system now has:
Requested: 100
Filled: 40
Remaining: 60
That changes the position, the exposure, the hedge, the next trade, and potentially the entire risk state.
This is why I think partial fills are a state-management problem, not just an order-management problem.
In this article, I'll walk through how I think about partial fills in an automated Polymarket trading system and why execution verification and reconciliation need to be separate parts of the architecture.
What is a partial fill?
A partial fill occurs when an order is executed for only part of its requested quantity.
For example:
Requested quantity: 100
Executed quantity: 40
Remaining quantity: 60
The strategy wanted 100.
The market gave the system 40.
Those are two different facts.
A trading bot that continues to reason about the original 100 as though it were executed is now operating with incorrect state.
The first rule is therefore:
Requested quantity and executed quantity must be tracked separately.
Why partial fills are dangerous for trading bots
Imagine a strategy generates:
BUY 100
The execution layer submits the order.
The market only fills:
40
Now the system has to answer:
- Is the remaining 60 still resting?
- Should the order be cancelled?
- Should the remaining quantity be re-priced?
- Is the position supposed to be hedged?
- How much exposure actually exists?
- Does the strategy still want the trade?
- What happens if the remaining order never fills?
None of those questions can be answered correctly if the system stores only:
order.quantity = 100
The actual execution state needs to be explicit.
The execution state should be more than FILLED / NOT FILLED
A common simplification is:
SUBMITTED
↓
FILLED
Real execution is closer to:
INTENDED
↓
SUBMITTED
↓
ACCEPTED
↓
PARTIALLY_FILLED
↓
FILLED
But there are other outcomes:
REJECTED
CANCELLED
FAILED
RETRYING
UNKNOWN
And after execution:
FILLED
↓
TRANSACTION
↓
CONFIRMED
↓
SETTLED
That is why I prefer thinking about execution as a state machine.
INTENDED
↓
SUBMITTED
↓
ACCEPTED
↓
MATCHED
↓
PARTIALLY FILLED
↓
FILLED
↓
TX_PENDING
↓
CONFIRMED
↓
SETTLED
The exact state model will depend on the trading system, but the important idea is the same:
The trading system should represent what actually happened.
Partial fills change your risk
Consider a hedged trade.
Suppose the strategy expects:
Leg 1: 100
Leg 2: 100
But Leg 1 only fills 40.
The system does not have a 100-unit exposure on Leg 1.
It has 40.
That means a second leg sized for 100 could create an unintended position.
Instead:
Requested Leg 1
↓
100
↓
Actual Fill
↓
40
↓
Hedge calculation
↓
40
This is why hedge logic should be based on actual execution, not intended execution.
The distinction is simple:
Requested size ≠ Filled size
and:
Filled size → actual exposure
The bot needs to track residual quantity
After a partial fill:
Requested: 100
Filled: 40
Remaining: 60
The remaining quantity should be explicit.
Conceptually:
remaining = requested - filled
But the trading system also needs to know what the remaining quantity means.
It could be:
60 resting on the book
or:
60 cancelled
or:
60 unknown
or:
60 requiring a retry
The quantity alone is not enough.
The state of the remaining quantity matters.
What happens when the second leg doesn't fill?
This is where partial fills become particularly important for arbitrage and hedged strategies.
Suppose the intended trade is:
Leg 1 → 100
Leg 2 → 100
But the result is:
Leg 1 → 100 filled
Leg 2 → 0 filled
The system now owns an unintended exposure.
A naive implementation might simply retry Leg 2.
That can be dangerous if the market moved.
The price may no longer support the original trade.
A more deliberate execution flow is:
Leg 1 executed
↓
Measure actual fill
↓
Check current market
↓
Check risk
↓
Attempt hedge
↓
Verify hedge
↓
Reconcile final position
The system should be able to choose among actions such as:
HEDGE
REPRICE
CANCEL
UNWIND
PAUSE
The correct action depends on the strategy and risk policy.
Partial fills and position reconciliation
This is where execution state meets account state.
Suppose your local system says:
Expected position: +100
But execution records say:
Filled: +40
And the account currently reports:
Actual position: +40
The system is consistent.
Now consider:
Expected position: +100
Filled: +40
Actual position: +25
That is a different problem.
Something else happened between execution and account state.
Now the trading system needs reconciliation.
A useful architecture is:
ORDER
↓
FILL(S)
↓
Local Position
↓
Position Reconciler
↓
Remote Position
↓
Verified
The point is not to assume that one event tells you the whole story.
Why WebSocket events aren't enough
Real-time events are essential for low-latency systems.
But a trading bot should not assume that every event will arrive exactly once and in perfect order.
Possible problems include:
- disconnects
- missed events
- duplicated events
- delayed events
- application restart
- API inconsistencies
That means the system needs two complementary mechanisms:
Real-time updates
+
Reconciliation
Real-time events keep the system fast.
Reconciliation helps it recover when reality and local state diverge.
A safer recovery sequence
Imagine a partial-fill event happens during a WebSocket disconnect.
The bot reconnects.
It should not automatically decide:
“Everything is fine. Continue trading.”
A safer flow is:
WebSocket disconnect
↓
Trading = PAUSED
↓
Reconnect
↓
Rebuild / reload local state
↓
Reconcile orders
↓
Reconcile fills
↓
Reconcile positions
↓
Verify exposure
↓
Verify risk
↓
Resume trading
The key distinction is:
Reconnect is a network operation. Recovery is a trading-system operation.
Unknown execution state needs its own path
One of the most dangerous states is:
UNKNOWN
Suppose the application submits an order.
The network fails before the application receives the final response.
Now the system does not know whether the order:
- was rejected
- was accepted
- partially filled
- completely filled
Immediately submitting the same order again could create duplicate exposure.
So instead:
UNKNOWN
↓
Do not blindly retry
↓
Query / reconcile
↓
Determine actual state
↓
Continue according to policy
This is another reason I prefer an explicit execution-verification layer.
Execution verification
I’ve been building a separate Polymarket Execution Verifier around this problem.
The idea is to verify execution across multiple layers:
Order
↓
Fill
↓
Transaction
↓
Settlement
↓
Position
Instead of allowing the trading bot to assume:
ORDER = DONE
the verifier asks:
What actually happened?
Possible results include:
KNOWN
UNKNOWN
FAILED
SETTLED
INCONSISTENT
This makes execution verification an explicit component rather than something hidden inside a strategy.
Partial fills in a control-plane architecture
I think of the broader system like this:
POLYMARKET
│
Market Data
│
▼
┌───────────────┐
│ Trading Bot │
│ │
│ Strategy │
│ Execution │
└───────┬───────┘
│
▼
Execution Verifier
│
┌─────────┴─────────┐
▼ ▼
Fill State TX State
│ │
└─────────┬─────────┘
▼
Position
│
▼
Control Plane
│
┌─────────────┼─────────────┐
▼ ▼ ▼
Risk Health Reconciliation
│ │ │
└─────────────┼─────────────┘
▼
Recovery
The goal is to separate responsibilities.
Strategy
Decides what it wants to trade.
Execution
Attempts to place the order.
Execution verifier
Determines what actually happened.
Control plane
Determines whether the system should continue operating.
That separation becomes increasingly valuable as the trading system grows.
The most important invariant
For me, the key invariant is:
Actual Position
=
Verified Executions
=
Risk Calculation Input
At least, that should be the goal.
If those three things disagree, the system should stop treating its local state as trustworthy.
That leads to a simple operational rule:
When critical state is uncertain, reduce or stop new risk until state is verified.
Testing partial fills
Partial-fill handling should be tested explicitly.
For example:
| Scenario | Expected behavior |
|---|---|
| Full fill | Mark execution complete |
| Partial fill | Track actual filled quantity |
| Remaining order open | Track residual quantity |
| Remaining order cancelled | Recalculate state |
| Partial hedge | Recalculate exposure |
| Unknown execution | Reconcile before retry |
| Duplicate event | Avoid double-counting |
| WebSocket reconnect | Reconcile |
| Position mismatch | Block trading |
| Settlement mismatch | Escalate / reconcile |
The happy path is easy.
The failure paths are where the trading system needs engineering.
Building around the strategy
This is why I've become increasingly interested in the infrastructure around automated Polymarket trading.
A strategy can answer:
What should I trade?
But that doesn't answer:
How much actually filled?
or:
What position do I really have?
or:
Is it safe to place another order?
Those questions belong to the execution, state, risk, and control layers.
The architecture becomes:
Strategy
↓
Execution
↓
Verification
↓
State
↓
Risk
↓
Monitoring
↓
Recovery
That is the direction I'm exploring with the Polymarket Trading Bot, Execution Verifier, and Trading Control Plane projects.
Related projects
Polymarket Trading Bot
Automated trading, execution, risk management, and backtesting.
https://github.com/casatrickdev/polymarket-trading-bot
Polymarket Execution Verifier
Verify execution across orders, fills, transactions, settlement, and position state.
https://github.com/casatrickdev/polymarket-execution-verifier
Polymarket Trading Control Plane
Monitoring, state reconciliation, risk controls, health, alerts, and recovery.
https://github.com/casatrickdev/polymarket-trading-control-plane
Together:
Trading Bot
↓
Execution
↓
Partial Fill Handling
↓
Execution Verification
↓
State Reconciliation
↓
Risk / Monitoring
↓
Recovery
Final takeaway
A partial fill looks like a small execution detail.
It isn't.
Once an automated trading system starts managing real positions, a partial fill changes:
- actual position
- remaining quantity
- exposure
- hedge requirements
- risk
- execution state
- what the strategy should do next
The key is not to make the system assume that an intended trade became a completed trade.
Instead:
Intent
↓
Execution
↓
Actual Fill
↓
Verified State
↓
Position
↓
Risk
A trading bot becomes much easier to reason about when it knows the difference between what it wanted, what it executed, and what it actually owns.
That's the problem I'm exploring with execution verification and trading-system infrastructure for Polymarket.
Top comments (0)