DEV Community

Cover image for How I Actually Execute Orders in a Polymarket Bot
BornToWin
BornToWin

Posted on

How I Actually Execute Orders in a Polymarket Bot

Most Polymarket bot tutorials focus on the strategy.

Find a signal.

Calculate an edge.

Then:

if (signal) {
  placeOrder();
}
Enter fullscreen mode Exit fullscreen mode

But that is where the real problem starts.

When building a practical Polymarket bot, detecting an opportunity is only one part of the system.

The harder question is:

How do you actually execute that opportunity correctly?

You need to answer questions like:

  • Should the bot use a limit order or aggressive execution?
  • How much liquidity is really available?
  • Is the order-book imbalance meaningful?
  • How long has the imbalance existed?
  • Will the order move the market?
  • Is the signal still valid when the order reaches the market?
  • Should an existing order be cancelled or replaced?
  • When should FOK or FAK be used?
  • When does split make sense?
  • When can merge help with inventory management?

This is the practical execution layer of a Polymarket trading bot.

Strategy vs Execution

I separate a Polymarket bot into two major components.

Strategy

Should I trade?

Execution

How should I trade?

The strategy might generate:

BUY YES
Enter fullscreen mode Exit fullscreen mode

But the execution engine still needs to determine:

Price
Size
Order type
Timing
Liquidity
Slippage
Position
Exposure
Enter fullscreen mode Exit fullscreen mode

A good strategy can still lose its edge because of poor execution.

Limit Orders

A limit order gives the bot control over the maximum acceptable price.

Suppose:

Best bid = 0.48
Best ask = 0.51
Enter fullscreen mode Exit fullscreen mode

The strategy determines:

Maximum entry price = 0.49
Enter fullscreen mode Exit fullscreen mode

The bot could place:

BUY YES @ 0.49
Enter fullscreen mode Exit fullscreen mode

Now the order waits for a matching seller.

The lifecycle could look like:

REST
  ↓
PARTIAL FILL
  ↓
FULL FILL
Enter fullscreen mode Exit fullscreen mode

Or:

REST
  ↓
NO FILL
  ↓
CANCEL
Enter fullscreen mode Exit fullscreen mode

Limit orders are useful when price is more important than immediate execution.

But there is an important trade-off.

Suppose the market moves:

0.50
  ↓
0.52
  ↓
0.55
  ↓
0.58
Enter fullscreen mode Exit fullscreen mode

The limit order never fills.

The bot protected its entry price, but it missed the opportunity.

So the real question isn't:

Are limit orders better?

It is:

Is missing the trade worse than paying the spread and execution cost?

That depends on the strategy.

Immediate Execution Has a Different Problem

Sometimes a signal has a very short lifetime.

For example:

Signal
  ↓
Market moves
  ↓
Edge disappears
Enter fullscreen mode Exit fullscreen mode

Waiting for a passive limit order can mean missing the opportunity.

The bot may instead take available liquidity.

But aggressive execution introduces:

  • Spread cost
  • Slippage
  • Market impact
  • Liquidity consumption

The execution engine should therefore compare:

Expected Edge
      >
Execution Cost
Enter fullscreen mode Exit fullscreen mode

If the expected edge is too small, crossing the book can destroy the trade.

FOK vs FAK

Execution behavior matters too.

FOK

FOK means Fill or Kill.

The entire order must be filled immediately.

For example:

BUY 100

Available = 100

→ Fill 100
Enter fullscreen mode Exit fullscreen mode

But:

BUY 100

Available = 60

→ Cancel
Enter fullscreen mode Exit fullscreen mode

FOK can make sense when partial execution would make the trade invalid.

FAK

FAK means Fill and Kill.

The available quantity is filled immediately and the remainder is cancelled.

For example:

BUY 100

Available = 60

→ Fill 60
→ Cancel remaining 40
Enter fullscreen mode Exit fullscreen mode

FAK can make sense when partial execution is still useful.

