DEV Community

guskarls
guskarls

Posted on • Originally published at guskarls.substack.com

Building a TWAP-Aware Polymarket Trading Engine: State, Data Quality, and Execution

A simple trading bot can be described in one sentence:

If a condition is true, place an order.

That approach becomes much more complicated when the market outcome depends on a TWAP (Time-Weighted Average Price) over a settlement window.

The bot now needs to understand not only the current market price, but also:

  • where we are inside the settlement window
  • which price samples have already been observed
  • where the final average could finish
  • whether the data is fresh
  • whether the strategy is allowed to trade
  • whether execution is safe

This article explains the engineering approach I use for a TWAP-aware Polymarket trading system.


1. The architecture

I think about the system as a pipeline:

Real-Time Data
      ↓
Data Validation
      ↓
TWAP Window Tracker
      ↓
Projected Settlement
      ↓
Signal Engine
      ↓
Risk Engine
      ↓
CLOB Execution
Enter fullscreen mode Exit fullscreen mode

Each component has one job.

This separation is important because trading logic, data reliability, risk management, and execution have very different failure modes.


2. Start with the market-data layer

The first requirement is reliable real-time data.

A trading strategy is only as good as the information it receives.

The data layer should handle:

  • incoming price updates
  • timestamps
  • subscriptions
  • reconnects
  • stale data
  • missing samples
  • duplicate events
  • connection state

Conceptually:

┌─────────────────┐
│ Market / Oracle │
│     Feed        │
└────────┬────────┘
         ↓
┌─────────────────┐
│ Event Processor │
└────────┬────────┘
         ↓
┌─────────────────┐
│ Data Validator  │
└────────┬────────┘
         ↓
    Valid Event
Enter fullscreen mode Exit fullscreen mode

I don't want strategy code directly consuming an unvalidated feed.


3. TWAP requires state

With a normal price-based strategy, the latest price might be enough.

With TWAP, the system needs to remember what happened during the window.

A useful state model is:

WAITING
   ↓
ACTIVE
   ↓
COLLECTING
   ↓
SIGNAL_READY
   ↓
EXECUTING
   ↓
SETTLED
Enter fullscreen mode Exit fullscreen mode

For each window, the system can maintain information such as:

windowStart
windowEnd
latestSample
sampleCount
projectedTWAP
dataFresh
strategyState
executionState
Enter fullscreen mode Exit fullscreen mode

The exact implementation depends on the strategy, but the important concept is the same:

the trading engine needs memory.


4. Current price isn't the same as projected settlement

This is the key difference.

A naive strategy might use:

currentPrice
Enter fullscreen mode Exit fullscreen mode

A TWAP-aware strategy is interested in:

projectedFinalTWAP
Enter fullscreen mode Exit fullscreen mode

Conceptually:

Observed contribution
        +
Expected remaining contribution
        =
Projected settlement
Enter fullscreen mode Exit fullscreen mode

As more observations arrive, the uncertainty around the final average can change.

So the signal engine should continuously update its view of the settlement window.

New price sample
      ↓
Update window
      ↓
Recalculate projection
      ↓
Evaluate signal
Enter fullscreen mode Exit fullscreen mode

This makes the strategy time-aware rather than simply price-reactive.


5. Data freshness is a trading condition

One of the most important safeguards is stale-data detection.

Imagine:

Price feed
    ↓
Stops updating
    ↓
Bot still sees old price
    ↓
Strategy generates signal
    ↓
Order gets placed
Enter fullscreen mode Exit fullscreen mode

That's a dangerous failure mode.

Instead:

Price feed
    ↓
Freshness check
    ↓
Fresh?
 ┌──┴──┐
Yes    No
 ↓      ↓
Signal  Stop
Enter fullscreen mode Exit fullscreen mode

The system should be able to say:

I don't have reliable data, so I'm not trading.

This is a much better default than trying to recover a signal from stale information.


6. WebSocket reconnects aren't just networking

A common mistake is treating reconnect logic as a separate infrastructure problem.

For a trading bot, it isn't.

Suppose the WebSocket disconnects halfway through a settlement window.

After reconnecting, the system needs to know:

  • Which market was being tracked?
  • Which window was active?
  • What was the previous state?
  • Did any samples arrive during the interruption?
  • Is the current data still valid?
  • Did an order execute before the disconnect?
  • Should trading resume immediately?

Therefore:

Disconnect
    ↓
Reconnect
    ↓
Restore / validate state
    ↓
Refresh data
    ↓
Resume only if safe
Enter fullscreen mode Exit fullscreen mode

A reconnect should not automatically mean:

connected = true
start trading
Enter fullscreen mode Exit fullscreen mode

7. Multiple windows need independent state

If you're tracking different market durations, don't put all timing logic into one global state.

For example:

5-minute window
      ↓
State A

15-minute window
      ↓
State B

4-hour window
      ↓
State C
Enter fullscreen mode Exit fullscreen mode

Each window can have its own:

  • timestamps
  • samples
  • projected settlement
  • signal
  • execution state

This makes concurrent market tracking much easier to reason about.


8. Separate strategy from risk

I prefer this separation:

Strategy
   ↓
"Is there an opportunity?"
   ↓
Risk Engine
   ↓
"Are we allowed to take it?"
   ↓
Execution Engine
   ↓
"How should we place the order?"
Enter fullscreen mode Exit fullscreen mode

The strategy shouldn't be responsible for everything.

For example, the risk layer can check:

  • maximum position size
  • exposure
  • duplicate orders
  • market liquidity
  • data freshness
  • trading status
  • other configured limits

That makes the strategy easier to test and modify.


9. Execution is another state machine

Placing an order isn't the end of the process.

The execution layer needs to handle states such as:

NO_ORDER
   ↓
ORDER_REQUESTED
   ↓
OPEN
   ↓
FILLED
Enter fullscreen mode Exit fullscreen mode

But real systems also have failure paths:

ORDER_REQUESTED
      ↓
   FAILED
      ↓
   RETRY / ABORT
Enter fullscreen mode Exit fullscreen mode

or:

OPEN
  ↓
PARTIALLY_FILLED
  ↓
FILLED
Enter fullscreen mode Exit fullscreen mode

The exact behavior should be defined before connecting the strategy to real execution.


10. Logging every important event

When a trading system behaves unexpectedly, you need to reconstruct what happened.

Useful events include:

DATA_RECEIVED
WINDOW_STARTED
TWAP_UPDATED
DATA_STALE
SIGNAL_GENERATED
RISK_CHECK
ORDER_SUBMITTED
ORDER_FILLED
ORDER_FAILED
WEBSOCKET_DISCONNECTED
WEBSOCKET_RECONNECTED
WINDOW_SETTLED
Enter fullscreen mode Exit fullscreen mode

A useful event log lets you answer:

Why did the bot make this trade?

without guessing.

That becomes especially valuable when comparing live behavior with backtest assumptions.


11. Backtesting isn't enough

A strategy can look good in a backtest and still fail during live execution.

The backtest may not fully represent:

  • latency
  • slippage
  • liquidity
  • stale data
  • API failures
  • reconnects
  • partial fills
  • rate limits
  • timing differences

So I think about testing in layers:

Backtest
   ↓
Simulation
   ↓
Paper Trading
   ↓
Small Live Test
   ↓
Production
Enter fullscreen mode Exit fullscreen mode

Each stage should answer different questions.


12. The complete system

Putting everything together:

                 ┌──────────────────┐
                 │  Market / Oracle │
                 └────────┬─────────┘
                          ↓
                 ┌──────────────────┐
                 │ Data Validation  │
                 └────────┬─────────┘
                          ↓
                 ┌──────────────────┐
                 │ TWAP Window      │
                 │ State Manager    │
                 └────────┬─────────┘
                          ↓
                 ┌──────────────────┐
                 │ Projected TWAP   │
                 └────────┬─────────┘
                          ↓
                 ┌──────────────────┐
                 │ Signal Engine    │
                 └────────┬─────────┘
                          ↓
                 ┌──────────────────┐
                 │ Risk Engine      │
                 └────────┬─────────┘
                          ↓
                 ┌──────────────────┐
                 │ CLOB Execution   │
                 └────────┬─────────┘
                          ↓
                 ┌──────────────────┐
                 │ Event Logging    │
                 └──────────────────┘
Enter fullscreen mode Exit fullscreen mode

The interesting part isn't any individual component.

It's how they behave together when something goes wrong.


13. The biggest lesson

A trading bot isn't just a strategy wrapped around an API.

A production-oriented trading system needs to understand:

data → state → strategy → risk → execution → recovery

That's particularly important for short-duration prediction markets, where a small timing or data-quality problem can change the entire decision.

For me, the goal isn't simply to make a script that can place an order.

It's to build a system that knows:

when to trade, how to trade, and when not to trade.

I'm continuing to experiment with Polymarket trading infrastructure, TWAP-based strategies, real-time market data, and automated execution.

Trading experiments can involve substantial risk. Backtests, simulations, and historical results do not guarantee future performance.

Top comments (0)