DEV Community

Cover image for Polymarket Binary Hedging Arbitrage: From Concept to Live Execution
Dream
Dream

Posted on

Polymarket Binary Hedging Arbitrage: From Concept to Live Execution

I. The Binary Market Structure of Polymarket

Polymarket is a prediction market where each question has only two possible outcomes — Yes or No, Up or Down, Win or Lose.

Take the BTC 15-minute price contract as an example. In each round, there are two contracts: Up and Down. The bet is whether BTC's closing price after 15 minutes will be higher or lower than the opening price.

  • If your side is correct → it pays $1
  • If your side is wrong → it pays $0

This market has an extremely special property:

The probabilities of the two outcomes must sum to 100%. Therefore, the price of Up plus the price of Down should theoretically equal exactly 1.


This property does not exist in ordinary futures markets. It provides us with a natural deterministic anchor.

II. Core Arbitrage Logic: Finding Certainty in Uncertainty

Quantitative trading essentially does one thing: find relatively certain opportunities in an uncertain market.

The binary structure of Polymarket provides such an anchor:

No matter whether BTC goes up or down during these 15 minutes, either Up or Down must settle at $1.

Using this anchor, we do not need to predict direction. We only need to find a moment when the combined cost of buying Up and Down is less than 1. Once that condition is met, the profit is locked in at the moment of purchase.

However, most of the time the market keeps the sum tightly around 1. Direct arbitrage opportunities are rare.

So where do the opportunities come from?

III. The Opportunity Window: Price Imbalance During Market Overreaction

Opportunities arise from price imbalance during market overreaction.

Imagine this scenario:

During a 15-minute round, BTC suddenly drops sharply. Panic spreads. The Up contract is heavily sold, and its price falls from 0.50 to 0.35.

In theory, if Up drops by 0.15, Down should rise by 0.15 so that their sum remains 1. But markets do not react symmetrically in real time. Up may have already crashed to 0.35, while Down is still moving upward from 0.50 toward 0.65 and hasn't fully caught up.

In that transitional moment, the sum may temporarily be:


This is the arbitrage window.

You spend 0.93 to buy a combination that must pay out 1 dollar.
The profit is already determined at the moment of purchase.

IV. The Original Idea: Four-Parameter Serial Version

The original idea came from Twitter blogger @the_smart_ape.
It is elegant and minimal, using only four parameters:


Execution logic:

During the monitoring window at the start of each round, continuously track price.

If one side drops more than the trigger threshold → buy it as Leg 1.

Wait for the opposite side's price to fall back.

When both legs' total price falls below the target → buy Leg 2.

Hold until settlement and collect payout.

The idea is clean and efficient. But in live trading, several problems appear.

V. Our Improvement: Proactively Locking Arbitrage Space

The original idea is passive:

  • Buy Leg 1
  • Wait for Leg 2 to become cheap enough

Our improvement is different:

At the moment of the dump, there is a high probability that Up and Down move at different speeds. We act simultaneously during this dislocation.

Execution logic:

  • Leg 1: Place a limit buy at dump price plus slippage.
  • Leg 2: Reverse-calculate price using SUM_TARGET - leg1Price
  • Submit both orders concurrently.

At the moment the orders are placed, the arbitrage space is already locked.
We are no longer waiting for the market to meet our condition — we let the market come to us.

Core implementation:

function executeBothLegs(symbols, dumpSide, dumpAsk) {
    var leg1Symbol = (dumpSide === "Up") ? symbols.up   : symbols.down
    var leg2Symbol = (dumpSide === "Up") ? symbols.down : symbols.up

    leg1Price = _N(dumpAsk + SLIPPAGE, 4)
    leg2Price = _N(SUM_TARGET - leg1Price, 4)

    var goLeg1 = exchange.Go("CreateOrder", leg1Symbol, "buy", leg1Price, SHARES)
    var goLeg2 = exchange.Go("CreateOrder", leg2Symbol, "buy", leg2Price, SHARES)

    var id1 = goLeg1.wait()
    var id2 = goLeg2.wait()

    leg1OrderId = id1
    leg2OrderId = id2
    state = STATE.BOTH_PENDING
}

Enter fullscreen mode Exit fullscreen mode

VI. Problem One: Leg 1 Fills but Price Never Recovers

Reality often looks like this:

  • Up crashes
  • You buy Leg 1
  • Down never pulls back
  • Market sentiment remains bearish You are stuck holding a single-sided position that may go to zero at settlement.

A stop-loss is mandatory.

Patch 1: Floor Price + Early Take Profit
We introduce two parameters:

  • FLOOR_PRICE: If price drops to a deep absolute level (e.g., 0.05), exit immediately.
  • EARLY_TAKE_PROFIT: If Leg 1 rises enough before Leg 2 fills, sell and take profit early.