The important part is not choosing one order type everywhere.

The execution type should match the strategy.

Don't Look Only at the Last Price

One of the biggest mistakes when building a Polymarket bot is looking only at the last traded price.

Consider this order book:

BIDS

0.48 → 100
0.47 → 300
0.46 → 500

ASKS

0.52 → 50
0.53 → 100
0.54 → 400
Enter fullscreen mode Exit fullscreen mode

The bot can now evaluate:

  • Best bid
  • Best ask
  • Spread
  • Depth
  • Available liquidity
  • Potential execution price
  • Potential price impact

The order book is part of the bot's current market state.

Order-Book Imbalance

One metric I find useful is order-book imbalance.

A simple calculation is:

imbalance =
(bidVolume - askVolume)
/
(bidVolume + askVolume)
Enter fullscreen mode Exit fullscreen mode

For example:

bidVolume = 800
askVolume = 200

imbalance =
(800 - 200) / (800 + 200)

= 0.60
Enter fullscreen mode Exit fullscreen mode

There is significantly more visible bid volume than ask volume within the selected depth.

But this is where many trading bots make a mistake.

Imbalance is not automatically a BUY signal.

A large imbalance can disappear very quickly.

Orders can be:

  • Cancelled
  • Replaced
  • Temporary
  • Concentrated at one price
  • Outside the relevant execution range

So I would not simply build:

if (imbalance > 0.5) {
    buy();
}
Enter fullscreen mode Exit fullscreen mode

and call it a complete trading strategy.

Define a Depth Window

Instead of calculating imbalance over an arbitrary amount of the order book, define a consistent depth.

For example:

Best bid
  +
5 bid levels

versus

Best ask
  +
5 ask levels
Enter fullscreen mode Exit fullscreen mode

Then calculate the imbalance.

A simple implementation could look like:

function calculateImbalance(
  bidVolume: number,
  askVolume: number
) {
  const total = bidVolume + askVolume;

  if (total === 0) {
    return 0;
  }

  return (bidVolume - askVolume) / total;
}
Enter fullscreen mode Exit fullscreen mode

The exact depth should depend on the market and strategy.

The important thing is consistency.

Persistence Matters

Checking imbalance once is often not enough.

Imagine:

t0 → +0.70
t1 → +0.05
t2 → -0.30
Enter fullscreen mode Exit fullscreen mode

The imbalance disappeared almost immediately.

Compare that with:

t0 → +0.70
t1 → +0.68
t2 → +0.72
t3 → +0.65
Enter fullscreen mode Exit fullscreen mode

The second condition is much more interesting because the imbalance persisted.

This means a bot can track:

Imbalance Magnitude
         +
Imbalance Duration
Enter fullscreen mode Exit fullscreen mode

A single snapshot can be noise.

A persistent condition can provide more useful information.

Imbalance Needs Context

I would not interpret imbalance by itself.

Consider:

Imbalance ↑
Price ↑
Trade flow ↑
Enter fullscreen mode Exit fullscreen mode

This is different from:

Imbalance ↑
Price ↓
Trade flow ↓
Enter fullscreen mode Exit fullscreen mode

The execution engine should combine order-book information with:

  • Price movement
  • Recent trades
  • Spread
  • Liquidity
  • Depth
  • Time remaining
  • Current position
  • Existing orders

The order book needs context.

Large Orders Create Another Problem

Suppose the ask side looks like:

0.50 → 20
0.51 → 30
0.52 → 50
0.53 → 100
Enter fullscreen mode Exit fullscreen mode

The bot wants to buy 150.

It cannot assume:

150 × 0.50
Enter fullscreen mode Exit fullscreen mode

The actual execution might be:

20 @ 0.50
30 @ 0.51
50 @ 0.52
50 @ 0.53
Enter fullscreen mode Exit fullscreen mode

Now the average execution price is much worse.

This is why a Polymarket trading bot should estimate:

  • Available depth
  • Expected average price
  • Slippage
  • Price impact

before sending large orders.

Order Push and Liquidity Consumption

A large marketable order can consume multiple levels of liquidity.

Before:

ASK

0.50 → 100
0.51 → 100
0.52 → 200
Enter fullscreen mode Exit fullscreen mode

After a large buy:

ASK

0.52 → 200
Enter fullscreen mode Exit fullscreen mode

The best ask moved because liquidity was consumed.

But I would not automatically call this momentum.

There is a difference between:

Liquidity consumption
Enter fullscreen mode Exit fullscreen mode

and:

Other market participants repricing
Enter fullscreen mode Exit fullscreen mode

That distinction matters when building a Polymarket bot.

Don't Let the Bot Make Its Own Execution Worse

Imagine:

Signal
  ↓
Large order
  ↓
Consume liquidity
  ↓
Price moves
  ↓
Bot continues buying
  ↓
Average entry becomes worse
Enter fullscreen mode Exit fullscreen mode

The original signal might still be correct.

The execution is the problem.

Order size should therefore consider:

Available Depth
      +
Expected Edge
      +
Maximum Slippage
      +
Current Exposure
Enter fullscreen mode Exit fullscreen mode

A good execution engine should know when to stop.

When Should the Bot Actually Place the Order?

A signal does not always mean:

BUY NOW
Enter fullscreen mode Exit fullscreen mode

I prefer an execution flow like:

Market Update
      ↓
Update State
      ↓
Check TWAP
      ↓
Check Order Book
      ↓
Check Imbalance
      ↓
Check Spread
      ↓
Check Liquidity
      ↓
Check Position
      ↓
Generate Signal
      ↓
Revalidate
      ↓
Submit Order
Enter fullscreen mode Exit fullscreen mode

The important step is:

Revalidate.

Signal-to-Execution Race Conditions

Imagine:

10:00:00.000
Signal generated

10:00:00.100
Order created

10:00:00.180
Order submitted

10:00:00.250
Order matched
Enter fullscreen mode Exit fullscreen mode

The market state at the time of the signal may be completely different from the state when the order is matched.

Before submitting an important order, the execution layer should re-check:

Market status
Price
Liquidity
Spread
Position
Exposure
Signal freshness
Enter fullscreen mode Exit fullscreen mode

Conceptually:

Signal
  ↓
Revalidate Market
  ↓
Revalidate Price
  ↓
Revalidate Liquidity
  ↓
Revalidate Risk
  ↓
Submit
Enter fullscreen mode Exit fullscreen mode

This helps prevent the bot from executing stale signals.

Split

Split is useful for inventory management.

Conceptually:

Collateral
    ↓
  SPLIT
    ↓
  YES + NO
Enter fullscreen mode Exit fullscreen mode

This can be useful when a bot needs inventory on both sides of a market.

For example, a market-making system may need:

YES inventory
      +
NO inventory
Enter fullscreen mode Exit fullscreen mode

Split can provide the paired outcome inventory.

Merge

Merge works in the opposite direction.

Suppose the bot has:

100 YES
100 NO
Enter fullscreen mode Exit fullscreen mode

The matching positions can potentially be merged:

100 YES
    +
100 NO
    ↓
100 collateral
Enter fullscreen mode Exit fullscreen mode

But if the bot has:

100 YES
50 NO
Enter fullscreen mode Exit fullscreen mode

only the matching portion can be merged:

50 YES
    +
50 NO
    ↓
50 collateral
Enter fullscreen mode Exit fullscreen mode

The remaining:

50 YES
Enter fullscreen mode Exit fullscreen mode

is still an open position.

This makes split and merge useful as inventory-management mechanisms.

Split and Merge Are Not Trading Signals

I don't think of split and merge as automatic BUY or SELL signals.

They are better viewed as:

Inventory Management
        +
Position Management
Enter fullscreen mode Exit fullscreen mode