function handleLeg1OnlyRisk(symbols, upBid, downBid, isLastMin) {
    var holdBid    = (leg1Side === "Up") ? upBid : downBid
    var profitLine = leg1EntryAsk * (1 + EARLY_TAKE_PROFIT)
    var stopLine   = leg1EntryAsk * (1 - LAST_MIN_STOP_LOSS)

    var needClose = false
    var reason    = ""

    if (holdBid <= FLOOR_PRICE) {
        needClose = true; reason = "FLOOR_PRICE"
    } else if (!isLastMin && holdBid >= profitLine) {
        needClose = true; reason = "EARLY_TAKE_PROFIT"
    } else if (isLastMin && holdBid <= stopLine) {
        needClose = true; reason = "STOP_LOSS"
    }

    if (needClose) {
        cancelAndConfirmUntilClear(leg2OrderId)
        closePosition(holdSymbol, holdBid, reason)
    }
}

Enter fullscreen mode Exit fullscreen mode

This caps downside and locks upside.

  • VII. Problem Two: Special Handling Near Settlement Near settlement, market behavior changes dramatically.

There may not be enough time for mean reversion. Volatility often increases.

Patch 2: Last-Minute Logic
We introduce LAST_MIN_S:

When entering the final phase:

  • Stop attempting Leg 2
  • Apply LAST_MIN_STOP_LOSS
  • If not stopped out, hold to settlement
var isLastMin = (remaining <= LAST_MIN_S)

if (isLastMin) {
    Log("⏰ In the last minute, cancel the pending orders that have not been executed")
    cancelAllPending("the last minute")
}

Enter fullscreen mode Exit fullscreen mode

Early phase = wait for recovery
Late phase = avoid going to zero

VIII. Problem Three: On-Chain Latency

Polymarket is on-chain.

Order confirmation and position updates may take several seconds.

We add:

  • Order timeout detection
  • Cancellation and retry mechanism
  • Slippage parameter to increase fill probability
function placeOrderAndConfirm(symbol, side, price, amount) {
    var orderId = exchange.CreateOrder(symbol, side, orderPrice, amount)

    var deadline = Date.now() + ORDER_TIMEOUT_S * 1000
    while (Date.now() < deadline) {
        var order = exchange.GetOrder(orderId)
        if (order && order.Status === 1) {
            return { orderId: orderId, avgPrice: order.AvgPrice }  
        }
        if (order && (order.Status === 2 || order.Status === 4)) {
            return { orderId: orderId, avgPrice: null }  
        }
        Sleep(1000)
    }

    exchange.CancelOrder(orderId)
}

Enter fullscreen mode Exit fullscreen mode

This ensures execution reliability in a blockchain environment.

IX. Redeem Mechanism

Polymarket has a special feature:

After settlement, funds are not automatically returned to balance.

You must manually call the Redeem function to unlock capital.

If forgotten, capital remains stuck.

The strategy automatically calls Redeem each round to ensure capital recycling.

function doRedeem() {
    var positions = exchange.GetPositions()
    for (var i = 0; i < positions.length; i++) {
        var pos = positions[i]
        if (pos.Info && pos.Info.redeemable) {
            var result = exchange.IO("redeem", pos.Symbol, true)
            Log("Redeem :", result)
        }
    }
}

if (!redeemDone && elapsed >= 840) {
    doRedeem()
    redeemDone = true
}

Enter fullscreen mode Exit fullscreen mode

X. Real-Time Monitoring Dashboard

The strategy includes a real-time monitoring panel displaying:

  • Account balance
  • Strategy state
  • Price monitoring
  • Position details and floating P/L

This allows full visibility during live trading.

XI. Live Trading Example & Strategy Limitations


Example:
A new round begins. Down drops 18.6% from 0.43 to 0.35.

  • Both legs are placed simultaneously:

Leg 1 Down at 0.37
Leg 2 Up at 0.60
Total = 0.97 (< target)

  • Actual fill:

Leg 1 = 0.34
Leg 2 = 0.60
Total cost = 0.94

Profit exceeded expectation.

Three Honest Limitations

  1. No opportunity in calm markets. Arbitrage depends on overreaction. In stable markets, the strategy idles.
  2. Single-leg exposure risk. If Leg 2 never fills, Leg 1 may hit stop loss. Stop parameters are a trade-off.
  3. SUM_TARGET threshold trade-off. High threshold → frequent but small profits. Low threshold → rare but large profits.

This defines the strategy's style.

XII. Future Optimization Directions

  • Integrate External BTC Price Feed. Pause entries during strong trending markets.
  • Mathematical Modeling. Up and Down are essentially binary options. Option pricing theory could model:
    • Probability of imbalance
    • Optimal entry timing
    • Expected value more rigorously
  • Dynamic Parameter Adjustment. Current parameters are static. Volatility changes constantly. Adaptive parameters would significantly improve robustness.

Final Thoughts

The core idea — exploiting temporary mispricing in binary markets — is not limited to Polymarket BTC contracts.
Any binary-structured market with short-term pricing inefficiencies can apply similar logic.
What we built is merely a framework.
The truly interesting work begins from here.

Strategy Source Code:
Polymarket BTC 15-Minute Dual-Leg Hedged Arbitrage Bot (Two-Sided Hedge Version)

Top comments (0)