The bot can ask:

Do I need YES + NO inventory?

→ Consider SPLIT
Enter fullscreen mode Exit fullscreen mode

or:

Do I have matching YES + NO?

→ Consider MERGE
Enter fullscreen mode Exit fullscreen mode

The decision still needs to consider:

  • Costs
  • Timing
  • Liquidity
  • Collateral
  • Current inventory

Practical Execution Checklist

Before submitting an important order, I want the bot to check:

[ ] Market is active
[ ] Market data is fresh
[ ] Order book is fresh
[ ] Spread is acceptable
[ ] Liquidity is sufficient
[ ] Expected slippage is acceptable
[ ] Imbalance is meaningful
[ ] Imbalance is persistent
[ ] Signal is still valid
[ ] Position size is acceptable
[ ] Exposure limit is not exceeded
[ ] Price is still valid
[ ] Order size is valid
[ ] Execution type is appropriate
Enter fullscreen mode Exit fullscreen mode

Only after those checks:

PLACE ORDER
Enter fullscreen mode Exit fullscreen mode

The Order Lifecycle Doesn't Stop at Submission

Placing the order is not the end.

The bot needs to monitor:

SUBMITTED
   ↓
OPEN
   ↓
PARTIALLY_FILLED
   ↓
FILLED
Enter fullscreen mode Exit fullscreen mode

Or:

SUBMITTED
   ↓
REJECTED
Enter fullscreen mode Exit fullscreen mode

Or:

OPEN
   ↓
MARKET MOVES
   ↓
CANCEL
   ↓
REPLACE
Enter fullscreen mode Exit fullscreen mode

This is why order management needs its own state machine.

For example:

type OrderState =
  | "NEW"
  | "SUBMITTED"
  | "OPEN"
  | "PARTIALLY_FILLED"
  | "FILLED"
  | "CANCELLED"
  | "REJECTED";
Enter fullscreen mode Exit fullscreen mode

Explicit order states make the execution logic easier to reason about.

Complete Polymarket Bot Execution Flow

The practical flow becomes:

MARKET DATA
     ↓
ORDER BOOK
     ↓
TWAP STATE
     ↓
TRADE FLOW
     ↓
IMBALANCE
     ↓
STRATEGY
     ↓
SIGNAL
     ↓
FRESHNESS CHECK
     ↓
LIQUIDITY CHECK
     ↓
SLIPPAGE CHECK
     ↓
POSITION CHECK
     ↓
EXECUTION TYPE
     ↓
ORDER SUBMIT
     ↓
FILL MONITOR
     ↓
CANCEL / REPLACE
     ↓
POSITION UPDATE
Enter fullscreen mode Exit fullscreen mode

This is very different from:

Signal → Buy
Enter fullscreen mode Exit fullscreen mode

Final Thoughts

The strategy is only half of a Polymarket bot.

The other half is execution.

A serious Polymarket bot needs to understand:

Should I trade?
Enter fullscreen mode Exit fullscreen mode

and:

How should I execute?
Enter fullscreen mode Exit fullscreen mode

Limit orders provide price control.

Immediate execution provides speed.

FOK provides all-or-nothing execution.

FAK allows partial immediate execution.

Order-book imbalance provides useful context, but it should not automatically become a BUY or SELL signal.

Split can help create inventory.

Merge can help manage matching positions.

And execution timing can be just as important as the original trading signal.

The execution process I care about is:

Signal
  ↓
Validate
  ↓
Measure Liquidity
  ↓
Check Imbalance
  ↓
Estimate Impact
  ↓
Choose Order Type
  ↓
Execute
  ↓
Monitor
  ↓
Reconcile
Enter fullscreen mode Exit fullscreen mode

That's where a Polymarket bot becomes an actual execution system rather than just a strategy script.

Automated trading involves financial risk. No execution technique guarantees profit, and historical or simulated results do not guarantee future performance.

Top comments (0)