<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Benjamin-Cup</title>
    <description>The latest articles on DEV Community by Benjamin-Cup (@benjamin_cup).</description>
    <link>https://dev.to/benjamin_cup</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3545650%2F71e51628-5e8b-4caf-a7c4-8805fdda2132.png</url>
      <title>DEV Community: Benjamin-Cup</title>
      <link>https://dev.to/benjamin_cup</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/benjamin_cup"/>
    <language>en</language>
    <item>
      <title>Building Polymarket Trading Bot: From Backtesting to Live Trading(Market Maker)</title>
      <dc:creator>Benjamin-Cup</dc:creator>
      <pubDate>Fri, 06 Nov 2026 18:45:18 +0000</pubDate>
      <link>https://dev.to/benjamin_cup/building-polymarket-trading-bot-from-backtesting-to-live-tradingmarket-maker-457h</link>
      <guid>https://dev.to/benjamin_cup/building-polymarket-trading-bot-from-backtesting-to-live-tradingmarket-maker-457h</guid>
      <description>&lt;p&gt;&lt;strong&gt;Day 10 — Polymarket Trading Bot Development Series&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A market-making strategy can perform well in historical simulations. But can it survive in a real market?&lt;/p&gt;

&lt;p&gt;Moving from backtesting to live trading introduces a completely different set of engineering challenges.&lt;/p&gt;

&lt;p&gt;Your bot must do more than calculate bid and ask prices. It needs to communicate with the exchange, manage orders, handle partial fills, recover from network failures, monitor inventory, and protect capital.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9hu6aajyh6mbzwj4a3m9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9hu6aajyh6mbzwj4a3m9.png" alt="Polymarket Trading Bot" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Consider this situation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your bot submits a BUY order for 100 YES tokens.&lt;/li&gt;
&lt;li&gt;The exchange fills 40 tokens.&lt;/li&gt;
&lt;li&gt;The remaining 60 tokens are still open.&lt;/li&gt;
&lt;li&gt;The market price suddenly changes.&lt;/li&gt;
&lt;li&gt;Your bot requests cancellation.&lt;/li&gt;
&lt;li&gt;The network connection times out.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;What should happen next?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Should the bot assume the order was canceled? Should it submit another order?&lt;/p&gt;

&lt;p&gt;Making the wrong decision could create unexpected exposure.&lt;/p&gt;

&lt;p&gt;In this article, we'll explore how to build a safer production architecture for a Python-based Polymarket market maker.&lt;/p&gt;

&lt;p&gt;We'll cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backtesting vs. paper trading vs. live trading&lt;/li&gt;
&lt;li&gt;Production system architecture&lt;/li&gt;
&lt;li&gt;Separating strategy from execution&lt;/li&gt;
&lt;li&gt;Order lifecycle management&lt;/li&gt;
&lt;li&gt;API errors and network recovery&lt;/li&gt;
&lt;li&gt;Risk management&lt;/li&gt;
&lt;li&gt;Production monitoring&lt;/li&gt;
&lt;li&gt;Database persistence&lt;/li&gt;
&lt;li&gt;VPS deployment&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  1. Understand the Three Stages of Trading
&lt;/h2&gt;

&lt;p&gt;Before deploying a trading bot, understand these three development stages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 1: Backtesting
&lt;/h3&gt;

&lt;p&gt;Backtesting uses historical market data to simulate how your strategy would have performed.&lt;/p&gt;

&lt;p&gt;Typical operations include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replaying historical YES and NO prices.&lt;/li&gt;
&lt;li&gt;Calculating bid and ask prices.&lt;/li&gt;
&lt;li&gt;Simulating order fills.&lt;/li&gt;
&lt;li&gt;Tracking inventory.&lt;/li&gt;
&lt;li&gt;Calculating historical P&amp;amp;L.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is to evaluate your strategy using past market conditions.&lt;/p&gt;

&lt;p&gt;However, historical simulations cannot perfectly reproduce real exchange execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 2: Paper Trading
&lt;/h3&gt;

&lt;p&gt;Paper trading runs your strategy against current market data without submitting real orders.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market midpoint: 0.50

Bot calculates:
BUY YES:  0.48
SELL YES: 0.52

Paper Trading:
BUY YES: 0.48
Status: Simulated Open Order

Market changes:
Best Ask: 0.48

Simulated Fill:
20 YES tokens
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No real money is involved.&lt;/p&gt;

&lt;p&gt;Paper trading helps test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Live market data connections.&lt;/li&gt;
&lt;li&gt;Strategy calculations.&lt;/li&gt;
&lt;li&gt;Order management.&lt;/li&gt;
&lt;li&gt;Inventory tracking.&lt;/li&gt;
&lt;li&gt;Logging and monitoring.&lt;/li&gt;
&lt;li&gt;Recovery after restarting the bot.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, simulated fills cannot perfectly reproduce real queue priority, matching behavior, or exchange latency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 3: Live Trading
&lt;/h3&gt;

&lt;p&gt;Live trading connects your bot to the actual exchange and submits real orders.&lt;/p&gt;

&lt;p&gt;Now your system must handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real account balances.&lt;/li&gt;
&lt;li&gt;Actual order execution.&lt;/li&gt;
&lt;li&gt;Partial fills.&lt;/li&gt;
&lt;li&gt;Trading fees.&lt;/li&gt;
&lt;li&gt;API failures.&lt;/li&gt;
&lt;li&gt;Network interruptions.&lt;/li&gt;
&lt;li&gt;Cancellation requests.&lt;/li&gt;
&lt;li&gt;Financial risk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Never move directly from backtesting to large live orders.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Design a Production Architecture
&lt;/h2&gt;

&lt;p&gt;A common mistake is putting the entire trading system into one Python file.&lt;/p&gt;

&lt;p&gt;A better approach is separating responsibilities into independent components.&lt;/p&gt;

&lt;p&gt;Here is a recommended architecture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              Polymarket
                  |
                  v
          Market Data Service
                  |
                  v
            Strategy Engine
                  |
                  v
             Risk Manager
                  |
                  v
           Order Management
                  |
                  v
           Execution Adapter
                  |
                  v
              Polymarket
                  |
                  v
           Order / Trade Events
                  |
                  v
           Portfolio Manager
                  |
             +----+----+
             |         |
             v         v
         Monitoring  Database
             |         |
             +----+----+
                  |
                  v
              Dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's understand the responsibilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Market Data Service&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Collects order book updates, best bid and ask prices, trades, token identifiers, and market status.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strategy Engine&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Contains the market-making logic. It calculates reference prices, spreads, inventory adjustments, and desired order sizes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Risk Manager&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Checks whether proposed orders are allowed before they reach the exchange.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Order Management&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tracks order creation, open orders, partial fills, cancellation requests, and order replacement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Execution Adapter&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Communicates with the exchange API and translates internal order instructions into exchange requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Portfolio Manager&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tracks available cash, YES and NO inventory, average cost, realized P&amp;amp;L, unrealized P&amp;amp;L, fees, and open-order exposure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monitoring&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tracks bot health, active orders, market data freshness, API latency, errors, and risk-limit violations.&lt;/p&gt;

&lt;p&gt;Separating these responsibilities makes the system easier to test, debug, and maintain.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Separate Strategy from Execution
&lt;/h2&gt;

&lt;p&gt;One of the most important architectural decisions is separating the strategy engine from the execution engine.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because the same strategy should work in three different environments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Historical backtesting&lt;/li&gt;
&lt;li&gt;Paper trading&lt;/li&gt;
&lt;li&gt;Live trading&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The strategy should decide &lt;strong&gt;what it wants to do&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The execution layer should decide &lt;strong&gt;how to perform that action&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, define an internal order model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderIntent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;token_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BUY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;
    &lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This object describes a proposed order. It does not submit anything to Polymarket.&lt;/p&gt;

&lt;p&gt;Next, define an execution interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Protocol&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExecutionClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Protocol&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;submit_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OrderIntent&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cancel_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_open_orders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_balances&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Different execution implementations can follow the same interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;          ExecutionClient
                 |
       +---------+---------+
       |         |         |
       v         v         v
    Backtest   Paper     Live
    Client     Client    Client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The strategy doesn't need to know which execution environment is being used.&lt;/p&gt;

&lt;p&gt;This makes testing much easier because you can evaluate the same strategy without risking real capital.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This is an internal interface example, not a claim that Polymarket's SDK provides these exact method names.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Build a Safe Order Lifecycle Manager
&lt;/h2&gt;

&lt;p&gt;Order management is one of the most important parts of a market-making system.&lt;/p&gt;

&lt;p&gt;Imagine your bot submits a BUY order for 100 YES tokens.&lt;/p&gt;

&lt;p&gt;The exchange reports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Original Quantity: 100
Filled Quantity:    30
Remaining Quantity: 70
Status: PARTIALLY_FILLED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The strategy recalculates its quotes and decides to cancel the original order.&lt;/p&gt;

&lt;p&gt;But cancellation takes time.&lt;/p&gt;

&lt;p&gt;During that period, another 20 tokens might be filled.&lt;/p&gt;

&lt;p&gt;Your final filled quantity is now 50, not 30.&lt;/p&gt;

&lt;p&gt;Your bot must correctly handle this situation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recommended internal order states
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             NEW
              |
              v
          SUBMITTING
              |
              v
             OPEN
              |
       +------+------+
       |             |
       v             v
PARTIALLY_FILLED  CANCEL_PENDING
       |             |
       |        +----+----+
       |        |         |
       v        v         v
    FILLED   CANCELED  PARTIALLY_FILLED
                         |
                         v
                       FILLED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact exchange statuses may differ. These are suggested internal states.&lt;/p&gt;

&lt;p&gt;The most important distinction is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Requesting cancellation is not the same as confirming cancellation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, an order may receive additional fills while cancellation is pending.&lt;/p&gt;

&lt;p&gt;Your system must process the final exchange state rather than assume that the cancellation request immediately stopped execution.&lt;/p&gt;

&lt;p&gt;Also, every execution should have a unique identifier so duplicate trade events cannot increase inventory twice.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Handle API Errors and Network Failures
&lt;/h2&gt;

&lt;p&gt;Live trading systems must expect failures.&lt;/p&gt;

&lt;p&gt;Common problems include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Network timeouts&lt;/li&gt;
&lt;li&gt;API rate limits&lt;/li&gt;
&lt;li&gt;Authentication failures&lt;/li&gt;
&lt;li&gt;Insufficient balances&lt;/li&gt;
&lt;li&gt;Exchange maintenance&lt;/li&gt;
&lt;li&gt;WebSocket disconnections&lt;/li&gt;
&lt;li&gt;Delayed responses&lt;/li&gt;
&lt;li&gt;Unexpected API responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One particularly dangerous situation happens when an order submission times out.&lt;/p&gt;

&lt;p&gt;Consider this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bot submits BUY order for 100 YES
                |
                v
       Exchange accepts order
                |
                v
       Network connection fails
                |
                v
          Bot receives timeout
                |
                v
       Bot submits another order
                |
                v
       Potential duplicate exposure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bot doesn't know whether the original order was accepted.&lt;/p&gt;

&lt;p&gt;Blindly retrying could create two orders instead of one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use an uncertain-order state
&lt;/h3&gt;

&lt;p&gt;A safer workflow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;          SUBMITTING
               |
               v
             TIMEOUT
               |
               v
       SUBMISSION_UNKNOWN
               |
               v
      RECONCILE WITH EXCHANGE
               |
         +-----+-----+
         |     |     |
         v     v     v
       FOUND NOT FOUND
               |
               v
         STILL UNCERTAIN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a submission response is uncertain:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Do not immediately submit another identical order.&lt;/li&gt;
&lt;li&gt;Check the exchange's current order state.&lt;/li&gt;
&lt;li&gt;Search using available order identifiers.&lt;/li&gt;
&lt;li&gt;Reconcile open orders and recent trades.&lt;/li&gt;
&lt;li&gt;Retry only when there is sufficient evidence that the original request was not accepted.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Use client-generated identifiers or idempotency mechanisms only where officially supported by the exchange API.&lt;/p&gt;

&lt;p&gt;For read operations, exponential backoff can help:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;retry_read_operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_attempts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_attempts&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;TimeoutError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;max_attempts&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt;

            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not apply this same blind retry approach to financial actions such as order creation.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Implement Risk Management
&lt;/h2&gt;

&lt;p&gt;A profitable strategy is not automatically a safe strategy.&lt;/p&gt;

&lt;p&gt;The risk manager should have the final decision about whether an order can be submitted.&lt;/p&gt;

&lt;p&gt;Here are some essential controls.&lt;/p&gt;

&lt;h3&gt;
  
  
  Maximum order size
&lt;/h3&gt;

&lt;p&gt;Prevent individual orders from becoming too large.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_order_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;maximum_quantity&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;quantity&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;maximum_quantity&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Maximum inventory
&lt;/h3&gt;

&lt;p&gt;Set separate limits for YES and NO positions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_inventory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;current_quantity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;proposed_quantity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;maximum_quantity&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;current_quantity&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;proposed_quantity&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;maximum_quantity&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A complete implementation must also account for sells, existing orders, pending cancellations, and potential fills.&lt;/p&gt;

&lt;h3&gt;
  
  
  Maximum capital allocation
&lt;/h3&gt;

&lt;p&gt;Don't allow the strategy to use all available funds just because it finds trading opportunities.&lt;/p&gt;

&lt;p&gt;Example configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;risk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;max_capital_allocation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
  &lt;span class="na"&gt;max_order_value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
  &lt;span class="na"&gt;max_yes_inventory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
  &lt;span class="na"&gt;max_no_inventory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
  &lt;span class="na"&gt;max_open_orders&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
  &lt;span class="na"&gt;max_daily_loss&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These values are illustrative, not financial recommendations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stale market data protection
&lt;/h3&gt;

&lt;p&gt;Imagine your WebSocket disconnects.&lt;/p&gt;

&lt;p&gt;Your bot still remembers that the market midpoint was 0.50, but the actual market has moved to 0.42.&lt;/p&gt;

&lt;p&gt;Continuing to submit orders using old prices can create unnecessary risk.&lt;/p&gt;

&lt;p&gt;A simple freshness check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_market_data_fresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;last_update_timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;maximum_age_seconds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;last_update_timestamp&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;maximum_age_seconds&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If market data becomes too old, stop submitting new quotes until the feed is restored and reconciled.&lt;/p&gt;

&lt;h3&gt;
  
  
  Emergency stop
&lt;/h3&gt;

&lt;p&gt;Every production trading bot needs a way to stop new trading activity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TradingSafety&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;can_trade&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember that stopping new orders and canceling existing orders are two different operations.&lt;/p&gt;

&lt;p&gt;Your emergency-stop procedure should define both behaviors and be tested before deployment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consider open-order exposure
&lt;/h3&gt;

&lt;p&gt;A common mistake is checking only filled inventory.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Current YES Inventory: 80
Open BUY Orders:       50

Potential Exposure:   130
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though the bot currently holds only 80 YES tokens, another 50 could still be filled.&lt;/p&gt;

&lt;p&gt;Risk management must consider this potential exposure.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Monitor Your Bot in Production
&lt;/h2&gt;

&lt;p&gt;A bot that is running is not necessarily a bot that is working correctly.&lt;/p&gt;

&lt;p&gt;Imagine your VPS runs overnight.&lt;/p&gt;

&lt;p&gt;At 03:00:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The WebSocket disconnects.&lt;/li&gt;
&lt;li&gt;Market data stops updating.&lt;/li&gt;
&lt;li&gt;An order remains open.&lt;/li&gt;
&lt;li&gt;The strategy continues using old prices.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without monitoring, you might not discover the problem until much later.&lt;/p&gt;

&lt;p&gt;A production monitoring system should track four main categories.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Market Data&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Last market update time&lt;/li&gt;
&lt;li&gt;WebSocket connection status&lt;/li&gt;
&lt;li&gt;Order book update frequency&lt;/li&gt;
&lt;li&gt;Data validation failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Execution&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Submitted orders&lt;/li&gt;
&lt;li&gt;Open orders&lt;/li&gt;
&lt;li&gt;Canceled orders&lt;/li&gt;
&lt;li&gt;Partial and full fills&lt;/li&gt;
&lt;li&gt;Submission errors&lt;/li&gt;
&lt;li&gt;Cancellation errors&lt;/li&gt;
&lt;li&gt;Execution latency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Portfolio&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Available balance&lt;/li&gt;
&lt;li&gt;YES and NO inventory&lt;/li&gt;
&lt;li&gt;Open-order exposure&lt;/li&gt;
&lt;li&gt;Realized and unrealized P&amp;amp;L&lt;/li&gt;
&lt;li&gt;Trading fees&lt;/li&gt;
&lt;li&gt;Total portfolio equity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;System&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU and memory usage&lt;/li&gt;
&lt;li&gt;Process uptime&lt;/li&gt;
&lt;li&gt;Restart count&lt;/li&gt;
&lt;li&gt;API response time&lt;/li&gt;
&lt;li&gt;Database errors&lt;/li&gt;
&lt;li&gt;Application exceptions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use structured logging so you can search by order ID, market ID, token ID, and error type.&lt;/p&gt;

&lt;p&gt;Never put private keys, passwords, or API secrets into application logs.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Build a Production Dashboard
&lt;/h2&gt;

&lt;p&gt;A dashboard helps you understand your bot's condition without reading every log entry.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;====================================
       POLYMARKET MARKET MAKER
====================================

BOT STATUS
Status: RUNNING
Mode: PAPER
Uptime: 12h 34m

MARKET DATA
WebSocket: CONNECTED
Last Update: 0.2s ago
Market: BTC YES/NO

ORDERS
Open Orders: 4
Submitted Today: 25
Partial Fills: 6
Completed Fills: 12

PORTFOLIO
YES Inventory: 80
NO Inventory: 60
Available Balance: $85.00

PERFORMANCE
Realized P&amp;amp;L: $2.50
Unrealized P&amp;amp;L: $0.80
Trading Costs: $0.35

RISK
Maximum Inventory: NORMAL
Daily Loss Limit: NORMAL
Market Data: FRESH

====================================
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dashboard should clearly distinguish paper-trading results from actual live account values.&lt;/p&gt;

&lt;p&gt;It should also show when data is unavailable or stale instead of displaying old values as if they were current.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. Preserve Trading State with a Database
&lt;/h2&gt;

&lt;p&gt;What happens if your VPS restarts unexpectedly?&lt;/p&gt;

&lt;p&gt;If your bot stores everything only in Python variables, it may lose important information about previous orders and inventory.&lt;/p&gt;

&lt;p&gt;A database helps preserve the system's state.&lt;/p&gt;

&lt;p&gt;You may need tables such as:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Table&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bot_orders&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Order IDs, prices, quantities, and statuses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bot_trades&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Individual executions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;inventory&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Current YES and NO positions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;market_snapshots&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Historical market data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bot_events&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Important operational events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;risk_events&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Risk violations and emergency stops&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A simplified SQL example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;bot_orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;BIGSERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;exchange_order_id&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;market_id&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;token_id&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;side&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;original_quantity&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;filled_quantity&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For execution records:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;bot_trades&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;BIGSERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;exchange_trade_id&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;exchange_order_id&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;token_id&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;side&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;quantity&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;executed_at&lt;/span&gt; &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The unique execution identifier helps prevent duplicate fills from being recorded twice.&lt;/p&gt;

&lt;p&gt;For financial calculations, use exact decimal arithmetic rather than ordinary floating-point calculations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Your local database should not automatically be treated as the source of truth for current exchange state.&lt;/p&gt;

&lt;p&gt;After restarting, reconcile your stored records against the exchange's open orders, recent trades, and account balances.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Recover Safely After a Restart
&lt;/h2&gt;

&lt;p&gt;Restarting a trading bot requires more than simply running the Python application again.&lt;/p&gt;

&lt;p&gt;Imagine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Three orders were open.&lt;/li&gt;
&lt;li&gt;Two orders had partial fills.&lt;/li&gt;
&lt;li&gt;The VPS restarted.&lt;/li&gt;
&lt;li&gt;The Python process started again.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The bot must understand what happened before it starts trading.&lt;/p&gt;

&lt;p&gt;A recommended startup sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;          Start Bot
              |
              v
       Load Configuration
              |
              v
       Connect to Exchange
              |
              v
        Retrieve Balances
              |
              v
       Retrieve Open Orders
              |
              v
       Retrieve Recent Trades
              |
              v
      Reconcile Local Database
              |
              v
       Validate Market Data
              |
              v
          Run Risk Checks
              |
              v
       Enable New Quoting
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the exchange state and local database disagree, stop new trading and investigate.&lt;/p&gt;

&lt;p&gt;For example, your database says an order is canceled, but the exchange reports that it is still open.&lt;/p&gt;

&lt;p&gt;You must reconcile that order before continuing.&lt;/p&gt;




&lt;h2&gt;
  
  
  11. Deploy the Bot on a VPS
&lt;/h2&gt;

&lt;p&gt;A VPS (Virtual Private Server) allows your bot to run continuously without keeping your personal computer switched on.&lt;/p&gt;

&lt;p&gt;A basic deployment architecture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Developer Computer
        |
        v
      Git Push
        |
        v
   Git Repository
        |
        v
       VPS
        |
   +----+----+----+
   |         |    |
   v         v    v
 Python   Database Monitoring
Environment
   |
   v
Market Maker Bot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Basic deployment steps
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — Prepare the server&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Install Python and the required system dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — Clone the repository&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone YOUR_REPOSITORY_URL
&lt;span class="nb"&gt;cd &lt;/span&gt;polymarket-market-maker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3 — Create a virtual environment&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4 — Install dependencies&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 5 — Configure environment variables&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Store authentication credentials securely.&lt;/p&gt;

&lt;p&gt;Never commit real credentials to GitHub.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6 — Start in paper mode&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; src.main &lt;span class="nt"&gt;--mode&lt;/span&gt; paper
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This assumes your application implements a &lt;code&gt;--mode&lt;/code&gt; argument.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 7 — Check logs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Verify that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Market data is updating.&lt;/li&gt;
&lt;li&gt;Strategy calculations are working.&lt;/li&gt;
&lt;li&gt;Simulated orders are recorded.&lt;/li&gt;
&lt;li&gt;Inventory calculations are correct.&lt;/li&gt;
&lt;li&gt;Risk checks are active.&lt;/li&gt;
&lt;li&gt;No unexpected errors appear.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 8 — Configure process supervision&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use an appropriate process manager to monitor the application and control restarts.&lt;/p&gt;

&lt;p&gt;However, automatic restarts do not guarantee trading safety.&lt;/p&gt;

&lt;p&gt;Your application must complete its recovery and reconciliation process before enabling new orders.&lt;/p&gt;




&lt;h2&gt;
  
  
  12. Protect API Credentials
&lt;/h2&gt;

&lt;p&gt;Security is part of production engineering.&lt;/p&gt;

&lt;p&gt;Your bot may need credentials or signing permissions to submit orders.&lt;/p&gt;

&lt;p&gt;Important practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Never publish private keys on GitHub.&lt;/li&gt;
&lt;li&gt;Never hardcode secrets in Python files.&lt;/li&gt;
&lt;li&gt;Use environment variables or a secure secret manager.&lt;/li&gt;
&lt;li&gt;Restrict server access.&lt;/li&gt;
&lt;li&gt;Prefer SSH keys over password-only access.&lt;/li&gt;
&lt;li&gt;Keep dependencies updated.&lt;/li&gt;
&lt;li&gt;Separate testing credentials from production credentials.&lt;/li&gt;
&lt;li&gt;Rotate credentials if they may have been exposed.&lt;/li&gt;
&lt;li&gt;Never print authentication headers or private keys in logs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Evaluate restricted signing permissions or session-based authorization when supported by the current official documentation.&lt;/p&gt;

&lt;p&gt;The goal is to reduce potential damage if your server or application is compromised.&lt;/p&gt;




&lt;h2&gt;
  
  
  13. Follow a Gradual Live-Trading Plan
&lt;/h2&gt;

&lt;p&gt;Don't move directly from backtesting to large live orders.&lt;/p&gt;

&lt;p&gt;Use a controlled rollout.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;Main objective&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Backtesting&lt;/td&gt;
&lt;td&gt;Validate strategy and historical performance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Paper Trading&lt;/td&gt;
&lt;td&gt;Test against current market data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Operational Testing&lt;/td&gt;
&lt;td&gt;Simulate failures and recovery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Small Live Deployment&lt;/td&gt;
&lt;td&gt;Test real execution with strict limits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. Gradual Evaluation&lt;/td&gt;
&lt;td&gt;Evaluate actual performance before increasing exposure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;During operational testing, deliberately simulate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WebSocket disconnections.&lt;/li&gt;
&lt;li&gt;VPS restarts.&lt;/li&gt;
&lt;li&gt;API timeouts.&lt;/li&gt;
&lt;li&gt;Invalid market data.&lt;/li&gt;
&lt;li&gt;Risk-limit violations.&lt;/li&gt;
&lt;li&gt;Partially filled orders.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Confirm that the bot behaves safely in every scenario.&lt;/p&gt;

&lt;p&gt;There is no fixed number of paper-trading hours that proves a strategy is safe. The testing period should depend on market activity and the amount of execution data collected.&lt;/p&gt;




&lt;h2&gt;
  
  
  14. Production Readiness Checklist
&lt;/h2&gt;

&lt;p&gt;Before enabling real orders, review the following checklist.&lt;/p&gt;

&lt;h3&gt;
  
  
  Strategy
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Bid and ask calculations are tested.&lt;/li&gt;
&lt;li&gt;[ ] Dynamic spread logic is tested.&lt;/li&gt;
&lt;li&gt;[ ] Inventory adjustments are working.&lt;/li&gt;
&lt;li&gt;[ ] Stale market data prevents new quotes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Execution
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Order submission is implemented.&lt;/li&gt;
&lt;li&gt;[ ] Order cancellation is implemented.&lt;/li&gt;
&lt;li&gt;[ ] Partial fills are handled.&lt;/li&gt;
&lt;li&gt;[ ] Duplicate execution events are prevented.&lt;/li&gt;
&lt;li&gt;[ ] Unknown submission states are reconciled.&lt;/li&gt;
&lt;li&gt;[ ] Existing orders are checked before replacement.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Portfolio
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] YES inventory is tracked.&lt;/li&gt;
&lt;li&gt;[ ] NO inventory is tracked.&lt;/li&gt;
&lt;li&gt;[ ] Available balances are checked.&lt;/li&gt;
&lt;li&gt;[ ] Open-order exposure is included.&lt;/li&gt;
&lt;li&gt;[ ] Realized and unrealized P&amp;amp;L are separated.&lt;/li&gt;
&lt;li&gt;[ ] Fees and resolution outcomes are accounted for.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Risk
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Maximum order size is configured.&lt;/li&gt;
&lt;li&gt;[ ] Maximum inventory is configured.&lt;/li&gt;
&lt;li&gt;[ ] Capital allocation is limited.&lt;/li&gt;
&lt;li&gt;[ ] Daily loss limits are configured.&lt;/li&gt;
&lt;li&gt;[ ] Emergency-stop behavior is tested.&lt;/li&gt;
&lt;li&gt;[ ] Strategy code cannot bypass risk checks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Infrastructure
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Logs are available.&lt;/li&gt;
&lt;li&gt;[ ] Monitoring is configured.&lt;/li&gt;
&lt;li&gt;[ ] Database records are persistent.&lt;/li&gt;
&lt;li&gt;[ ] Startup reconciliation is implemented.&lt;/li&gt;
&lt;li&gt;[ ] Credentials are protected.&lt;/li&gt;
&lt;li&gt;[ ] VPS access is secured.&lt;/li&gt;
&lt;li&gt;[ ] Backups and recovery procedures are tested.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Building a Polymarket market maker is not just about calculating profitable bid and ask prices.&lt;/p&gt;

&lt;p&gt;A production trading system must manage the entire process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Collect reliable market data.&lt;/li&gt;
&lt;li&gt;Generate trading quotes.&lt;/li&gt;
&lt;li&gt;Validate risk limits.&lt;/li&gt;
&lt;li&gt;Submit and manage orders.&lt;/li&gt;
&lt;li&gt;Track partial fills.&lt;/li&gt;
&lt;li&gt;Manage inventory.&lt;/li&gt;
&lt;li&gt;Recover from failures.&lt;/li&gt;
&lt;li&gt;Monitor performance.&lt;/li&gt;
&lt;li&gt;Preserve state after restarts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The most important lesson is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Never assume an order was filled, canceled, or rejected until you have enough information to confirm its actual state.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Backtesting helps evaluate your strategy.&lt;/p&gt;

&lt;p&gt;Paper trading helps test the system under current market conditions.&lt;/p&gt;

&lt;p&gt;Production engineering makes the system more reliable.&lt;/p&gt;

&lt;p&gt;However, none of these guarantees profitable trading. Real execution introduces financial risks that simulations cannot completely reproduce.&lt;/p&gt;

&lt;p&gt;Before increasing trading activity, focus on making your bot predictable, observable, and recoverable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Continue Building Your Polymarket Trading Bot
&lt;/h2&gt;

&lt;p&gt;If you're following this development series, you can explore the project and tutorials here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;https://github.com/Benj4minCup/Polymarket-Trading-Bot-python&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;YouTube:&lt;/strong&gt; &lt;a href="https://www.youtube.com/watch?v=UCF7MA1Kekk" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=UCF7MA1Kekk&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Telegram:&lt;/strong&gt; &lt;a href="https://telegram.me/BenjaminCup" rel="noopener noreferrer"&gt;https://telegram.me/BenjaminCup&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Coming Next — Day 11
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Advanced Polymarket Market Maker Architecture: WebSockets, Real-Time Order Book Processing, and Low-Latency Execution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the next article, we'll explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WebSocket market data connections.&lt;/li&gt;
&lt;li&gt;Processing real-time order book updates.&lt;/li&gt;
&lt;li&gt;Maintaining local order book state.&lt;/li&gt;
&lt;li&gt;Detecting stale or missing data.&lt;/li&gt;
&lt;li&gt;Asynchronous Python architecture.&lt;/li&gt;
&lt;li&gt;Separating market data and execution tasks.&lt;/li&gt;
&lt;li&gt;Reducing unnecessary API requests.&lt;/li&gt;
&lt;li&gt;Building a more responsive trading system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is to understand how to build a market maker that reacts to changing market conditions without relying on slow, repeated polling.&lt;/p&gt;

&lt;h1&gt;
  
  
  polymarket #trading #bot #tutorial #python
&lt;/h1&gt;

</description>
      <category>polymarket</category>
      <category>python</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Polymarket Trading Bot :Market Maker - How to Backtest Strategies and Optimize Trading Parameters</title>
      <dc:creator>Benjamin-Cup</dc:creator>
      <pubDate>Thu, 05 Nov 2026 23:00:10 +0000</pubDate>
      <link>https://dev.to/benjamin_cup/polymarket-trading-bot-market-maker-how-to-backtest-strategies-and-optimize-trading-parameters-4elm</link>
      <guid>https://dev.to/benjamin_cup/polymarket-trading-bot-market-maker-how-to-backtest-strategies-and-optimize-trading-parameters-4elm</guid>
      <description>&lt;p&gt;&lt;em&gt;Day 9 — Building a Python backtesting framework to simulate order execution, measure performance, and optimize market-making strategies.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the previous article, we built an adaptive market-making strategy that adjusts its spreads based on volatility, liquidity, and inventory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fndn213eyften4a9d7z0d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fndn213eyften4a9d7z0d.png" alt="Polymarket Trading Bot" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But an important question remains:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do we know whether our strategy actually works?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine your Polymarket bot places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;YES buy order at $0.48&lt;/li&gt;
&lt;li&gt;YES sell order at $0.52&lt;/li&gt;
&lt;li&gt;Order quantity: 100 tokens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The theoretical gross profit is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.52&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.48&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mf"&gt;4.00&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Looks profitable, right?&lt;/p&gt;

&lt;p&gt;But what if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your buy order never gets filled?&lt;/li&gt;
&lt;li&gt;Your order is only partially filled?&lt;/li&gt;
&lt;li&gt;The market moves against you immediately after execution?&lt;/li&gt;
&lt;li&gt;Other traders are ahead of you in the order queue?&lt;/li&gt;
&lt;li&gt;Trading costs eliminate your spread?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why we need &lt;strong&gt;backtesting&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this article, we'll build the foundation of a Python backtesting framework for a Polymarket market maker bot.&lt;/p&gt;

&lt;p&gt;We'll cover:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Backtesting fundamentals&lt;/li&gt;
&lt;li&gt;Historical market data&lt;/li&gt;
&lt;li&gt;Market-making quote calculations&lt;/li&gt;
&lt;li&gt;Limit-order execution simulation&lt;/li&gt;
&lt;li&gt;Inventory and P&amp;amp;L tracking&lt;/li&gt;
&lt;li&gt;Performance metrics&lt;/li&gt;
&lt;li&gt;Parameter optimization&lt;/li&gt;
&lt;li&gt;Avoiding overfitting&lt;/li&gt;
&lt;li&gt;Preparing for paper trading&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  1. What Is Backtesting?
&lt;/h2&gt;

&lt;p&gt;Backtesting means testing a trading strategy against historical market data to estimate how it would have performed in the past.&lt;/p&gt;

&lt;p&gt;Instead of immediately connecting your bot to a real trading account, you replay historical market conditions and simulate the decisions your bot would have made.&lt;/p&gt;

&lt;p&gt;Think of it like a flight simulator.&lt;/p&gt;

&lt;p&gt;You can test different situations without risking a real aircraft. Backtesting provides a similar environment for trading strategies.&lt;/p&gt;

&lt;p&gt;For example, we can compare three configurations:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Strategy&lt;/th&gt;
&lt;th&gt;Half-spread&lt;/th&gt;
&lt;th&gt;Order size&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;$0.01&lt;/td&gt;
&lt;td&gt;10 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;$0.02&lt;/td&gt;
&lt;td&gt;10 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;$0.03&lt;/td&gt;
&lt;td&gt;10 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Using the same historical data, we can compare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Number of executed orders&lt;/li&gt;
&lt;li&gt;Captured spread&lt;/li&gt;
&lt;li&gt;Inventory exposure&lt;/li&gt;
&lt;li&gt;Maximum drawdown&lt;/li&gt;
&lt;li&gt;Net profitability&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Backtesting vs. Paper Trading vs. Live Trading
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Real money&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Backtesting&lt;/td&gt;
&lt;td&gt;Replay historical data&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Paper trading&lt;/td&gt;
&lt;td&gt;Simulate current market conditions&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live trading&lt;/td&gt;
&lt;td&gt;Execute real orders&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A successful backtest does not guarantee successful live trading. Each stage reveals different problems.&lt;/p&gt;


&lt;h2&gt;
  
  
  2. Understand the Backtesting Architecture
&lt;/h2&gt;

&lt;p&gt;Before writing code, let's understand the main components.&lt;/p&gt;

&lt;p&gt;A basic backtesting system needs six components:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;       Historical Market Data
                |
                v
        Market Replay Engine
                |
                v
           Strategy Engine
                |
                v
        Execution Simulator
                |
                v
         Portfolio Manager
                |
                v
       Performance Analyzer
                |
                v
          Backtest Results
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Each component has a separate responsibility.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Historical Data&lt;/td&gt;
&lt;td&gt;Stores market snapshots and trades&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replay Engine&lt;/td&gt;
&lt;td&gt;Replays historical events chronologically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strategy Engine&lt;/td&gt;
&lt;td&gt;Calculates bid and ask prices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Execution Simulator&lt;/td&gt;
&lt;td&gt;Simulates order fills&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Portfolio Manager&lt;/td&gt;
&lt;td&gt;Tracks inventory, cash, and P&amp;amp;L&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance Analyzer&lt;/td&gt;
&lt;td&gt;Calculates performance and risk metrics&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One important design principle:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The strategy should propose orders, but the execution simulator should decide whether those orders get filled.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This separation makes the system easier to test and improve.&lt;/p&gt;


&lt;h2&gt;
  
  
  3. Collect Historical Market Data
&lt;/h2&gt;

&lt;p&gt;A backtesting system is only as reliable as its historical data.&lt;/p&gt;

&lt;p&gt;For a Polymarket market maker, useful data includes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Data&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Timestamp&lt;/td&gt;
&lt;td&gt;Reconstruct market events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YES best bid/ask&lt;/td&gt;
&lt;td&gt;Track YES market prices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NO best bid/ask&lt;/td&gt;
&lt;td&gt;Track NO market prices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bid/ask depth&lt;/td&gt;
&lt;td&gt;Measure available liquidity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trade price&lt;/td&gt;
&lt;td&gt;Track executed prices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trade size&lt;/td&gt;
&lt;td&gt;Track executed quantities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Market ID&lt;/td&gt;
&lt;td&gt;Identify the market&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Token ID&lt;/td&gt;
&lt;td&gt;Identify YES or NO tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tick size&lt;/td&gt;
&lt;td&gt;Validate quote prices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fee information&lt;/td&gt;
&lt;td&gt;Calculate trading costs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Market status&lt;/td&gt;
&lt;td&gt;Identify active or resolved markets&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Why Is Order Book Depth Important?
&lt;/h3&gt;

&lt;p&gt;Consider two markets:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Market A&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Available quantity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;$0.49&lt;/td&gt;
&lt;td&gt;1,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$0.48&lt;/td&gt;
&lt;td&gt;800&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$0.47&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Market B&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Available quantity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;$0.49&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$0.48&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$0.47&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Both markets have the same best bid.&lt;/p&gt;

&lt;p&gt;However, their liquidity is completely different.&lt;/p&gt;

&lt;p&gt;If your bot wants to buy 100 tokens, Market A has much more available liquidity.&lt;/p&gt;

&lt;p&gt;This is why using only the best bid and ask is insufficient.&lt;/p&gt;
&lt;h3&gt;
  
  
  Snapshots vs. Event-Level Data
&lt;/h3&gt;

&lt;p&gt;There are two common approaches:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Order book snapshots&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Record the order book at specific intervals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event-level data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Record individual changes, such as orders being added, removed, or executed.&lt;/p&gt;

&lt;p&gt;Event-level data provides more detailed information and is preferable for realistic execution simulation when available.&lt;/p&gt;


&lt;h2&gt;
  
  
  4. Calculate Market Metrics and Quotes
&lt;/h2&gt;

&lt;p&gt;Let's start with basic market calculations.&lt;/p&gt;

&lt;p&gt;The midpoint is:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;midpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;best_bid&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;best_ask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The spread is:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;spread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;best_ask&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;best_bid&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;best_bid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.48&lt;/span&gt;
&lt;span class="n"&gt;best_ask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.52&lt;/span&gt;

&lt;span class="n"&gt;midpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;best_bid&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;best_ask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;spread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;best_ask&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;best_bid&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;midpoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# 0.50
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spread&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# 0.04
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now calculate the market-making quotes.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_quotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;midpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;half_spread&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;bid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;midpoint&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;half_spread&lt;/span&gt;
    &lt;span class="n"&gt;ask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;midpoint&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;half_spread&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ask&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;quotes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_quotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;midpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;half_spread&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.02&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ask&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.52&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is our basic quoting model.&lt;/p&gt;

&lt;p&gt;In production, we must also validate tick size, order quantity, available balance, market status, and inventory risk.&lt;/p&gt;


&lt;h2&gt;
  
  
  5. Simulate Realistic Order Execution
&lt;/h2&gt;

&lt;p&gt;This is one of the most important parts of backtesting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A market price touching your limit order does not automatically mean your order gets filled.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine your bot places a YES buy order at $0.48.&lt;/p&gt;

&lt;p&gt;There are already 300 tokens ahead of your order at that price.&lt;/p&gt;

&lt;p&gt;Another trader sells 50 tokens at $0.48.&lt;/p&gt;

&lt;p&gt;Your order receives nothing because the earlier orders have priority.&lt;/p&gt;

&lt;p&gt;This is called queue position.&lt;/p&gt;

&lt;p&gt;A simplified execution model:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_fill_quantity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;trade_volume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;quantity_ahead&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;remaining_order_quantity&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;available&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;trade_volume&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;quantity_ahead&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;remaining_order_quantity&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;fill&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_fill_quantity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;trade_volume&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;quantity_ahead&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;remaining_order_quantity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# 50
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The estimated fill is 50 tokens.&lt;/p&gt;

&lt;p&gt;This is only an educational approximation. A realistic simulator must account for actual matching rules, queue changes, and available historical data.&lt;/p&gt;
&lt;h3&gt;
  
  
  Important Execution Scenarios
&lt;/h3&gt;

&lt;p&gt;Your simulator should eventually support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No fills&lt;/li&gt;
&lt;li&gt;Full fills&lt;/li&gt;
&lt;li&gt;Partial fills&lt;/li&gt;
&lt;li&gt;Multiple partial fills&lt;/li&gt;
&lt;li&gt;Order cancellations&lt;/li&gt;
&lt;li&gt;Cancellation delays&lt;/li&gt;
&lt;li&gt;Order replacements&lt;/li&gt;
&lt;li&gt;Expired orders&lt;/li&gt;
&lt;li&gt;Network interruptions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A realistic execution simulator is often more valuable than adding another complicated trading indicator.&lt;/p&gt;


&lt;h2&gt;
  
  
  6. Track Order States and Inventory
&lt;/h2&gt;

&lt;p&gt;Your backtesting engine needs to understand the lifecycle of each order.&lt;/p&gt;

&lt;p&gt;A simplified order state machine:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;       NEW
        |
        v
       OPEN
        |
        v
     PARTIAL
      /   \
     v     v
  FILLED  CANCELED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For example, your bot submits an order for 100 YES tokens.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First execution: 30 tokens&lt;/li&gt;
&lt;li&gt;Second execution: 40 tokens&lt;/li&gt;
&lt;li&gt;Remaining quantity: 30 tokens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your system must accurately track the executed quantity and remaining quantity.&lt;/p&gt;

&lt;p&gt;You also need to track YES and NO inventory separately.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Inventory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yes_quantity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;no_quantity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yes_cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;no_cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;buy_yes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yes_quantity&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;quantity&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yes_cost&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;quantity&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;buy_no&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;no_quantity&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;quantity&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;no_cost&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;quantity&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;inventory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Inventory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;buy_yes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.48&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;buy_no&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.47&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yes_quantity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# 100
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;no_quantity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# 50
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A complete portfolio manager should also track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Average cost basis&lt;/li&gt;
&lt;li&gt;Sell quantities&lt;/li&gt;
&lt;li&gt;Realized P&amp;amp;L&lt;/li&gt;
&lt;li&gt;Unrealized P&amp;amp;L&lt;/li&gt;
&lt;li&gt;Trading fees&lt;/li&gt;
&lt;li&gt;Cash balance&lt;/li&gt;
&lt;li&gt;Resolution payouts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember: a market maker is not automatically market-neutral.&lt;/p&gt;

&lt;p&gt;Accumulating too many YES or NO tokens can create significant directional exposure.&lt;/p&gt;


&lt;h2&gt;
  
  
  7. Calculate P&amp;amp;L and Performance Metrics
&lt;/h2&gt;

&lt;p&gt;Let's calculate a simple completed trade.&lt;/p&gt;

&lt;p&gt;Assume:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Buy price: $0.48&lt;/li&gt;
&lt;li&gt;Sell price: $0.52&lt;/li&gt;
&lt;li&gt;Quantity: 100&lt;/li&gt;
&lt;li&gt;Trading costs: $0.30&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gross P&amp;amp;L:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;gross_pnl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.52&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.48&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gross_pnl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# 4.00
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Net P&amp;amp;L:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;net_pnl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gross_pnl&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.30&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;net_pnl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# 3.70
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But total profit is not enough to evaluate a strategy.&lt;/p&gt;

&lt;p&gt;We also need to measure risk.&lt;/p&gt;
&lt;h3&gt;
  
  
  Important Performance Metrics
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Net P&amp;amp;L&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How much money did the strategy make after trading costs?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Fill Rate&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What percentage of submitted order quantity was executed?&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;fill_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;filled_quantity&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;submitted_quantity&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A higher fill rate is not always better. Aggressive quotes can receive more fills but suffer from adverse selection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Maximum Drawdown&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Measures the largest decline from a previous portfolio equity peak.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Portfolio equity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;$1,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;$1,100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;$1,050&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;$950&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;$1,150&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The drawdown from $1,100 to $950 is:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;drawdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1100&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;950&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1100&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;drawdown&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# 0.1364
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's approximately 13.64%.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Adverse Selection&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This happens when your order gets filled and the market immediately moves against you.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your bot buys YES at $0.50.&lt;/li&gt;
&lt;li&gt;The order gets filled.&lt;/li&gt;
&lt;li&gt;The midpoint falls to $0.47.&lt;/li&gt;
&lt;li&gt;Your position loses approximately $0.03 per token at the new midpoint.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A useful measurement is markout:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;buy_markout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;midpoint_after&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;fill_price&lt;/span&gt;
&lt;span class="n"&gt;sell_markout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fill_price&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;midpoint_after&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Measure markout over multiple time horizons, such as 1, 5, and 30 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Inventory Exposure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Track how much capital is tied up in YES and NO positions.&lt;/p&gt;

&lt;p&gt;Also consider the possible resolution outcomes instead of relying only on token quantity differences.&lt;/p&gt;


&lt;h2&gt;
  
  
  8. Optimize Trading Parameters
&lt;/h2&gt;

&lt;p&gt;Now we can start comparing different strategy configurations.&lt;/p&gt;

&lt;p&gt;Some important parameters include:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Example values&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Minimum half-spread&lt;/td&gt;
&lt;td&gt;0.01, 0.02, 0.03&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maximum half-spread&lt;/td&gt;
&lt;td&gt;0.03, 0.05, 0.08&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Order size&lt;/td&gt;
&lt;td&gt;5, 10, 20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maximum inventory&lt;/td&gt;
&lt;td&gt;50, 100, 200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inventory skew&lt;/td&gt;
&lt;td&gt;0.0001, 0.0002&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quote refresh interval&lt;/td&gt;
&lt;td&gt;1s, 2s, 5s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We can define experiments in Python:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;experiments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;baseline&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;half_spread&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.02&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order_size&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;max_inventory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wider_spread&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;half_spread&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.03&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order_size&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;max_inventory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;smaller_inventory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;half_spread&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.02&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order_size&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;max_inventory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Run every configuration against the same historical dataset.&lt;/p&gt;

&lt;p&gt;Then compare the results:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Strategy&lt;/th&gt;
&lt;th&gt;Net P&amp;amp;L&lt;/th&gt;
&lt;th&gt;Fill rate&lt;/th&gt;
&lt;th&gt;Max drawdown&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Baseline&lt;/td&gt;
&lt;td&gt;$50&lt;/td&gt;
&lt;td&gt;45%&lt;/td&gt;
&lt;td&gt;8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wider spread&lt;/td&gt;
&lt;td&gt;$42&lt;/td&gt;
&lt;td&gt;30%&lt;/td&gt;
&lt;td&gt;4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Smaller inventory&lt;/td&gt;
&lt;td&gt;$38&lt;/td&gt;
&lt;td&gt;35%&lt;/td&gt;
&lt;td&gt;2%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;These numbers are hypothetical examples.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The baseline generates the highest profit, but it also has the largest drawdown.&lt;/p&gt;

&lt;p&gt;The smaller-inventory strategy earns less but has lower risk.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't optimize only for maximum historical profit.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider profitability, drawdown, inventory exposure, adverse selection, and consistency.&lt;/p&gt;


&lt;h2&gt;
  
  
  9. Avoid Overfitting
&lt;/h2&gt;

&lt;p&gt;Overfitting is one of the biggest problems in quantitative trading.&lt;/p&gt;

&lt;p&gt;It happens when you adjust a strategy so heavily to historical data that it performs well on past observations but poorly on new market conditions.&lt;/p&gt;

&lt;p&gt;A practical solution is to divide historical data into three periods.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dataset&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Training&lt;/td&gt;
&lt;td&gt;Develop the strategy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validation&lt;/td&gt;
&lt;td&gt;Compare configurations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testing&lt;/td&gt;
&lt;td&gt;Evaluate unseen historical data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;January–March: Training&lt;/li&gt;
&lt;li&gt;April: Validation&lt;/li&gt;
&lt;li&gt;May: Testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These dates are illustrative.&lt;/p&gt;

&lt;p&gt;Keep the periods chronological. Never allow future market information to influence earlier trading decisions.&lt;/p&gt;
&lt;h3&gt;
  
  
  Walk-Forward Testing
&lt;/h3&gt;

&lt;p&gt;Another useful approach is walk-forward testing.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tune parameters using an earlier period.&lt;/li&gt;
&lt;li&gt;Test the selected configuration on the next unseen period.&lt;/li&gt;
&lt;li&gt;Move the testing window forward.&lt;/li&gt;
&lt;li&gt;Repeat.&lt;/li&gt;
&lt;li&gt;Compare performance across all periods.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This helps determine whether your strategy can adapt to changing market conditions.&lt;/p&gt;


&lt;h2&gt;
  
  
  10. Account for Realistic Trading Conditions
&lt;/h2&gt;

&lt;p&gt;A good backtest should not assume perfect execution.&lt;/p&gt;

&lt;p&gt;Consider these factors:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Factor&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Trading fees&lt;/td&gt;
&lt;td&gt;Reduce captured spread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Queue position&lt;/td&gt;
&lt;td&gt;Orders may not receive fills&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Partial fills&lt;/td&gt;
&lt;td&gt;Orders may execute gradually&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency&lt;/td&gt;
&lt;td&gt;Prices can change before execution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cancellation delays&lt;/td&gt;
&lt;td&gt;Orders may fill before cancellation completes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adverse selection&lt;/td&gt;
&lt;td&gt;Filled orders may move against you&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resolution risk&lt;/td&gt;
&lt;td&gt;Open positions have final settlement outcomes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I recommend testing three execution scenarios:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Optimistic:&lt;/strong&gt; Higher fill probability and lower latency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Base case:&lt;/strong&gt; Conservative queue and execution assumptions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stress case:&lt;/strong&gt; Lower fill probability, higher costs, and delayed cancellations.&lt;/p&gt;

&lt;p&gt;If your strategy only works under optimistic assumptions, it needs further investigation.&lt;/p&gt;


&lt;h2&gt;
  
  
  11. Organize the Python Project
&lt;/h2&gt;

&lt;p&gt;As the backtesting system grows, avoid putting everything into one Python file.&lt;/p&gt;

&lt;p&gt;A modular project structure could look like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;polymarket-market-maker/
│
├── config/
│   ├── backtest.yaml
│   └── strategy.yaml
│
├── data/
│   ├── historical/
│   └── processed/
│
├── src/
│   ├── data/
│   │   ├── loader.py
│   │   └── validator.py
│   │
│   ├── strategy/
│   │   ├── market_maker.py
│   │   ├── spread_model.py
│   │   └── inventory_skew.py
│   │
│   ├── execution/
│   │   ├── simulator.py
│   │   ├── order.py
│   │   └── fill_model.py
│   │
│   ├── portfolio/
│   │   ├── inventory.py
│   │   └── pnl.py
│   │
│   ├── backtesting/
│   │   ├── engine.py
│   │   └── metrics.py
│   │
│   └── main.py
│
├── tests/
├── results/
├── requirements.txt
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Each directory has a clear responsibility.&lt;/p&gt;

&lt;p&gt;The main advantage is that the strategy can eventually be reused with different execution adapters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backtesting execution&lt;/li&gt;
&lt;li&gt;Paper trading execution&lt;/li&gt;
&lt;li&gt;Live exchange execution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes the system easier to maintain and extend.&lt;/p&gt;


&lt;h2&gt;
  
  
  12. Common Backtesting Mistakes
&lt;/h2&gt;

&lt;p&gt;Before finishing, remember these common mistakes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Assuming every order gets filled.&lt;/li&gt;
&lt;li&gt;Ignoring trading fees.&lt;/li&gt;
&lt;li&gt;Ignoring partial executions.&lt;/li&gt;
&lt;li&gt;Using future information.&lt;/li&gt;
&lt;li&gt;Optimizing only for historical profit.&lt;/li&gt;
&lt;li&gt;Ignoring remaining inventory.&lt;/li&gt;
&lt;li&gt;Testing on insufficient historical data.&lt;/li&gt;
&lt;li&gt;Treating paper trading as proof of live execution.&lt;/li&gt;
&lt;li&gt;Changing too many parameters simultaneously.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A backtest should help you understand where your strategy fails, not just where it succeeds.&lt;/p&gt;


&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Building a Polymarket market maker bot is not just about calculating attractive bid and ask prices.&lt;/p&gt;

&lt;p&gt;You also need to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Whether your orders can realistically get filled.&lt;/li&gt;
&lt;li&gt;How much inventory they accumulate.&lt;/li&gt;
&lt;li&gt;How execution costs affect profitability.&lt;/li&gt;
&lt;li&gt;How the strategy behaves under different market conditions.&lt;/li&gt;
&lt;li&gt;Whether its performance remains consistent on unseen data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember these three lessons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Realistic execution matters more than impressive backtest profits.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Always test your strategy on historical data it has never seen before.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Risk management and inventory exposure matter as much as profitability.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A strategy that survives realistic simulations and unseen historical periods is a stronger candidate for paper trading.&lt;/p&gt;

&lt;p&gt;However, even a strong backtest cannot guarantee future profitability.&lt;/p&gt;
&lt;h2&gt;
  
  
  What's Next? Day 10
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Polymarket Market Maker Bot: From Backtesting to Live Trading and Production Monitoring&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the next article, we'll explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connecting the strategy to an execution engine.&lt;/li&gt;
&lt;li&gt;Moving from backtesting to paper trading.&lt;/li&gt;
&lt;li&gt;Monitoring orders and partial fills.&lt;/li&gt;
&lt;li&gt;Handling API failures and network interruptions.&lt;/li&gt;
&lt;li&gt;Managing risk during live operation.&lt;/li&gt;
&lt;li&gt;Building production monitoring workflows.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Follow the Project
&lt;/h2&gt;

&lt;p&gt;If you're interested in building a Polymarket trading bot with Python, check out the project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; 
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Benj4minCup" rel="noopener noreferrer"&gt;
        Benj4minCup
      &lt;/a&gt; / &lt;a href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;
        Polymarket-Trading-Bot-python
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      polymarket Twap Bot polymarket Arbitrage Bot polymarket bot 
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Polymarket Trading bot system&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;An open-source and Strong Strategy collection of Polymarket trading bot and Polymarket arbitrage bot and Polymarket TWAP trading bot in Python for high-performance automated trading on polymarket crypto 5min and 15min markets.&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/33036584/633381478-71b65c58-00d2-4bbe-8b6d-8ed6fc9812e4.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3OTM5MTk5MTMsIm5iZiI6MTc5MzkxOTYxMywicGF0aCI6Ii8zMzAzNjU4NC82MzMzODE0NzgtNzFiNjVjNTgtMDBkMi00YmJlLThiNmQtOGVkNmZjOTgxMmU0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjExMDUlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYxMTA1VDIzMDAxM1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTYwYjZhZmUxZjJiNTNhNmQ5ODk1Nzc5Y2RiYjRiNmI4M2UyN2NkYjQ4YjcxYWRjZmZjNTQwYWZhOWE1N2ZhNDImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.aRNOIJnLEyvoQmq-iDAJm4Ufe8MCKdyZ9U2yelwQSQU"&gt;&lt;img width="1536" height="1024" alt="Polymarket-benjamincup-bot-dashboard" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F33036584%2F633381478-71b65c58-00d2-4bbe-8b6d-8ed6fc9812e4.png%3Fjwt%3DeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3OTM5MTk5MTMsIm5iZiI6MTc5MzkxOTYxMywicGF0aCI6Ii8zMzAzNjU4NC82MzMzODE0NzgtNzFiNjVjNTgtMDBkMi00YmJlLThiNmQtOGVkNmZjOTgxMmU0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjExMDUlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYxMTA1VDIzMDAxM1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTYwYjZhZmUxZjJiNTNhNmQ5ODk1Nzc5Y2RiYjRiNmI4M2UyN2NkYjQ4YjcxYWRjZmZjNTQwYWZhOWE1N2ZhNDImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.aRNOIJnLEyvoQmq-iDAJm4Ufe8MCKdyZ9U2yelwQSQU" class="js-gh-image-fallback"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This repository is primarily intended for educational and research purposes. It includes strategy concepts, implementation approaches, and selected performance screenshots to help developers understand how different automated trading strategies can be designed and tested.&lt;/p&gt;

&lt;p&gt;The repository does not provide a complete production-ready trading bot source code. Instead, it provides strategy descriptions and research materials that you can use as a foundation for developing your own system.&lt;/p&gt;

&lt;p&gt;If you are interested in building a Polymarket Trading Bot, you can follow my tutorials and use the concepts in this repository to develop your own implementation.&lt;/p&gt;

&lt;p&gt;For users who prefer a ready-to-deploy solution or require custom strategy development, commercial bot development and customization are also available.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;YouTube:&lt;/strong&gt; &lt;br&gt;&lt;br&gt;
  &lt;iframe&gt;
    src="https://www.youtube.com/embed/UCF7MA1Kekk"&lt;br&gt;
    width="710"&lt;br&gt;
    height="399"&lt;br&gt;
    style="width: 100%; height: auto; aspect-ratio: 16 / 9;"&lt;br&gt;
    allowfullscreen&lt;br&gt;
    loading="lazy"&amp;gt;&lt;br&gt;
  &lt;/iframe&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Telegram:&lt;/strong&gt; &lt;a href="https://telegram.me/BenjaminCup" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://telegram.me/BenjaminCup" rel="noopener noreferrer"&gt;https://telegram.me/BenjaminCup&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Disclaimer: This article is for educational purposes only and does not constitute financial advice. Backtesting and simulated performance do not guarantee future results. Prediction-market trading involves financial risk, including the possibility of losing your entire trading capital.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>polymarket</category>
      <category>architecture</category>
      <category>algorithms</category>
      <category>crypto</category>
    </item>
    <item>
      <title>Advanced Polymarket Market Making Strategy: Dynamic Spreads, Volatility, and Market Conditions in Python</title>
      <dc:creator>Benjamin-Cup</dc:creator>
      <pubDate>Wed, 04 Nov 2026 13:23:33 +0000</pubDate>
      <link>https://dev.to/benjamin_cup/advanced-polymarket-market-making-strategy-dynamic-spreads-volatility-and-market-conditions-in-45mf</link>
      <guid>https://dev.to/benjamin_cup/advanced-polymarket-market-making-strategy-dynamic-spreads-volatility-and-market-conditions-in-45mf</guid>
      <description>&lt;p&gt;&lt;em&gt;Day 8: Taking Your Polymarket Market Maker Bot Beyond the Basics&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the first seven articles, we built the foundation of a Polymarket market maker bot.&lt;/p&gt;

&lt;p&gt;We learned how to understand the order book, retrieve market data, calculate bid and ask prices, manage orders, handle partial fills, control inventory risk, and prepare a bot for deployment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdkxh4zjlz3dcsdb3w3qk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdkxh4zjlz3dcsdb3w3qk.png" alt="Polymarket Trading Bot" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But there is still one important question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should your market maker use the same spread and order size in every market condition?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine two situations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Situation A: A quiet market&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;BTC is moving slowly. The Polymarket order book has reasonable liquidity, and the best bid and ask prices are relatively stable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Situation B: A volatile market&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;BTC suddenly moves sharply. The order book changes quickly, liquidity disappears, and the probability of a YES outcome changes rapidly.&lt;/p&gt;

&lt;p&gt;Should your bot use exactly the same bid, ask, and order size in both situations?&lt;/p&gt;

&lt;p&gt;Probably not.&lt;/p&gt;

&lt;p&gt;A fixed-spread market maker is easier to build, but it does not automatically adapt to changing market conditions.&lt;/p&gt;

&lt;p&gt;In this article, we'll explore how to build a more adaptive market maker using dynamic spreads, volatility measurements, liquidity checks, and market-regime filters.&lt;/p&gt;

&lt;p&gt;We'll cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why fixed spreads can be dangerous.&lt;/li&gt;
&lt;li&gt;How to estimate short-term volatility.&lt;/li&gt;
&lt;li&gt;How to adjust spreads dynamically.&lt;/li&gt;
&lt;li&gt;How to adapt order size to market liquidity.&lt;/li&gt;
&lt;li&gt;How to identify unstable market conditions.&lt;/li&gt;
&lt;li&gt;How to combine volatility and inventory controls.&lt;/li&gt;
&lt;li&gt;How to implement a basic adaptive pricing model in Python.&lt;/li&gt;
&lt;li&gt;How to evaluate whether dynamic quoting actually improves performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is to make the bot respond intelligently to changing conditions instead of using one fixed configuration all the time.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Why Fixed-Spread Market Making Has Limitations
&lt;/h2&gt;

&lt;p&gt;Let's start with a simple market maker.&lt;/p&gt;

&lt;p&gt;Suppose the YES token has a midpoint of $0.50.&lt;/p&gt;

&lt;p&gt;Your bot always uses a half-spread of $0.02.&lt;/p&gt;

&lt;p&gt;It calculates:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
Bid=0.50-0.02=0.48&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
Ask=0.50+0.02=0.52&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;The resulting spread is four cents.&lt;/p&gt;

&lt;p&gt;This is easy to understand and implement.&lt;/p&gt;

&lt;p&gt;However, market conditions do not remain constant.&lt;/p&gt;

&lt;p&gt;When volatility is low, a four-cent spread might be unnecessarily wide. Other traders may offer better prices, making your orders less competitive.&lt;/p&gt;

&lt;p&gt;When volatility is high, the same four-cent spread might be too narrow. Your orders may be filled just before the market moves against you.&lt;/p&gt;

&lt;p&gt;This creates two different problems:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In calm markets:&lt;/strong&gt; Your quotes may be too conservative.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In volatile markets:&lt;/strong&gt; Your quotes may be too aggressive.&lt;/p&gt;

&lt;p&gt;A dynamic market maker attempts to adjust its behavior based on the current market environment.&lt;/p&gt;

&lt;p&gt;It does not guarantee better results, but it gives the strategy a way to respond to changing risk.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Understand Market Volatility
&lt;/h2&gt;

&lt;p&gt;Volatility describes how much a price changes over time.&lt;/p&gt;

&lt;p&gt;A market with small, gradual price movements has relatively low short-term volatility.&lt;/p&gt;

&lt;p&gt;A market with large and frequent price movements has relatively high short-term volatility.&lt;/p&gt;

&lt;p&gt;For a Polymarket crypto market maker, you might monitor two different types of prices:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Polymarket YES or NO token price.&lt;/li&gt;
&lt;li&gt;The underlying cryptocurrency reference price, such as BTC.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These prices provide different information.&lt;/p&gt;

&lt;p&gt;The Polymarket token price reflects the market's changing probability estimate and available trading liquidity.&lt;/p&gt;

&lt;p&gt;The BTC price reflects movement in the underlying asset.&lt;/p&gt;

&lt;p&gt;For a BTC Up/Down market, both can be useful, but they should not be mixed into one measurement without a clearly defined model.&lt;/p&gt;
&lt;h3&gt;
  
  
  A simple example
&lt;/h3&gt;

&lt;p&gt;Imagine these BTC prices:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;BTC price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10:00:00&lt;/td&gt;
&lt;td&gt;$100,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:00:05&lt;/td&gt;
&lt;td&gt;$100,010&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:00:10&lt;/td&gt;
&lt;td&gt;$100,008&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:00:15&lt;/td&gt;
&lt;td&gt;$100,012&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The movement is relatively small.&lt;/p&gt;

&lt;p&gt;Now imagine:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;BTC price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10:00:00&lt;/td&gt;
&lt;td&gt;$100,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:00:05&lt;/td&gt;
&lt;td&gt;$100,150&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:00:10&lt;/td&gt;
&lt;td&gt;$99,920&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:00:15&lt;/td&gt;
&lt;td&gt;$100,180&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The second sequence shows much larger price changes.&lt;/p&gt;

&lt;p&gt;A market maker should consider whether its current spread and order size are appropriate for each environment.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Calculate Short-Term Volatility in Python
&lt;/h2&gt;

&lt;p&gt;One simple approach is to calculate price returns.&lt;/p&gt;

&lt;p&gt;A return measures the percentage change between two consecutive prices.&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
r_t=\frac{P_t-P_{t-1}}{P_{t-1}}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;For example, if BTC moves from $100,000 to $100,100:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
r_t=\frac{100100-100000}{100000}=0.001&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;That is a return of 0.1%.&lt;/p&gt;

&lt;p&gt;We can calculate the standard deviation of recent returns to estimate short-term volatility.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;statistics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pstdev&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;VolatilityTracker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_samples&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;deque&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxlen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;max_samples&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_price&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Price must be positive&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_volatility&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

        &lt;span class="n"&gt;returns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;)[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:],&lt;/span&gt;
        &lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;returns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;pstdev&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;returns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example calculates the population standard deviation of the observed returns.&lt;/p&gt;

&lt;p&gt;It is intentionally simple. A production implementation should define its sampling interval, handle missing data, use consistent timestamps, and consider whether a rolling or exponentially weighted volatility estimate is more appropriate.&lt;/p&gt;

&lt;p&gt;Also remember that the output depends on the data frequency.&lt;/p&gt;

&lt;p&gt;Thirty price observations collected every second describe a different time horizon from thirty observations collected every minute.&lt;/p&gt;

&lt;p&gt;Do not compare volatility values without considering their sampling intervals.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Use Volatility to Adjust the Spread
&lt;/h2&gt;

&lt;p&gt;Now let's connect volatility to quote calculation.&lt;/p&gt;

&lt;p&gt;In Day 4, we used a fixed half-spread.&lt;/p&gt;

&lt;p&gt;Now we want the half-spread to change according to market conditions.&lt;/p&gt;

&lt;p&gt;A simplified formula is:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
H=H_{\min}+\alpha V&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(H) is the dynamic half-spread.&lt;/li&gt;
&lt;li&gt;(H_{\min}) is the minimum half-spread.&lt;/li&gt;
&lt;li&gt;(V) is the measured volatility.&lt;/li&gt;
&lt;li&gt;(\alpha) controls how strongly volatility affects the spread.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is an illustrative model. The volatility measure must be scaled appropriately before using it in a pricing formula.&lt;/p&gt;

&lt;p&gt;Let's look at a simplified example.&lt;/p&gt;

&lt;p&gt;Suppose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minimum half-spread = $0.01.&lt;/li&gt;
&lt;li&gt;Volatility measurement = 0.002.&lt;/li&gt;
&lt;li&gt;Volatility coefficient = 5.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
H=0.01+(5 \times 0.002)&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
H=0.02&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;If the midpoint is $0.50, the candidate quotes become:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bid: $0.48.&lt;/li&gt;
&lt;li&gt;Ask: $0.52.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When volatility increases, the half-spread increases.&lt;/p&gt;

&lt;p&gt;This gives the bot more room between its buy and sell prices.&lt;/p&gt;

&lt;p&gt;However, a wider spread does not eliminate adverse selection. If the market is moving extremely quickly, even a wide quote can become outdated.&lt;/p&gt;

&lt;p&gt;Sometimes the safer decision is not to quote at all.&lt;/p&gt;
&lt;h2&gt;
  
  
  5. Implement Dynamic Spread Calculation
&lt;/h2&gt;

&lt;p&gt;Let's turn the basic formula into Python.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_dynamic_half_spread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;min_half_spread&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;volatility&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;volatility_factor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_half_spread&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;min_half_spread&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Minimum spread must be positive&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;volatility&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Volatility cannot be negative&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;volatility_factor&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Volatility factor cannot be negative&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;max_half_spread&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;min_half_spread&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid maximum spread&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;dynamic_spread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;min_half_spread&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;volatility&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;volatility_factor&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dynamic_spread&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_half_spread&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;half_spread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_dynamic_half_spread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;min_half_spread&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.01&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;volatility&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.002&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;volatility_factor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;max_half_spread&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.05&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Half spread:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;half_spread&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function calculates a candidate half-spread and prevents it from exceeding the configured maximum.&lt;/p&gt;

&lt;p&gt;A production bot should also define what happens when the calculated spread is too wide to quote competitively or violates the market's valid price increments.&lt;/p&gt;

&lt;p&gt;Do not assume that a larger spread is always better.&lt;/p&gt;

&lt;p&gt;The objective is to balance execution probability against adverse-selection and inventory risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Adjust Order Size Based on Liquidity
&lt;/h2&gt;

&lt;p&gt;Spread is only one part of the strategy.&lt;/p&gt;

&lt;p&gt;Order size matters too.&lt;/p&gt;

&lt;p&gt;Imagine the order book looks like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Market A&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Available quantity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;$0.49&lt;/td&gt;
&lt;td&gt;1,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$0.48&lt;/td&gt;
&lt;td&gt;1,500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$0.47&lt;/td&gt;
&lt;td&gt;2,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Market B&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Available quantity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;$0.49&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$0.48&lt;/td&gt;
&lt;td&gt;35&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$0.47&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Both markets may show similar best prices, but their available liquidity is very different.&lt;/p&gt;

&lt;p&gt;Placing a 500-token order in Market A may be reasonable under your strategy's limits.&lt;/p&gt;

&lt;p&gt;Placing the same order in Market B could represent a much larger portion of the available liquidity.&lt;/p&gt;

&lt;p&gt;This is why order size should consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Available order-book depth.&lt;/li&gt;
&lt;li&gt;Current inventory.&lt;/li&gt;
&lt;li&gt;Available funds.&lt;/li&gt;
&lt;li&gt;Outstanding orders.&lt;/li&gt;
&lt;li&gt;Volatility.&lt;/li&gt;
&lt;li&gt;Maximum permitted exposure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A basic liquidity ratio
&lt;/h3&gt;

&lt;p&gt;You can estimate how large your order is compared with available depth:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
L=\frac{Q_{\text{order}}}{Q_{\text{available}}}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Proposed order size: 50 tokens.&lt;/li&gt;
&lt;li&gt;Available quantity near the relevant price: 500 tokens.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;[&lt;br&gt;
L=\frac{50}{500}=0.10&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Your order is 10% of the selected available quantity.&lt;/p&gt;

&lt;p&gt;This ratio does not predict whether the order will fill. It is simply a way to understand how large your order is relative to the visible liquidity you chose to measure.&lt;/p&gt;

&lt;p&gt;Visible liquidity can disappear or change, and it does not necessarily represent the full amount available at execution time.&lt;/p&gt;
&lt;h2&gt;
  
  
  7. Create a Basic Adaptive Order Size Function
&lt;/h2&gt;

&lt;p&gt;We can also adjust the proposed order size according to volatility.&lt;/p&gt;

&lt;p&gt;For example, we might reduce the size when volatility rises.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_order_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;volatility&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;volatility_sensitivity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;minimum_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;base_size&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Base size must be positive&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;volatility&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;volatility_sensitivity&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid volatility parameters&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base_size&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;volatility&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;volatility_sensitivity&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minimum_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suppose the base size is 100 tokens.&lt;/p&gt;

&lt;p&gt;As volatility increases, the calculated size decreases.&lt;/p&gt;

&lt;p&gt;This is a simple educational model. It does not include inventory, liquidity, balance, minimum order sizes, or the market's actual execution constraints.&lt;/p&gt;

&lt;p&gt;In a real market maker, order size should be calculated only after the risk manager checks all relevant exposure.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Combine Dynamic Spreads With Inventory Skew
&lt;/h2&gt;

&lt;p&gt;Now let's combine the ideas from Day 4 and Day 6.&lt;/p&gt;

&lt;p&gt;A market maker needs to consider at least two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How risky is the current market?&lt;/li&gt;
&lt;li&gt;How much inventory does the bot already hold?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Volatility can influence the spread.&lt;/p&gt;

&lt;p&gt;Inventory can influence the reference price.&lt;/p&gt;

&lt;p&gt;A simplified model is:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
P_{\text{adjusted}}=P_{\text{mid}}-kI&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
Bid=P_{\text{adjusted}}-H&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
Ask=P_{\text{adjusted}}+H&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(P_{\text{mid}}) is the reference midpoint.&lt;/li&gt;
&lt;li&gt;(I) is the inventory deviation from the target.&lt;/li&gt;
&lt;li&gt;(k) is the inventory-skew coefficient.&lt;/li&gt;
&lt;li&gt;(H) is the dynamic half-spread.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's consider an example.&lt;/p&gt;

&lt;p&gt;Assume:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Midpoint = $0.50.&lt;/li&gt;
&lt;li&gt;Inventory deviation = 100 tokens.&lt;/li&gt;
&lt;li&gt;Inventory skew = 0.0001.&lt;/li&gt;
&lt;li&gt;Dynamic half-spread = $0.03.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The adjusted midpoint becomes:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
0.50-(100 \times 0.0001)=0.49&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;The quotes become:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
Bid=0.49-0.03=0.46&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
Ask=0.49+0.03=0.52&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;The bot has both widened its spread and shifted its reference price downward.&lt;/p&gt;

&lt;p&gt;This is a basic way to combine market-condition risk with inventory risk.&lt;/p&gt;

&lt;p&gt;But there is an important limitation: the formula assumes that the volatility and inventory measurements are meaningful and correctly scaled.&lt;/p&gt;

&lt;p&gt;It also assumes that a two-sided quote remains appropriate.&lt;/p&gt;

&lt;p&gt;If the market is unstable or the bot has exceeded its risk limit, it may be better to reduce exposure or pause quoting instead.&lt;/p&gt;
&lt;h2&gt;
  
  
  9. Detect Market Regimes
&lt;/h2&gt;

&lt;p&gt;Not every market condition requires the same behavior.&lt;/p&gt;

&lt;p&gt;You can divide market conditions into simple categories.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Market regime&lt;/th&gt;
&lt;th&gt;Possible characteristics&lt;/th&gt;
&lt;th&gt;Example response&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Calm&lt;/td&gt;
&lt;td&gt;Stable prices and reasonable depth&lt;/td&gt;
&lt;td&gt;Normal quoting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Active&lt;/td&gt;
&lt;td&gt;More frequent price changes&lt;/td&gt;
&lt;td&gt;Recalculate quotes more often&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Volatile&lt;/td&gt;
&lt;td&gt;Large and rapid movements&lt;/td&gt;
&lt;td&gt;Wider spreads and smaller orders&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Illiquid&lt;/td&gt;
&lt;td&gt;Thin order book and large gaps&lt;/td&gt;
&lt;td&gt;Reduce size or pause&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uncertain&lt;/td&gt;
&lt;td&gt;Stale data or unreliable state&lt;/td&gt;
&lt;td&gt;Stop new quoting until reconciled&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These are conceptual categories, not universal thresholds.&lt;/p&gt;

&lt;p&gt;Your bot needs measurable rules to determine which category applies.&lt;/p&gt;

&lt;p&gt;For example, a volatility filter might compare recent volatility with a configured threshold.&lt;/p&gt;

&lt;p&gt;A liquidity filter might compare available depth with the intended order size.&lt;/p&gt;

&lt;p&gt;A data-quality filter might check how old the latest market update is.&lt;/p&gt;

&lt;p&gt;A production system should also use hysteresis or minimum time-in-regime rules where appropriate.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because a market can move around a threshold.&lt;/p&gt;

&lt;p&gt;If your bot switches between normal and volatile mode every second, its behavior may become unstable.&lt;/p&gt;

&lt;p&gt;Hysteresis means using different conditions to enter and exit a regime.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter volatile mode when volatility rises above 0.003.&lt;/li&gt;
&lt;li&gt;Return to normal mode only when volatility falls below 0.002.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The gap between the thresholds helps prevent rapid switching.&lt;/p&gt;
&lt;h2&gt;
  
  
  10. Know When Not to Make a Market
&lt;/h2&gt;

&lt;p&gt;An advanced market maker must understand that sometimes the correct decision is to do nothing.&lt;/p&gt;

&lt;p&gt;Consider these situations:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Situation 1: Market data is stale&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your bot has not received a fresh order-book update.&lt;/p&gt;

&lt;p&gt;It cannot safely assume that its previous quotes are still appropriate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Situation 2: Liquidity disappears&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The visible order book becomes extremely thin.&lt;/p&gt;

&lt;p&gt;A normal order size may now represent a large share of available liquidity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Situation 3: Volatility becomes extreme&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The underlying crypto price moves rapidly, and the Polymarket token price changes faster than your strategy can safely react.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Situation 4: Inventory exceeds the limit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The bot already holds more tokens than its strategy allows.&lt;/p&gt;

&lt;p&gt;Submitting additional buy orders could increase the exposure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Situation 5: The order state is uncertain&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A previous submission or cancellation timed out, and the bot cannot determine the current exchange state.&lt;/p&gt;

&lt;p&gt;In these cases, the bot should follow its configured safety policy.&lt;/p&gt;

&lt;p&gt;This might mean reducing orders, canceling certain resting orders, or pausing new submissions.&lt;/p&gt;

&lt;p&gt;The exact action should depend on the risk condition and the bot's current exposure.&lt;/p&gt;

&lt;p&gt;A market maker should not be forced to quote at every moment.&lt;/p&gt;
&lt;h2&gt;
  
  
  11. Build a Simple Adaptive Quote Engine
&lt;/h2&gt;

&lt;p&gt;Let's combine the ideas into one educational function.&lt;/p&gt;

&lt;p&gt;It will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Calculate the inventory-adjusted midpoint.&lt;/li&gt;
&lt;li&gt;Calculate a volatility-adjusted spread.&lt;/li&gt;
&lt;li&gt;Produce candidate bid and ask prices.&lt;/li&gt;
&lt;li&gt;Check basic price boundaries.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It will not place orders or replace the risk manager.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_adaptive_quotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;midpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;inventory_target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;volatility&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;base_half_spread&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;volatility_factor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;inventory_skew&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;midpoint&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid midpoint&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;volatility&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Volatility cannot be negative&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;base_half_spread&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Base spread must be positive&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;inventory_deviation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;inventory_target&lt;/span&gt;

    &lt;span class="n"&gt;adjusted_midpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;midpoint&lt;/span&gt;
        &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;inventory_deviation&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;inventory_skew&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;dynamic_half_spread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;base_half_spread&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;volatility&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;volatility_factor&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;bid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;adjusted_midpoint&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;dynamic_half_spread&lt;/span&gt;
    &lt;span class="n"&gt;ask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;adjusted_midpoint&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;dynamic_half_spread&lt;/span&gt;

    &lt;span class="n"&gt;min_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.01&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;max_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.99&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;bid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_price&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_price&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;bid&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid quote relationship&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;bid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ask&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;adjusted_midpoint&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;adjusted_midpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;half_spread&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dynamic_half_spread&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inventory_deviation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inventory_deviation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;quotes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_adaptive_quotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;midpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.50&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;100&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;inventory_target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;volatility&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.002&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;base_half_spread&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.01&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;volatility_factor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;inventory_skew&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a starting point for experimentation, not a complete production quoting algorithm.&lt;/p&gt;

&lt;p&gt;A real implementation must additionally validate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The actual market tick size.&lt;/li&gt;
&lt;li&gt;Minimum and maximum order sizes.&lt;/li&gt;
&lt;li&gt;Market status.&lt;/li&gt;
&lt;li&gt;Available balance.&lt;/li&gt;
&lt;li&gt;Current order-book liquidity.&lt;/li&gt;
&lt;li&gt;Outstanding orders and possible fills.&lt;/li&gt;
&lt;li&gt;Maximum inventory and loss limits.&lt;/li&gt;
&lt;li&gt;Data freshness.&lt;/li&gt;
&lt;li&gt;Whether quoting should be paused.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It should also account for the fact that YES and NO tokens may need separate pricing and inventory models.&lt;/p&gt;

&lt;h2&gt;
  
  
  12. How Do You Know Dynamic Quoting Is Better?
&lt;/h2&gt;

&lt;p&gt;Adding more parameters does not automatically improve a trading strategy.&lt;/p&gt;

&lt;p&gt;A complicated bot can perform worse than a simple bot if its filters are poorly calibrated or its data is unreliable.&lt;/p&gt;

&lt;p&gt;You should compare the fixed-spread and dynamic-spread strategies under the same evaluation conditions.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Fixed spread&lt;/th&gt;
&lt;th&gt;Dynamic spread&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Net P&amp;amp;L&lt;/td&gt;
&lt;td&gt;Measure&lt;/td&gt;
&lt;td&gt;Measure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fill rate&lt;/td&gt;
&lt;td&gt;Measure&lt;/td&gt;
&lt;td&gt;Measure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maximum inventory&lt;/td&gt;
&lt;td&gt;Measure&lt;/td&gt;
&lt;td&gt;Measure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Average order size&lt;/td&gt;
&lt;td&gt;Measure&lt;/td&gt;
&lt;td&gt;Measure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Post-fill price movement&lt;/td&gt;
&lt;td&gt;Measure&lt;/td&gt;
&lt;td&gt;Measure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fees and execution costs&lt;/td&gt;
&lt;td&gt;Measure&lt;/td&gt;
&lt;td&gt;Measure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time spent quoting&lt;/td&gt;
&lt;td&gt;Measure&lt;/td&gt;
&lt;td&gt;Measure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Risk-limit breaches&lt;/td&gt;
&lt;td&gt;Measure&lt;/td&gt;
&lt;td&gt;Measure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Do not fill this table with expected improvements. Collect actual results from your own tests.&lt;/p&gt;

&lt;p&gt;A dynamic strategy might reduce inventory exposure but also receive fewer fills.&lt;/p&gt;

&lt;p&gt;It might improve post-fill price movement while missing some trading opportunities.&lt;/p&gt;

&lt;p&gt;It might perform better in volatile markets but worse in calm markets.&lt;/p&gt;

&lt;p&gt;These are trade-offs to measure, not assumptions to make.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run controlled experiments
&lt;/h3&gt;

&lt;p&gt;A useful process is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build a fixed-spread baseline.&lt;/li&gt;
&lt;li&gt;Record the data and decisions it produces.&lt;/li&gt;
&lt;li&gt;Add volatility-based spread adjustment.&lt;/li&gt;
&lt;li&gt;Compare the results using the same data and execution assumptions.&lt;/li&gt;
&lt;li&gt;Add inventory-aware size adjustment.&lt;/li&gt;
&lt;li&gt;Evaluate the new version separately.&lt;/li&gt;
&lt;li&gt;Test on data that was not used to tune the parameters.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Change one major feature at a time where possible.&lt;/p&gt;

&lt;p&gt;This helps you understand which modification actually caused a performance difference.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion: Build a Market Maker That Adapts to the Market
&lt;/h2&gt;

&lt;p&gt;A basic market maker can calculate a bid and ask using a fixed spread.&lt;/p&gt;

&lt;p&gt;But real markets do not remain constant.&lt;/p&gt;

&lt;p&gt;Volatility changes. Liquidity changes. Inventory changes. Order-book conditions change.&lt;/p&gt;

&lt;p&gt;A more advanced market maker should recognize these changes and adjust its behavior accordingly.&lt;/p&gt;

&lt;p&gt;The key lessons from Day 8 are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fixed spreads have limitations.&lt;/strong&gt; The same quote may be too wide in a calm market and too narrow in a volatile market.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measure volatility consistently.&lt;/strong&gt; The sampling interval and data source matter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adjust spreads carefully.&lt;/strong&gt; Wider quotes may reduce some execution risks but do not guarantee better results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adapt order size to risk and liquidity.&lt;/strong&gt; A large order can be inappropriate in a thin market.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Combine inventory and volatility controls.&lt;/strong&gt; Both influence how aggressively the bot should quote.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recognize unsafe market conditions.&lt;/strong&gt; Sometimes pausing is better than placing another order.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measure every improvement.&lt;/strong&gt; More sophisticated logic is useful only when testing demonstrates a meaningful benefit.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The next step is not simply adding more filters or more complicated formulas.&lt;/p&gt;

&lt;p&gt;It is building a strategy that can explain why it is quoting, how much risk it is taking, and when it should stop.&lt;/p&gt;

&lt;p&gt;That is the difference between a basic trading script and a more sophisticated market-making system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Continue the project
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub repository:&lt;/strong&gt; &lt;a href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;https://github.com/Benj4minCup/Polymarket-Trading-Bot-python&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;YouTube tutorial:&lt;/strong&gt; &lt;a href="https://www.youtube.com/watch?v=UCF7MA1Kekk" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=UCF7MA1Kekk&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Telegram:&lt;/strong&gt; &lt;a href="https://telegram.me/BenjaminCup" rel="noopener noreferrer"&gt;https://telegram.me/BenjaminCup&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Follow the project and experiment with the concepts in this tutorial series.&lt;/p&gt;

</description>
      <category>polymarket</category>
      <category>architecture</category>
      <category>tutorial</category>
      <category>python</category>
    </item>
    <item>
      <title>Building a Polymarket Market Maker Bot in Python: Testing, Monitoring &amp; Deployment</title>
      <dc:creator>Benjamin-Cup</dc:creator>
      <pubDate>Tue, 03 Nov 2026 15:15:35 +0000</pubDate>
      <link>https://dev.to/benjamin_cup/building-a-polymarket-market-maker-bot-in-python-testing-monitoring-deployment-4hi0</link>
      <guid>https://dev.to/benjamin_cup/building-a-polymarket-market-maker-bot-in-python-testing-monitoring-deployment-4hi0</guid>
      <description>&lt;p&gt;Day 7 of 7 — From Zero to a Complete Market Maker Bot&lt;/p&gt;

&lt;p&gt;Building a market maker bot is not just about placing buy and sell orders. A reliable bot must also manage inventory, control risk, handle API failures, and measure actual trading performance.&lt;/p&gt;

&lt;p&gt;In this final part of the series, we'll bring everything together and look at how to prepare a Polymarket market maker bot for deployment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fntk1n6k6dxg9syw8u3q7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fntk1n6k6dxg9syw8u3q7.png" alt="Polymarket Trading Bot" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Complete Bot Architecture
&lt;/h2&gt;

&lt;p&gt;A market maker bot consists of several components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Market Data Collector:&lt;/strong&gt; Retrieves order books, prices, and market updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pricing Engine:&lt;/strong&gt; Calculates bid and ask prices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risk Manager:&lt;/strong&gt; Checks inventory, balance, and exposure limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Order Manager:&lt;/strong&gt; Submits, tracks, cancels, and replaces orders.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring System:&lt;/strong&gt; Tracks performance, errors, and system health.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key principle is separation of responsibility: pricing decides what to quote, risk management decides whether it's safe, and order management handles execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Test Before Live Trading
&lt;/h2&gt;

&lt;p&gt;Never connect a new strategy directly to a live account.&lt;/p&gt;

&lt;p&gt;Use four testing stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Historical data analysis.&lt;/li&gt;
&lt;li&gt;Strategy simulation.&lt;/li&gt;
&lt;li&gt;Real-time paper trading.&lt;/li&gt;
&lt;li&gt;Limited live testing with strict risk limits.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Paper trading helps identify problems such as duplicate orders, partial fills, incorrect inventory calculations, and stale market data.&lt;/p&gt;

&lt;p&gt;Remember: simulated fills do not guarantee real-world execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Measure Real Trading Performance
&lt;/h2&gt;

&lt;p&gt;A profitable-looking spread does not necessarily mean a profitable strategy.&lt;/p&gt;

&lt;p&gt;Track these important metrics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Realized P&amp;amp;L:&lt;/strong&gt; Profit or loss from completed trades.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unrealized P&amp;amp;L:&lt;/strong&gt; Current estimated profit or loss from open positions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Net P&amp;amp;L:&lt;/strong&gt; Results after applicable fees and trading costs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fill Rate:&lt;/strong&gt; Percentage of submitted order quantity that gets filled.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inventory Exposure:&lt;/strong&gt; How much inventory the bot holds and for how long.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adverse Selection:&lt;/strong&gt; Whether prices move against the bot after its orders fill.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These metrics help identify whether your strategy is actually working.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Implement Risk Management
&lt;/h2&gt;

&lt;p&gt;Before submitting an order, check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is market data fresh?&lt;/li&gt;
&lt;li&gt;Is the market active?&lt;/li&gt;
&lt;li&gt;Is the order price valid?&lt;/li&gt;
&lt;li&gt;Is sufficient balance available?&lt;/li&gt;
&lt;li&gt;Is inventory within limits?&lt;/li&gt;
&lt;li&gt;Are existing open orders creating additional exposure?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If something is wrong, the bot should pause new orders or reduce exposure instead of continuing blindly.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Handle API Failures and Restarts
&lt;/h2&gt;

&lt;p&gt;Network failures and unexpected crashes are normal in production systems.&lt;/p&gt;

&lt;p&gt;After restarting, the bot should:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Load its saved configuration.&lt;/li&gt;
&lt;li&gt;Connect to Polymarket.&lt;/li&gt;
&lt;li&gt;Retrieve open orders and trade history.&lt;/li&gt;
&lt;li&gt;Reconcile local records with exchange state.&lt;/li&gt;
&lt;li&gt;Recalculate inventory and available balance.&lt;/li&gt;
&lt;li&gt;Verify market data freshness.&lt;/li&gt;
&lt;li&gt;Resume trading only when the state is understood.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Never blindly resubmit an order after an API timeout. The original order might already exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Deploy and Monitor
&lt;/h2&gt;

&lt;p&gt;A VPS (Virtual Private Server) allows your bot to run continuously without depending on your personal computer.&lt;/p&gt;

&lt;p&gt;Before deployment, prepare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Secure API credentials.&lt;/li&gt;
&lt;li&gt;Environment-based configuration.&lt;/li&gt;
&lt;li&gt;Structured logs.&lt;/li&gt;
&lt;li&gt;Automatic process recovery.&lt;/li&gt;
&lt;li&gt;Health checks and alerts.&lt;/li&gt;
&lt;li&gt;Emergency-stop procedures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Monitor market data, open orders, inventory, P&amp;amp;L, API errors, and system resources.&lt;/p&gt;

&lt;p&gt;Automatic restarts alone are not enough. Always reconcile exchange state before resuming trading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Over these seven articles, we've explored the essential components of building a Polymarket market maker bot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding the order book.&lt;/li&gt;
&lt;li&gt;Collecting market data.&lt;/li&gt;
&lt;li&gt;Calculating bid and ask prices.&lt;/li&gt;
&lt;li&gt;Managing orders and partial fills.&lt;/li&gt;
&lt;li&gt;Controlling inventory risk.&lt;/li&gt;
&lt;li&gt;Testing strategies.&lt;/li&gt;
&lt;li&gt;Monitoring and deploying the system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The biggest lesson is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A trading bot is more than a script that places orders. It's a complete system that must understand its exposure, handle failures, and measure its real performance.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A good architecture and successful backtest cannot guarantee profitability. Test carefully and increase trading limits only when the evidence supports it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continue Building
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Benj4minCup" rel="noopener noreferrer"&gt;
        Benj4minCup
      &lt;/a&gt; / &lt;a href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;
        Polymarket-Trading-Bot-python
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      polymarket Twap Bot polymarket Arbitrage Bot polymarket bot 
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Polymarket Trading bot system&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;An open-source and Strong Strategy collection of Polymarket trading bot and Polymarket arbitrage bot and Polymarket TWAP trading bot in Python for high-performance automated trading on polymarket crypto 5min and 15min markets.&lt;/p&gt;
&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/33036584/633381478-71b65c58-00d2-4bbe-8b6d-8ed6fc9812e4.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3OTM3MTkyMzksIm5iZiI6MTc5MzcxODkzOSwicGF0aCI6Ii8zMzAzNjU4NC82MzMzODE0NzgtNzFiNjVjNTgtMDBkMi00YmJlLThiNmQtOGVkNmZjOTgxMmU0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjExMDMlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYxMTAzVDE1MTUzOVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWQ0OWZlYzBjNzc5ODZlYzczYzFhYTA3YTkwYTU3YTkwNzZkMGQ0MDhmMzQ2ODQxNGUzNWNhMjBiYmU1MDk4ZDMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.eTIDDV0smQiZ9DWd5CAAGkkwMZwffIy1z_h3QYv3G68"&gt;&lt;img width="1536" height="1024" alt="Polymarket-benjamincup-bot-dashboard" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F33036584%2F633381478-71b65c58-00d2-4bbe-8b6d-8ed6fc9812e4.png%3Fjwt%3DeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3OTM3MTkyMzksIm5iZiI6MTc5MzcxODkzOSwicGF0aCI6Ii8zMzAzNjU4NC82MzMzODE0NzgtNzFiNjVjNTgtMDBkMi00YmJlLThiNmQtOGVkNmZjOTgxMmU0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjExMDMlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYxMTAzVDE1MTUzOVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWQ0OWZlYzBjNzc5ODZlYzczYzFhYTA3YTkwYTU3YTkwNzZkMGQ0MDhmMzQ2ODQxNGUzNWNhMjBiYmU1MDk4ZDMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.eTIDDV0smQiZ9DWd5CAAGkkwMZwffIy1z_h3QYv3G68" class="js-gh-image-fallback"&gt;&lt;/a&gt;
&lt;p&gt;This repository is primarily intended for educational and research purposes. It includes strategy concepts, implementation approaches, and selected performance screenshots to help developers understand how different automated trading strategies can be designed and tested.&lt;/p&gt;
&lt;p&gt;The repository does not provide a complete production-ready trading bot source code. Instead, it provides strategy descriptions and research materials that you can use as a foundation for developing your own system.&lt;/p&gt;
&lt;p&gt;If you are interested in building a Polymarket Trading Bot, you can follow my tutorials and use the concepts in this repository to develop your own implementation.&lt;/p&gt;
&lt;p&gt;For users who prefer a ready-to-deploy solution or require custom strategy development, commercial bot development and customization are also available.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;YouTube:&lt;/strong&gt; &lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/UCF7MA1Kekk" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Telegram:&lt;/strong&gt; &lt;a href="https://telegram.me/BenjaminCup" rel="noopener noreferrer"&gt;https://telegram.me/BenjaminCup&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for following this seven-day series!&lt;/p&gt;

&lt;h1&gt;
  
  
  Python #Polymarket #TradingBot #MarketMaking #AlgorithmicTrading #CryptoTrading #OpenSource
&lt;/h1&gt;

</description>
      <category>polymarket</category>
      <category>python</category>
      <category>tutorial</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Building a Polymarket Market Maker Bot in Python: Inventory Risk, Adverse Selection &amp; Risk Management</title>
      <dc:creator>Benjamin-Cup</dc:creator>
      <pubDate>Mon, 02 Nov 2026 13:43:41 +0000</pubDate>
      <link>https://dev.to/benjamin_cup/building-a-polymarket-market-maker-bot-in-python-inventory-risk-adverse-selection-risk-n44</link>
      <guid>https://dev.to/benjamin_cup/building-a-polymarket-market-maker-bot-in-python-inventory-risk-adverse-selection-risk-n44</guid>
      <description>&lt;p&gt;&lt;em&gt;Day 6 of 7 — Building a Polymarket Market Maker Bot From Zero to Complete&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In Day 4, we learned how to calculate bid and ask prices. In Day 5, we explored order management, partial fills, cancellations, and uncertain API responses.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frqrkic3xd7qm1rhb0664.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frqrkic3xd7qm1rhb0664.png" alt="Polymarket Trading Bot" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today, we're going to tackle another critical challenge in automated market making:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you protect your trading bot when it accumulates tokens and the market moves against its position?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine your Polymarket bot purchases 100 YES tokens at $0.48 each.&lt;/p&gt;

&lt;p&gt;Your strategy expects to earn money by selling those tokens at a higher price.&lt;/p&gt;

&lt;p&gt;But before your sell order executes, the market changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your purchase price: $0.48&lt;/li&gt;
&lt;li&gt;New best bid: $0.42&lt;/li&gt;
&lt;li&gt;New best ask: $0.44&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your tokens are now worth less than what you paid.&lt;/p&gt;

&lt;p&gt;Your pricing algorithm might be working perfectly. Your API integration might be reliable. Your order manager might correctly track every transaction.&lt;/p&gt;

&lt;p&gt;Yet your strategy is still losing money.&lt;/p&gt;

&lt;p&gt;This is why professional market-making systems need more than a pricing algorithm. They need an inventory management and risk-control system.&lt;/p&gt;

&lt;p&gt;In this tutorial, we'll explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inventory risk and why it matters.&lt;/li&gt;
&lt;li&gt;Adverse selection and how it affects market makers.&lt;/li&gt;
&lt;li&gt;How to measure trading positions and financial exposure.&lt;/li&gt;
&lt;li&gt;Inventory-aware pricing strategies.&lt;/li&gt;
&lt;li&gt;Implementing risk-management logic in Python.&lt;/li&gt;
&lt;li&gt;Maximum inventory, exposure, and loss limits.&lt;/li&gt;
&lt;li&gt;Detecting unfavorable fills.&lt;/li&gt;
&lt;li&gt;Testing risk-management systems before live trading.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the end, you'll understand how to make your Polymarket bot aware of the risks created by its own orders.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Understanding Inventory Risk
&lt;/h2&gt;

&lt;p&gt;Before discussing risk management, let's understand inventory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inventory is the collection of tokens your trading bot currently holds.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In a Polymarket binary market, this usually means YES and NO tokens.&lt;/p&gt;

&lt;p&gt;Inventory risk occurs when the value or potential payout of those positions changes in a way that negatively affects your strategy.&lt;/p&gt;

&lt;h3&gt;
  
  
  A practical example
&lt;/h3&gt;

&lt;p&gt;Suppose your bot purchases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;100 YES tokens&lt;/li&gt;
&lt;li&gt;Purchase price: $0.48 per token&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your initial investment is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.48&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Later, the YES token price falls to $0.43.&lt;/p&gt;

&lt;p&gt;Its indicative market value becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.43&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;43&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your unrealized loss is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="mi"&gt;43&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You've lost approximately $5 in estimated position value, even though you haven't sold anything.&lt;/p&gt;

&lt;p&gt;This is called an &lt;strong&gt;unrealized loss&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Note that this simplified calculation doesn't include fees, execution costs, or the possibility that the entire position cannot be sold at the displayed price.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does inventory risk happen?
&lt;/h3&gt;

&lt;p&gt;Market makers generally place buy and sell orders around a reference price.&lt;/p&gt;

&lt;p&gt;They want to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Buy tokens at a lower price.&lt;/li&gt;
&lt;li&gt;Sell tokens at a higher price.&lt;/li&gt;
&lt;li&gt;Earn the difference, known as the spread.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;However, buy and sell orders don't always execute equally.&lt;/p&gt;

&lt;p&gt;Consider this situation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bot places BUY orders
        |
        v
Buy orders execute repeatedly
        |
        v
Bot accumulates YES tokens
        |
        v
Sell orders remain unfilled
        |
        v
Market price starts falling
        |
        v
Inventory loses value
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bot might have executed many successful purchases, but it now holds more inventory than intended.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The important lesson: A market maker must continuously monitor its inventory, not just the number of orders it has submitted.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  2. What Is Adverse Selection?
&lt;/h2&gt;

&lt;p&gt;Inventory risk describes the position your bot holds.&lt;/p&gt;

&lt;p&gt;Adverse selection describes a different problem:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your orders may be filled because another trader has information or market signals that make your quoted price unfavorable.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's look at an example.&lt;/p&gt;

&lt;p&gt;The YES token is trading around $0.50.&lt;/p&gt;

&lt;p&gt;Your bot places a sell order at $0.51.&lt;/p&gt;

&lt;p&gt;Another trader immediately purchases your tokens.&lt;/p&gt;

&lt;p&gt;A moment later, new information enters the market, and the YES token price rises to $0.56.&lt;/p&gt;

&lt;p&gt;Your order was successfully executed, but you sold at a price that quickly became unfavorable.&lt;/p&gt;

&lt;p&gt;The opposite can happen when your buy order executes just before the market price falls.&lt;/p&gt;

&lt;p&gt;This is adverse selection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why can other traders have an advantage?
&lt;/h3&gt;

&lt;p&gt;Other traders may react faster to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Changes in the underlying cryptocurrency price.&lt;/li&gt;
&lt;li&gt;Sudden increases in market volatility.&lt;/li&gt;
&lt;li&gt;New information affecting the probability of an outcome.&lt;/li&gt;
&lt;li&gt;Changes in liquidity and order-book depth.&lt;/li&gt;
&lt;li&gt;Markets approaching their resolution time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, imagine your bot is trading a Polymarket BTC Up/Down market.&lt;/p&gt;

&lt;p&gt;BTC suddenly moves sharply upward.&lt;/p&gt;

&lt;p&gt;The probability of the YES outcome changes, but your bot hasn't updated its quotes yet.&lt;/p&gt;

&lt;p&gt;Your existing sell order may now be too cheap.&lt;/p&gt;

&lt;p&gt;Another trader can purchase your tokens at your outdated price before your bot has time to react.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why is this dangerous?
&lt;/h3&gt;

&lt;p&gt;A wide spread doesn't automatically protect your market maker.&lt;/p&gt;

&lt;p&gt;If your prices are outdated, other traders may consistently execute against your orders when those prices are unfavorable.&lt;/p&gt;

&lt;p&gt;Your apparent spread profit can be overwhelmed by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adverse price movements.&lt;/li&gt;
&lt;li&gt;Trading fees.&lt;/li&gt;
&lt;li&gt;Execution costs.&lt;/li&gt;
&lt;li&gt;Unfavorable order fills.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why market makers need to monitor both inventory and market conditions.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Measuring Inventory and Financial Exposure
&lt;/h2&gt;

&lt;p&gt;You cannot manage risk if you don't know what your bot currently owns.&lt;/p&gt;

&lt;p&gt;At a minimum, your system should track:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Data&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;YES quantity&lt;/td&gt;
&lt;td&gt;Current YES token position&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NO quantity&lt;/td&gt;
&lt;td&gt;Current NO token position&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Average cost&lt;/td&gt;
&lt;td&gt;Average acquisition price&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Current reference price&lt;/td&gt;
&lt;td&gt;Estimated current token value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open buy orders&lt;/td&gt;
&lt;td&gt;Potential additional inventory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open sell orders&lt;/td&gt;
&lt;td&gt;Potential inventory reduction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Available funds&lt;/td&gt;
&lt;td&gt;Remaining buying capacity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Potential exposure&lt;/td&gt;
&lt;td&gt;Risk if outstanding orders execute&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Let's use an example.&lt;/p&gt;

&lt;p&gt;Your bot currently holds:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Position&lt;/th&gt;
&lt;th&gt;Quantity&lt;/th&gt;
&lt;th&gt;Average Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;$0.48&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NO&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;$0.46&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The total acquisition cost is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;yes_cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.48&lt;/span&gt;
&lt;span class="n"&gt;no_cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.46&lt;/span&gt;

&lt;span class="n"&gt;total_cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;yes_cost&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;no_cost&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_cost&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# 66.40
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your bot spent $66.40 acquiring these positions.&lt;/p&gt;

&lt;p&gt;However, acquisition cost alone doesn't tell you the current financial risk.&lt;/p&gt;

&lt;p&gt;You also need to understand the current market prices and what the tokens represent.&lt;/p&gt;

&lt;p&gt;For standard binary markets, a winning token generally pays $1 at resolution, while a losing token pays $0, subject to the specific market's resolution rules.&lt;/p&gt;

&lt;p&gt;Before resolution, token prices change as market expectations and trading conditions change.&lt;/p&gt;

&lt;p&gt;It's important to distinguish five different measurements:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Cost Basis&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The amount originally paid to acquire the position.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Mark-to-Market Value&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The estimated current value of the position using a selected market price.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Realized P&amp;amp;L&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Profit or loss from completed transactions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Unrealized P&amp;amp;L&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Estimated profit or loss on positions that are still open.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Resolution Value&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The final payout determined by the market's resolution rules.&lt;/p&gt;

&lt;p&gt;These measurements answer different questions. A reliable trading system should not treat them as interchangeable.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Tracking YES and NO Inventory Separately
&lt;/h2&gt;

&lt;p&gt;One simple way to measure inventory imbalance is to calculate the difference between YES and NO token quantities.&lt;/p&gt;

&lt;p&gt;Formula:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;inventory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;yes_quantity&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;no_quantity&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mathematically:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
I = Q_{YES} - Q_{NO}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(Q_{YES}): Number of YES tokens held.&lt;/li&gt;
&lt;li&gt;(Q_{NO}): Number of NO tokens held.&lt;/li&gt;
&lt;li&gt;(I): Net token-count difference.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;yes_quantity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
&lt;span class="n"&gt;no_quantity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;

&lt;span class="n"&gt;inventory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;yes_quantity&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;no_quantity&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# 60
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your bot holds 60 more YES tokens than NO tokens.&lt;/p&gt;

&lt;p&gt;This metric is useful for identifying an imbalance.&lt;/p&gt;

&lt;p&gt;However, &lt;strong&gt;net token quantity is not the same as financial exposure&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because YES and NO tokens can have different market prices.&lt;/p&gt;

&lt;p&gt;Their payout characteristics also depend on the specific market.&lt;/p&gt;

&lt;p&gt;Furthermore, outstanding orders can change your position even before they execute.&lt;/p&gt;

&lt;p&gt;For better risk management, track:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Net token inventory.&lt;/li&gt;
&lt;li&gt;Monetary exposure.&lt;/li&gt;
&lt;li&gt;Outstanding order exposure.&lt;/li&gt;
&lt;li&gt;Individual YES and NO position limits.&lt;/li&gt;
&lt;li&gt;Total portfolio exposure.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A balanced YES/NO token count does not automatically eliminate every type of financial risk.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Implementing Inventory-Aware Pricing
&lt;/h2&gt;

&lt;p&gt;Now let's connect inventory management with the pricing algorithm we built in Day 4.&lt;/p&gt;

&lt;p&gt;A basic market maker calculates its prices using:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
Bid = Midpoint - HalfSpread&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
Ask = Midpoint + HalfSpread&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Suppose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Midpoint:   $0.50
Half-spread: $0.02
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bot generates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bid: $0.48
Ask: $0.52
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a reasonable starting point.&lt;/p&gt;

&lt;p&gt;But what happens if your bot already holds 500 YES tokens?&lt;/p&gt;

&lt;p&gt;Should it continue buying at the same price?&lt;/p&gt;

&lt;p&gt;Probably not.&lt;/p&gt;

&lt;p&gt;It should become less aggressive about accumulating additional inventory.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;inventory-aware pricing&lt;/strong&gt; becomes useful.&lt;/p&gt;

&lt;h3&gt;
  
  
  The inventory-skew formula
&lt;/h3&gt;

&lt;p&gt;A simplified inventory-adjusted reference price is:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
P_{adjusted} = P_{mid} - kI&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(P_{mid}): Original reference midpoint.&lt;/li&gt;
&lt;li&gt;(I): Inventory deviation from the target.&lt;/li&gt;
&lt;li&gt;(k): Inventory-skew coefficient.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When inventory exceeds its target, the adjusted reference price decreases.&lt;/p&gt;

&lt;p&gt;This makes buying less aggressive and selling more attractive.&lt;/p&gt;

&lt;p&gt;When inventory is below its target, the adjusted reference price can increase, encouraging the bot to rebuild its position.&lt;/p&gt;
&lt;h3&gt;
  
  
  Practical example
&lt;/h3&gt;

&lt;p&gt;Assume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Midpoint:                  $0.50
Half-spread:               $0.02
Inventory deviation:       100 tokens
Inventory-skew coefficient: 0.0001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Calculate the adjusted midpoint:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
P_{adjusted} = 0.50 - (100 \times 0.0001)&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
P_{adjusted} = 0.49&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Now calculate the new quotes:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
Bid = 0.49 - 0.02 = 0.47&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
Ask = 0.49 + 0.02 = 0.51&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Compare the results:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Quote&lt;/th&gt;
&lt;th&gt;Original&lt;/th&gt;
&lt;th&gt;Inventory Adjusted&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bid&lt;/td&gt;
&lt;td&gt;$0.48&lt;/td&gt;
&lt;td&gt;$0.47&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ask&lt;/td&gt;
&lt;td&gt;$0.52&lt;/td&gt;
&lt;td&gt;$0.51&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The bot now offers a lower buying price and a lower selling price.&lt;/p&gt;

&lt;p&gt;This discourages additional buying while making it easier to sell existing inventory.&lt;/p&gt;

&lt;p&gt;The coefficient is illustrative. It must be calibrated to the market, trading costs, inventory limits, and strategy.&lt;/p&gt;

&lt;p&gt;Also, inventory should be measured against a target position, not necessarily zero. Some strategies intentionally maintain a nonzero position.&lt;/p&gt;


&lt;h2&gt;
  
  
  6. Writing Inventory-Aware Pricing Logic in Python
&lt;/h2&gt;

&lt;p&gt;Let's implement this concept.&lt;/p&gt;

&lt;p&gt;We'll use Python's &lt;code&gt;Decimal&lt;/code&gt; instead of ordinary floating-point numbers.&lt;/p&gt;

&lt;p&gt;Financial calculations can suffer from floating-point rounding errors, so Decimal is useful when working with prices and quantities.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_inventory_aware_quotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;midpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;half_spread&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;inventory_target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;skew_per_token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;midpoint&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Midpoint must be between 0 and 1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;half_spread&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Half-spread must be positive&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;skew_per_token&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Skew must not be negative&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;inventory_deviation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;inventory_target&lt;/span&gt;

    &lt;span class="n"&gt;adjusted_midpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;midpoint&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;inventory_deviation&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;skew_per_token&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;bid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;adjusted_midpoint&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;half_spread&lt;/span&gt;
    &lt;span class="n"&gt;ask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;adjusted_midpoint&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;half_spread&lt;/span&gt;

    &lt;span class="c1"&gt;# Illustrative binary-token price bounds.
&lt;/span&gt;    &lt;span class="n"&gt;bid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.01&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.99&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="n"&gt;ask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.01&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.99&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;bid&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid quotes: bid must be below ask&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;bid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ask&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inventory_deviation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inventory_deviation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;adjusted_midpoint&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;adjusted_midpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="n"&gt;quotes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_inventory_aware_quotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;midpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.50&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;half_spread&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.02&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;100&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;inventory_target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;skew_per_token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quotes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Understanding the results
&lt;/h3&gt;

&lt;p&gt;Try changing the inventory value:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Inventory&lt;/th&gt;
&lt;th&gt;Expected behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;No inventory adjustment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;Lower adjusted midpoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-100&lt;/td&gt;
&lt;td&gt;Higher adjusted midpoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Very large positive or negative value&lt;/td&gt;
&lt;td&gt;Candidate prices may become invalid&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One important detail: the example clamps prices to an illustrative range, but this doesn't guarantee valid quotes.&lt;/p&gt;

&lt;p&gt;A production implementation must also validate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Actual market tick size.&lt;/li&gt;
&lt;li&gt;Minimum and maximum allowed prices.&lt;/li&gt;
&lt;li&gt;Bid/ask relationship.&lt;/li&gt;
&lt;li&gt;Market-specific order rules.&lt;/li&gt;
&lt;li&gt;Inventory and exposure limits.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The function only calculates candidate quotes. It does not submit orders or guarantee profitability.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Why Inventory Skew Is Not Enough
&lt;/h2&gt;

&lt;p&gt;Inventory-aware pricing is useful, but it cannot solve every risk problem.&lt;/p&gt;

&lt;p&gt;Imagine your bot holds 500 YES tokens.&lt;/p&gt;

&lt;p&gt;Suddenly, the market becomes extremely volatile.&lt;/p&gt;

&lt;p&gt;Your inventory-skew formula adjusts the bid and ask prices.&lt;/p&gt;

&lt;p&gt;However, the market may still be moving too quickly for those prices to be safe.&lt;/p&gt;

&lt;p&gt;This is why professional trading systems need additional risk controls.&lt;/p&gt;

&lt;h3&gt;
  
  
  A. Maximum Inventory Limit
&lt;/h3&gt;

&lt;p&gt;Define the maximum number of tokens your bot is allowed to hold.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MAX_YES_INVENTORY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your bot reaches 200 YES tokens, it should stop increasing its YES position.&lt;/p&gt;

&lt;p&gt;Possible actions include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Canceling or reducing open buy orders.&lt;/li&gt;
&lt;li&gt;Blocking new exposure-increasing orders.&lt;/li&gt;
&lt;li&gt;Allowing permitted inventory-reducing actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  B. Maximum Outstanding Exposure
&lt;/h3&gt;

&lt;p&gt;An order doesn't need to execute to create potential risk.&lt;/p&gt;

&lt;p&gt;Suppose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Current YES inventory: 150
Open YES buy orders:   100
Maximum inventory:    200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your potential inventory is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;potential_inventory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;potential_inventory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# 250
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though the bot currently owns only 150 tokens, it could own 250 if all open buy orders execute.&lt;/p&gt;

&lt;p&gt;That exceeds the configured limit.&lt;/p&gt;

&lt;p&gt;A simplified calculation is:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
Q_{potential} = Q_{held} + Q_{open\ buys}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;A production risk manager must also account for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Partial fills.&lt;/li&gt;
&lt;li&gt;Pending cancellations.&lt;/li&gt;
&lt;li&gt;Multiple outstanding orders.&lt;/li&gt;
&lt;li&gt;Orders that reduce exposure.&lt;/li&gt;
&lt;li&gt;Orders whose execution state is uncertain.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  C. Maximum Loss Limit
&lt;/h3&gt;

&lt;p&gt;Define the maximum acceptable loss for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An individual market.&lt;/li&gt;
&lt;li&gt;The entire strategy.&lt;/li&gt;
&lt;li&gt;A trading session.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MAX_SESSION_LOSS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;50.00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the configured loss threshold is reached, the bot can stop submitting new orders and enter a controlled risk-reduction mode.&lt;/p&gt;

&lt;p&gt;The calculation should distinguish realized and unrealized P&amp;amp;L and include relevant fees and costs.&lt;/p&gt;

&lt;p&gt;Define the policy before trading rather than changing it whenever the market becomes uncomfortable.&lt;/p&gt;

&lt;h3&gt;
  
  
  D. Stale Market Data Detection
&lt;/h3&gt;

&lt;p&gt;Imagine your bot stops receiving market updates.&lt;/p&gt;

&lt;p&gt;Its last known midpoint is $0.50, but the actual market has already moved to $0.42.&lt;/p&gt;

&lt;p&gt;If the bot continues quoting around $0.50, it may create extremely unfavorable orders.&lt;/p&gt;

&lt;p&gt;A stale-data rule should prevent new pricing decisions from using outdated information.&lt;/p&gt;

&lt;p&gt;Depending on the system design, the bot may also need to cancel resting orders.&lt;/p&gt;

&lt;h3&gt;
  
  
  E. Market and Resolution Risk
&lt;/h3&gt;

&lt;p&gt;A market approaching resolution can behave differently from one with plenty of time remaining.&lt;/p&gt;

&lt;p&gt;For example, in a short-interval BTC Up/Down market, a sharp BTC movement can rapidly change the probability of the outcome.&lt;/p&gt;

&lt;p&gt;Your bot should consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Time remaining until resolution.&lt;/li&gt;
&lt;li&gt;Current market conditions.&lt;/li&gt;
&lt;li&gt;Volatility.&lt;/li&gt;
&lt;li&gt;Reliability of reference data.&lt;/li&gt;
&lt;li&gt;Potential price changes before an order executes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The same quoting parameters are not necessarily appropriate throughout every stage of a market.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Detecting Adverse Selection After Order Fills
&lt;/h2&gt;

&lt;p&gt;How can you determine whether your bot is repeatedly getting unfavorable fills?&lt;/p&gt;

&lt;p&gt;One useful approach is to compare the reference price at the time of a fill with the reference price after the fill.&lt;/p&gt;

&lt;p&gt;Let's consider a BUY transaction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Purchase price:             $0.48
Reference price at fill:    $0.49
Reference price 5s later:   $0.45
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reference price decreased by $0.04.&lt;/p&gt;

&lt;p&gt;This is a warning sign that the buy order may have been adversely selected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Calculate post-fill price movement
&lt;/h3&gt;

&lt;p&gt;For a buy:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
\Delta P = P_{after} - P_{at\ fill}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Using our example:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
\Delta P = 0.45 - 0.49&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
\Delta P = -0.04&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;A negative value means the reference price decreased after the purchase.&lt;/p&gt;

&lt;p&gt;For a sell, an increase in the reference price after the fill can be unfavorable because the bot sold before the market moved higher.&lt;/p&gt;
&lt;h3&gt;
  
  
  What should your bot record?
&lt;/h3&gt;

&lt;p&gt;For every executed order, store:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Market ID&lt;/td&gt;
&lt;td&gt;Which market was traded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Token ID&lt;/td&gt;
&lt;td&gt;Which token was traded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Side&lt;/td&gt;
&lt;td&gt;BUY or SELL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fill price&lt;/td&gt;
&lt;td&gt;Actual execution price&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fill quantity&lt;/td&gt;
&lt;td&gt;Number of executed tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reference price&lt;/td&gt;
&lt;td&gt;Price at the time of execution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Post-fill price&lt;/td&gt;
&lt;td&gt;Price after a selected interval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inventory before&lt;/td&gt;
&lt;td&gt;Position before execution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inventory after&lt;/td&gt;
&lt;td&gt;Position after execution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fees&lt;/td&gt;
&lt;td&gt;Associated trading costs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You can then measure post-fill price movement over different periods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 second.&lt;/li&gt;
&lt;li&gt;5 seconds.&lt;/li&gt;
&lt;li&gt;30 seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The appropriate time intervals depend on your market and strategy.&lt;/p&gt;

&lt;p&gt;This analysis helps answer important questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are buy orders frequently filled before prices fall?&lt;/li&gt;
&lt;li&gt;Are sell orders frequently filled before prices rise?&lt;/li&gt;
&lt;li&gt;Does adverse selection become worse during volatile periods?&lt;/li&gt;
&lt;li&gt;Are certain order sizes associated with worse outcomes?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember that reference-price movement is not the same as realized profit or loss.&lt;/p&gt;

&lt;p&gt;You need consistent reference prices, observation windows, and enough historical observations before changing your strategy.&lt;/p&gt;


&lt;h2&gt;
  
  
  9. Building a Risk-Control Decision Process
&lt;/h2&gt;

&lt;p&gt;A reliable market maker needs explicit rules for when it should continue quoting, reduce exposure, or stop placing orders.&lt;/p&gt;

&lt;p&gt;Here is a simplified decision process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;          Receive Market Update
                   |
                   v
         Is Market Data Fresh?
                   |
             +-----+-----+
             |           |
            No          Yes
             |           |
             v           v
        Pause or      Check Inventory,
        Cancel as     Exposure and
        Needed        Loss Limits
                          |
                          v
                   Are Limits Safe?
                          |
                    +-----+-----+
                    |           |
                   No          Yes
                    |           |
                    v           v
               Reduce Risk   Calculate
               or Pause      Adjusted Quotes
                                  |
                                  v
                            Validate Orders
                                  |
                                  v
                             Manage Orders
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The appropriate response depends on the specific risk condition.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Risk condition&lt;/th&gt;
&lt;th&gt;Possible response&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Inventory too high&lt;/td&gt;
&lt;td&gt;Reduce buying pressure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Outstanding exposure too high&lt;/td&gt;
&lt;td&gt;Block additional exposure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Market data stale&lt;/td&gt;
&lt;td&gt;Pause new quoting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uncertain order state&lt;/td&gt;
&lt;td&gt;Reconcile orders before submitting more&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Loss threshold reached&lt;/td&gt;
&lt;td&gt;Activate predefined risk policy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One important point: canceling every order is not always the safest response.&lt;/p&gt;

&lt;p&gt;A cancellation can race with an execution. A risk-reducing order might also be canceled unnecessarily.&lt;/p&gt;

&lt;p&gt;Your system should define how to respond to each risk condition instead of relying on a single emergency action.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Testing Risk Management Before Live Trading
&lt;/h2&gt;

&lt;p&gt;Never wait for a real trading loss to discover that your inventory calculations are incorrect.&lt;/p&gt;

&lt;p&gt;Your risk-management system should be tested against specific scenarios.&lt;/p&gt;

&lt;p&gt;Here is a practical test checklist:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Test Scenario&lt;/th&gt;
&lt;th&gt;Expected Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Inventory is zero&lt;/td&gt;
&lt;td&gt;Quotes use the original reference price&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inventory exceeds target&lt;/td&gt;
&lt;td&gt;Quotes discourage additional accumulation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inventory falls below target&lt;/td&gt;
&lt;td&gt;Quotes shift in the opposite direction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maximum inventory reached&lt;/td&gt;
&lt;td&gt;New exposure-increasing orders are blocked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open buy orders could exceed the limit&lt;/td&gt;
&lt;td&gt;Additional buying is restricted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Market data becomes stale&lt;/td&gt;
&lt;td&gt;New quoting pauses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Partial fill arrives&lt;/td&gt;
&lt;td&gt;Inventory and remaining quantity are updated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duplicate trade event arrives&lt;/td&gt;
&lt;td&gt;Inventory is not counted twice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cancellation is pending&lt;/td&gt;
&lt;td&gt;Potential exposure remains accounted for&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maximum loss reached&lt;/td&gt;
&lt;td&gt;Configured risk response activates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Candidate prices are invalid&lt;/td&gt;
&lt;td&gt;Orders are rejected before submission&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You should also test situations where several problems happen simultaneously.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Current inventory is near its maximum
             +
Market price is changing rapidly
             +
Cancellation request times out
             |
             v
      Risk Manager Activated
             |
             v
   Reconcile Actual Order State
             |
             v
   Recalculate Potential Exposure
             |
             v
   Apply Configured Risk Policy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is especially important because trading systems often experience multiple events at nearly the same time.&lt;/p&gt;

&lt;p&gt;A reliable risk manager must avoid making an uncertain situation worse by blindly submitting additional orders.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The goal isn't to build a bot that never loses money. That's impossible to guarantee.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The goal is to build a bot that understands its exposure, respects its limits, and responds predictably when something goes wrong.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion: Risk Management Is Part of the Trading Strategy
&lt;/h2&gt;

&lt;p&gt;Inventory risk and adverse selection are two of the most important challenges in automated market making.&lt;/p&gt;

&lt;p&gt;Your bot can calculate reasonable bid and ask prices and correctly manage every API request, but it can still lose money if it accumulates an unwanted position or repeatedly gets filled at unfavorable prices.&lt;/p&gt;

&lt;p&gt;Let's summarize the most important lessons from Day 6:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Track inventory continuously.&lt;/strong&gt; Know what your bot owns and what outstanding orders could add to its position.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use inventory-aware pricing.&lt;/strong&gt; Adjust quotes when the current position moves away from its target.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measure adverse selection.&lt;/strong&gt; Analyze how reference prices move after order execution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implement explicit risk limits.&lt;/strong&gt; Monitor inventory, outstanding exposure, market-data freshness, and losses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stop quoting when critical information is unreliable.&lt;/strong&gt; Never let your bot trade blindly using outdated data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test failure scenarios.&lt;/strong&gt; Make sure your risk controls work when fills, cancellations, and market movements happen together.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Remember: inventory skew and risk limits help control exposure, but they do not guarantee profitability. Market making remains exposed to volatility, fees, execution costs, and unfavorable fills.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next? Day 7 — Testing, Monitoring and Deployment
&lt;/h2&gt;

&lt;p&gt;We've now covered market data, pricing, order management, inventory risk, and risk controls.&lt;/p&gt;

&lt;p&gt;In the final article, we'll bring the project together.&lt;/p&gt;

&lt;p&gt;We'll explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Testing the complete trading bot.&lt;/li&gt;
&lt;li&gt;Measuring market-making performance.&lt;/li&gt;
&lt;li&gt;Monitoring live trading operations.&lt;/li&gt;
&lt;li&gt;Handling failures and unexpected behavior.&lt;/li&gt;
&lt;li&gt;Preparing a safer deployment workflow.&lt;/li&gt;
&lt;li&gt;Evaluating whether the strategy is actually profitable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The final goal is to move from a collection of trading components to a complete, testable market-making system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continue the Project
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;https://github.com/Benj4minCup/Polymarket-Trading-Bot-python&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;YouTube Tutorial:&lt;/strong&gt; &lt;a href="https://www.youtube.com/watch?v=UCF7MA1Kekk" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=UCF7MA1Kekk&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Telegram:&lt;/strong&gt; &lt;a href="https://telegram.me/BenjaminCup" rel="noopener noreferrer"&gt;https://telegram.me/BenjaminCup&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Follow the series to learn how to build a Polymarket trading bot step by step, from market data and quote calculation to order management and risk control.&lt;/p&gt;

</description>
      <category>polymarket</category>
      <category>architecture</category>
      <category>tutorial</category>
      <category>python</category>
    </item>
    <item>
      <title>Polymarket Trading Bot:How to Build a Market Maker Bot: Order Management, Limit Orders, and Partial Fills</title>
      <dc:creator>Benjamin-Cup</dc:creator>
      <pubDate>Thu, 29 Oct 2026 00:22:28 +0000</pubDate>
      <link>https://dev.to/benjamin_cup/polymarket-trading-bothow-to-build-a-market-maker-bot-order-management-limit-orders-and-partial-3m9p</link>
      <guid>https://dev.to/benjamin_cup/polymarket-trading-bothow-to-build-a-market-maker-bot-order-management-limit-orders-and-partial-3m9p</guid>
      <description>&lt;p&gt;&lt;em&gt;Day 5 of 7: Building a Polymarket Market Maker Bot From Zero to Complete&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In Day 4, we explored how a Polymarket market maker bot calculates bid and ask prices, manages spreads, and adjusts quotes based on inventory.&lt;/p&gt;

&lt;p&gt;But calculating the right price is only half the job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens after your bot places an order?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine your Python trading bot wants to buy YES tokens at &lt;code&gt;$0.48&lt;/code&gt; and sell them at &lt;code&gt;$0.52&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Before either order fills:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The market price changes.&lt;/li&gt;
&lt;li&gt;Another trader takes the available liquidity.&lt;/li&gt;
&lt;li&gt;Your order gets partially filled.&lt;/li&gt;
&lt;li&gt;Your API request times out.&lt;/li&gt;
&lt;li&gt;Your bot crashes while orders remain active.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your bot cannot handle these situations, even a good market-making strategy can lose control of its positions.&lt;/p&gt;

&lt;p&gt;In this tutorial, we'll explore how to build the order-management foundation of a Polymarket trading bot.&lt;/p&gt;

&lt;p&gt;We'll cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How limit orders work&lt;/li&gt;
&lt;li&gt;How to track an order's lifecycle&lt;/li&gt;
&lt;li&gt;How to handle partial fills&lt;/li&gt;
&lt;li&gt;When to cancel and replace orders&lt;/li&gt;
&lt;li&gt;How to avoid duplicate orders after API timeouts&lt;/li&gt;
&lt;li&gt;How to combine WebSockets with REST reconciliation&lt;/li&gt;
&lt;li&gt;How to protect open orders when a bot crashes&lt;/li&gt;
&lt;li&gt;How to test order-management failures before live trading&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The examples use Python and &lt;code&gt;Decimal&lt;/code&gt; for financial values. They demonstrate the decision-making logic, not a complete integration with the live Polymarket API.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. What Is Order Management?
&lt;/h2&gt;

&lt;p&gt;Order management is the part of a trading bot responsible for controlling the orders it sends to the exchange.&lt;/p&gt;

&lt;p&gt;It answers questions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which orders are currently active?&lt;/li&gt;
&lt;li&gt;How many tokens have been filled?&lt;/li&gt;
&lt;li&gt;How many tokens remain?&lt;/li&gt;
&lt;li&gt;Does an existing order still match the target price?&lt;/li&gt;
&lt;li&gt;Should the bot cancel an outdated order?&lt;/li&gt;
&lt;li&gt;What happens if an API request times out?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A market maker typically has three main components:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pricing engine&lt;/td&gt;
&lt;td&gt;Calculates target bid and ask prices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Order manager&lt;/td&gt;
&lt;td&gt;Places, tracks, updates, and cancels orders&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Risk manager&lt;/td&gt;
&lt;td&gt;Checks inventory, available funds, and exposure limits&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For example, the pricing engine calculates a YES bid of &lt;code&gt;$0.48&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Before submitting the order, the order manager checks whether a similar order already exists. The risk manager checks whether buying more YES tokens would exceed the configured position limit.&lt;/p&gt;

&lt;p&gt;Only then should the bot consider submitting the order.&lt;/p&gt;

&lt;p&gt;This separation makes the code easier to test, debug, and maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Understand Limit Orders
&lt;/h2&gt;

&lt;p&gt;A limit order specifies the maximum price you're willing to pay when buying or the minimum price you're willing to accept when selling.&lt;/p&gt;

&lt;p&gt;Imagine the YES token order book looks like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Order&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Quantity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Best ask&lt;/td&gt;
&lt;td&gt;$0.52&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Second ask&lt;/td&gt;
&lt;td&gt;$0.53&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best bid&lt;/td&gt;
&lt;td&gt;$0.47&lt;/td&gt;
&lt;td&gt;150&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Second bid&lt;/td&gt;
&lt;td&gt;$0.46&lt;/td&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The spread is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$0.52 - $0.47 = $0.05&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Your market maker calculates a bid at &lt;code&gt;$0.48&lt;/code&gt; and an ask at &lt;code&gt;$0.51&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If accepted and resting on the book, these orders offer to buy at &lt;code&gt;$0.48&lt;/code&gt; and sell at &lt;code&gt;$0.51&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, &lt;strong&gt;an accepted order is not necessarily a filled order&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A buy order at &lt;code&gt;$0.48&lt;/code&gt; might remain open because no seller is willing to trade at that price.&lt;/p&gt;

&lt;p&gt;Similarly, a sell order at &lt;code&gt;$0.51&lt;/code&gt; might remain open because no buyer accepts the offer.&lt;/p&gt;

&lt;p&gt;Your bot must track actual fills instead of assuming that an accepted order has executed.&lt;/p&gt;

&lt;h3&gt;
  
  
  What about post-only orders?
&lt;/h3&gt;

&lt;p&gt;Where supported, a post-only order is intended to rest on the order book rather than immediately match against an existing order.&lt;/p&gt;

&lt;p&gt;This can help a market maker provide liquidity instead of unintentionally taking it.&lt;/p&gt;

&lt;p&gt;However, post-only orders don't guarantee profit. Your order might still be filled just before the market moves against you.&lt;/p&gt;

&lt;p&gt;Always verify the supported order types and rules for the current Polymarket client and market.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Track the Order Lifecycle
&lt;/h2&gt;

&lt;p&gt;A reliable bot needs to know the state of every order it manages.&lt;/p&gt;

&lt;p&gt;A simplified order lifecycle looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Calculate target quote
        |
        v
Create order
        |
        v
Submit to exchange
        |
        +------&amp;gt; Rejected
        |
        v
      Accepted
        |
        v
     Open order
        |
        +------&amp;gt; Partially filled
        |                |
        |                v
        |       Update remaining quantity
        |                |
        +------&amp;gt; Fully filled
        |
        +------&amp;gt; Canceled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Real order lifecycles are more complicated. An order can be partially filled before cancellation, and a fill can occur while a cancellation request is being processed.&lt;/p&gt;

&lt;p&gt;Let's define a simple data model.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TrackedOrder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;token_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;
    &lt;span class="n"&gt;original_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;
    &lt;span class="n"&gt;matched_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;

    &lt;span class="nd"&gt;@property&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;remaining_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;original_size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;matched_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This model tracks the order ID, token, side, price, original quantity, matched quantity, and current status.&lt;/p&gt;

&lt;p&gt;The remaining quantity is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Remaining quantity = Original quantity - Matched quantity&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Suppose your bot submits an order to buy 100 YES tokens.&lt;/p&gt;

&lt;p&gt;If 35 tokens have been filled:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;100 - 35 = 65 tokens remaining&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The order manager must now manage the remaining 65 tokens, not the original 100.&lt;/p&gt;

&lt;p&gt;This is a small example, but the principle is essential for accurate inventory management.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Why Partial Fills Matter
&lt;/h2&gt;

&lt;p&gt;Partial fills are one of the most important challenges in market making.&lt;/p&gt;

&lt;p&gt;Imagine your bot submits these orders:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Buy 100 YES tokens at &lt;code&gt;$0.48&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Sell 100 YES tokens at &lt;code&gt;$0.52&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The buy order fills for 70 tokens, but the sell order remains unfilled.&lt;/p&gt;

&lt;p&gt;Your position has changed. You now own 70 additional YES tokens while the sell order may still have 100 tokens available to execute.&lt;/p&gt;

&lt;p&gt;If market conditions change, the remaining sell order might no longer match your strategy.&lt;/p&gt;

&lt;p&gt;The bot may need to reduce its size, reprice it, or cancel it.&lt;/p&gt;

&lt;p&gt;Three rules help prevent common mistakes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule 1: Update inventory using confirmed trade information.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An order acknowledgment doesn't mean the trade has completed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule 2: Recalculate the remaining quantity.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Always account for the quantity already matched.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule 3: Recalculate risk after every fill.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A partial fill can make previously acceptable quotes too risky.&lt;/p&gt;

&lt;p&gt;There is another important production consideration: duplicate trade events.&lt;/p&gt;

&lt;p&gt;If the same trade update arrives twice, your bot must not add the filled quantity to inventory twice. Use stable trade identifiers and idempotent processing to prevent duplicate accounting.&lt;/p&gt;
&lt;h2&gt;
  
  
  5. When Should You Cancel and Replace an Order?
&lt;/h2&gt;

&lt;p&gt;Market prices change constantly.&lt;/p&gt;

&lt;p&gt;Suppose your bot has a resting buy order at &lt;code&gt;$0.48&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A few seconds later, the best bid moves to &lt;code&gt;$0.50&lt;/code&gt;, and the best ask moves to &lt;code&gt;$0.51&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Your order is still valid, but it is now less competitive.&lt;/p&gt;

&lt;p&gt;Your bot has several choices:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keep the existing order.&lt;/li&gt;
&lt;li&gt;Cancel it and submit a new order.&lt;/li&gt;
&lt;li&gt;Reduce the order size because inventory is too large.&lt;/li&gt;
&lt;li&gt;Stop quoting because the market has become too risky.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The correct decision depends on your strategy and risk limits.&lt;/p&gt;
&lt;h3&gt;
  
  
  Avoid excessive repricing
&lt;/h3&gt;

&lt;p&gt;A beginner might replace an order every time the best bid changes by one tick.&lt;/p&gt;

&lt;p&gt;That sounds responsive, but it can cause:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Excessive API requests&lt;/li&gt;
&lt;li&gt;Frequent cancellations&lt;/li&gt;
&lt;li&gt;More opportunities for race conditions&lt;/li&gt;
&lt;li&gt;Unnecessary order-management complexity&lt;/li&gt;
&lt;li&gt;Increased exposure while orders are being updated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead, define explicit repricing rules.&lt;/p&gt;

&lt;p&gt;For example, reconsider an order when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The target price changes by a configured amount.&lt;/li&gt;
&lt;li&gt;The order exceeds its maximum age.&lt;/li&gt;
&lt;li&gt;Inventory crosses a risk threshold.&lt;/li&gt;
&lt;li&gt;Market data becomes stale.&lt;/li&gt;
&lt;li&gt;Market conditions make quoting unsafe.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are example rules, not universally optimal settings.&lt;/p&gt;

&lt;p&gt;Here's a simple price-comparison function:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;should_reprice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;current_price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;target_price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;min_change&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_price&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;target_price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;min_change&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;current_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.48&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;target_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.49&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;min_change&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.01&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;should_reprice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;current_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;target_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;min_change&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# True
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The function returns &lt;code&gt;True&lt;/code&gt; because the price difference meets the configured threshold.&lt;/p&gt;

&lt;p&gt;In production, use the market's actual tick size and valid price increments. Don't assume every market uses the same increment.&lt;/p&gt;

&lt;p&gt;Also remember that deciding to reprice is different from successfully replacing an order.&lt;/p&gt;
&lt;h2&gt;
  
  
  6. The Dangerous Part: Canceling and Replacing Orders
&lt;/h2&gt;

&lt;p&gt;Consider this sequence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your bot has a buy order open at &lt;code&gt;$0.48&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The target price changes to &lt;code&gt;$0.49&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Your bot requests cancellation of the old order.&lt;/li&gt;
&lt;li&gt;It immediately submits a new order at &lt;code&gt;$0.49&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The old order fills before the cancellation takes effect.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now both orders may have executed or remain relevant to your exposure.&lt;/p&gt;

&lt;p&gt;Your bot could buy more tokens than intended.&lt;/p&gt;

&lt;p&gt;This is called a &lt;strong&gt;race condition&lt;/strong&gt;: two operations happen close together, and their timing affects the result.&lt;/p&gt;

&lt;p&gt;A safer workflow is:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Target price changes
        |
        v
Mark old order for replacement
        |
        v
Request cancellation
        |
        v
Reconcile order status and fills
        |
        v
Recalculate inventory and exposure
        |
        v
Check risk limits
        |
        v
Submit replacement if still safe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The important part is reconciliation.&lt;/p&gt;

&lt;p&gt;A cancellation response doesn't erase fills that happened before cancellation. Likewise, an API timeout doesn't prove that the cancellation failed.&lt;/p&gt;

&lt;p&gt;Before creating additional exposure, your bot should determine the old order's actual state as accurately as possible.&lt;/p&gt;
&lt;h2&gt;
  
  
  7. What Happens When the API Times Out?
&lt;/h2&gt;

&lt;p&gt;This is one of the most dangerous order-management problems.&lt;/p&gt;

&lt;p&gt;Your bot submits an order, but the request times out.&lt;/p&gt;

&lt;p&gt;Did the exchange receive the order?&lt;/p&gt;

&lt;p&gt;There are at least two possibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The exchange never received it.&lt;/li&gt;
&lt;li&gt;The exchange accepted it, but your bot never received the response.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your bot blindly retries the request, the second situation can create a duplicate order.&lt;/p&gt;
&lt;h3&gt;
  
  
  Use an explicit unknown state
&lt;/h3&gt;

&lt;p&gt;Your internal order manager can track states such as:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;PENDING_SUBMISSION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pending_submission&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;OPEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;open&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;PARTIALLY_FILLED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;partially_filled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;PENDING_CANCEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pending_cancel&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;FILLED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;filled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;CANCELED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;canceled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;REJECTED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rejected&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;UNKNOWN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;These are example internal states, not a claim that Polymarket returns these exact status strings.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;UNKNOWN&lt;/code&gt; state is especially important.&lt;/p&gt;

&lt;p&gt;It means your bot doesn't yet know what happened.&lt;/p&gt;

&lt;p&gt;When a submission times out:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Mark the submission as uncertain.&lt;/li&gt;
&lt;li&gt;Avoid blindly sending another order.&lt;/li&gt;
&lt;li&gt;Query the exchange's order or account information where possible.&lt;/li&gt;
&lt;li&gt;Process available order and trade updates.&lt;/li&gt;
&lt;li&gt;Reconcile the exchange state with local records.&lt;/li&gt;
&lt;li&gt;Retry only after the previous attempt is understood and the strategy still permits another order.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the API supports a documented idempotency mechanism, use it correctly. Otherwise, build a reconciliation process that accounts for uncertain outcomes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A timeout is a lack of information, not proof that an order was rejected.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  8. WebSockets and REST: Why You Need Both
&lt;/h2&gt;

&lt;p&gt;A market maker needs two kinds of information:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What is happening in the market?&lt;/li&gt;
&lt;li&gt;What is happening to the bot's own orders?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A practical architecture combines WebSocket updates with REST reconciliation.&lt;/p&gt;
&lt;h3&gt;
  
  
  Market data stream
&lt;/h3&gt;

&lt;p&gt;Provides order-book updates used by the pricing engine to calculate new quotes.&lt;/p&gt;
&lt;h3&gt;
  
  
  User and account updates
&lt;/h3&gt;

&lt;p&gt;Where supported, provides updates related to your own orders and trades.&lt;/p&gt;
&lt;h3&gt;
  
  
  REST reconciliation
&lt;/h3&gt;

&lt;p&gt;Allows the bot to query the current state of orders or trades and recover from missed events or reconnects.&lt;/p&gt;

&lt;p&gt;Why not use WebSockets alone?&lt;/p&gt;

&lt;p&gt;Connections can disconnect, applications can restart, and events can be missed while the bot is offline.&lt;/p&gt;

&lt;p&gt;Why not use REST polling alone?&lt;/p&gt;

&lt;p&gt;Frequent polling can create unnecessary API traffic and may be less responsive to market changes.&lt;/p&gt;

&lt;p&gt;A useful architecture looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market WebSocket
       |
       v
Market Data Cache
       |
       v
Pricing Engine
       |
       v
Risk Manager
       |
       v
Order Manager
       |
       v
Polymarket CLOB
       |
       +------&amp;gt; Order/Trade Updates
       |
       +------&amp;gt; REST Reconciliation
                       |
                       v
               Local Order State
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;WebSockets provide timely updates. REST reconciliation helps the bot recover when its local view becomes incomplete.&lt;/p&gt;

&lt;p&gt;Check the current official Polymarket documentation for the supported endpoints, authentication, subscription formats, and client methods before implementing this architecture.&lt;/p&gt;
&lt;h2&gt;
  
  
  9. Build a Basic Order Manager in Python
&lt;/h2&gt;

&lt;p&gt;Let's bring the main concepts together.&lt;/p&gt;

&lt;p&gt;The following code implements a small decision-making layer. It does not submit real orders or call the Polymarket API.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;PENDING_SUBMISSION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pending_submission&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;OPEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;open&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;PARTIALLY_FILLED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;partially_filled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;PENDING_CANCEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pending_cancel&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;FILLED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;filled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;CANCELED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;canceled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;REJECTED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rejected&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;UNKNOWN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;side&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;
    &lt;span class="n"&gt;original_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;
    &lt;span class="n"&gt;matched_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OrderStatus&lt;/span&gt;

    &lt;span class="nd"&gt;@property&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;remaining_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;original_size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;matched_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;needs_replacement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;target_price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;min_price_change&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;active_states&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OPEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PARTIALLY_FILLED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;active_states&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remaining_size&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;target_price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;min_price_change&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let's understand what this code does.&lt;/p&gt;

&lt;p&gt;First, it defines the possible states the bot tracks.&lt;/p&gt;

&lt;p&gt;Second, it calculates how much of an order remains unfilled.&lt;/p&gt;

&lt;p&gt;Third, it checks whether an active order should be considered for replacement.&lt;/p&gt;

&lt;p&gt;For example, an open buy order at &lt;code&gt;$0.48&lt;/code&gt; may need reconsideration when the target price changes to &lt;code&gt;$0.50&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, this function does not cancel or replace anything automatically.&lt;/p&gt;

&lt;p&gt;A complete implementation must also check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Market data freshness&lt;/li&gt;
&lt;li&gt;Available balance&lt;/li&gt;
&lt;li&gt;Inventory and exposure limits&lt;/li&gt;
&lt;li&gt;Duplicate or conflicting orders&lt;/li&gt;
&lt;li&gt;Open-order limits&lt;/li&gt;
&lt;li&gt;Outstanding cancellation requests&lt;/li&gt;
&lt;li&gt;Exchange connectivity and market status&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keeping these responsibilities separate makes the system easier to reason about and test.&lt;/p&gt;
&lt;h2&gt;
  
  
  10. Add Risk Checks Before Sending Orders
&lt;/h2&gt;

&lt;p&gt;Never place an order simply because the pricing engine produced a price.&lt;/p&gt;

&lt;p&gt;Before submission, check the following:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Market data&lt;/td&gt;
&lt;td&gt;Is the order book fresh enough?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Price&lt;/td&gt;
&lt;td&gt;Is the price valid for this market?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quantity&lt;/td&gt;
&lt;td&gt;Is the order size permitted?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Balance&lt;/td&gt;
&lt;td&gt;Are sufficient funds or tokens available?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inventory&lt;/td&gt;
&lt;td&gt;Could this order exceed the position limit?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open orders&lt;/td&gt;
&lt;td&gt;Does a duplicate or conflicting order exist?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Order state&lt;/td&gt;
&lt;td&gt;Is another submission or cancellation unresolved?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Market status&lt;/td&gt;
&lt;td&gt;Is the market still accepting orders?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connectivity&lt;/td&gt;
&lt;td&gt;Can the bot monitor and reconcile its orders?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One especially important rule is to consider &lt;strong&gt;potential exposure from open orders&lt;/strong&gt;, not just current inventory.&lt;/p&gt;

&lt;p&gt;Suppose your bot currently holds 80 YES tokens and has two open buy orders for 50 additional YES tokens each.&lt;/p&gt;

&lt;p&gt;Its current inventory is 80 tokens.&lt;/p&gt;

&lt;p&gt;If both orders fill, inventory could reach:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;80 + 50 + 50 = 180 tokens&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If the configured inventory limit is 150 tokens, the bot must account for those possible fills before submitting more orders.&lt;/p&gt;

&lt;p&gt;The exact exposure calculation depends on your strategy, available collateral, related positions, and other outstanding orders.&lt;/p&gt;

&lt;p&gt;Start with conservative limits and test the calculations carefully.&lt;/p&gt;
&lt;h2&gt;
  
  
  11. Protect Your Orders When the Bot Crashes
&lt;/h2&gt;

&lt;p&gt;Imagine your bot runs on a VPS and has several active orders.&lt;/p&gt;

&lt;p&gt;Then the process crashes because of a software bug or server restart.&lt;/p&gt;

&lt;p&gt;The orders may remain active even though the process that manages them is no longer running.&lt;/p&gt;

&lt;p&gt;The market can continue moving while your bot is unable to react.&lt;/p&gt;

&lt;p&gt;A production system needs a recovery plan.&lt;/p&gt;
&lt;h3&gt;
  
  
  Before shutdown or restart
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Decide whether open orders should be canceled or preserved for controlled recovery.&lt;/li&gt;
&lt;li&gt;Persist enough information to identify previously submitted orders.&lt;/li&gt;
&lt;li&gt;Never assume that stopping the process automatically cancels exchange orders.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  After restart
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Reconnect to the exchange.&lt;/li&gt;
&lt;li&gt;Retrieve relevant open orders and trade information.&lt;/li&gt;
&lt;li&gt;Rebuild local order state.&lt;/li&gt;
&lt;li&gt;Reconcile fills that occurred while offline.&lt;/li&gt;
&lt;li&gt;Recalculate inventory and available funds.&lt;/li&gt;
&lt;li&gt;Resume quoting only when the account state is sufficiently understood.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Where supported, investigate heartbeat or dead-man-switch functionality that can cancel resting orders if required heartbeats stop. Verify its exact behavior and timeout semantics before relying on it.&lt;/p&gt;

&lt;p&gt;Additional protections can include maximum order lifetimes, stale-data shutdown rules, and emergency cancellation procedures.&lt;/p&gt;

&lt;p&gt;These protections complement reconciliation; they don't replace it.&lt;/p&gt;
&lt;h2&gt;
  
  
  12. Test Failure Scenarios Before Live Trading
&lt;/h2&gt;

&lt;p&gt;A bot that works during a normal demonstration isn't necessarily reliable.&lt;/p&gt;

&lt;p&gt;Before using real funds, test how it responds to failures.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Expected behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Order accepted&lt;/td&gt;
&lt;td&gt;Track it as active&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Order rejected&lt;/td&gt;
&lt;td&gt;Record the rejection and avoid treating it as filled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Partial fill&lt;/td&gt;
&lt;td&gt;Update inventory and remaining quantity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full fill&lt;/td&gt;
&lt;td&gt;Mark the order complete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cancellation races with a fill&lt;/td&gt;
&lt;td&gt;Reconcile the final status and matched quantity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Submission times out&lt;/td&gt;
&lt;td&gt;Mark the outcome uncertain and avoid blind retries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duplicate trade event arrives&lt;/td&gt;
&lt;td&gt;Do not count the same fill twice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WebSocket disconnects&lt;/td&gt;
&lt;td&gt;Reconnect and reconcile missed updates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bot restarts with open orders&lt;/td&gt;
&lt;td&gt;Rebuild local state before resuming&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Market becomes inactive&lt;/td&gt;
&lt;td&gt;Stop submitting inappropriate orders&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Balance changes&lt;/td&gt;
&lt;td&gt;Recalculate available funds and exposure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Market data becomes stale&lt;/td&gt;
&lt;td&gt;Stop new quoting until data is reliable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For every scenario, define the expected behavior before writing the test.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; The order-submission request times out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expected behavior:&lt;/strong&gt; The bot marks the outcome as uncertain, checks the exchange state, avoids blindly resubmitting, and prevents additional exposure from exceeding its risk limits while the outcome is unresolved.&lt;/p&gt;

&lt;p&gt;This is how you move from a simple trading script toward a reliable trading system.&lt;/p&gt;
&lt;h2&gt;
  
  
  13. The Complete Order-Management Loop
&lt;/h2&gt;

&lt;p&gt;A market maker's order-management loop can be summarized in ten steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read fresh market data.&lt;/li&gt;
&lt;li&gt;Calculate target bid and ask prices.&lt;/li&gt;
&lt;li&gt;Check market and account risk.&lt;/li&gt;
&lt;li&gt;Compare target prices with tracked orders.&lt;/li&gt;
&lt;li&gt;Decide whether to keep, cancel, or replace orders.&lt;/li&gt;
&lt;li&gt;Submit only permitted orders.&lt;/li&gt;
&lt;li&gt;Track acknowledgments and trade updates.&lt;/li&gt;
&lt;li&gt;Reconcile uncertain order states.&lt;/li&gt;
&lt;li&gt;Update inventory and available funds.&lt;/li&gt;
&lt;li&gt;Repeat.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The bot should stop placing new orders when market data becomes stale, account state cannot be reconciled, or a configured risk limit is breached.&lt;/p&gt;

&lt;p&gt;A reliable market maker doesn't keep trading just because its main process is still running.&lt;/p&gt;

&lt;p&gt;It trades only when it has enough reliable information to make a controlled decision.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Building a Polymarket market maker bot requires much more than calculating bid and ask prices.&lt;/p&gt;

&lt;p&gt;The bot must manage the complete order lifecycle, including partial fills, cancellations, API timeouts, reconnects, and recovery after a crash.&lt;/p&gt;

&lt;p&gt;Here are the most important lessons from Day 5:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An accepted order is not necessarily a filled order.&lt;/li&gt;
&lt;li&gt;Partial fills must update inventory and remaining quantity.&lt;/li&gt;
&lt;li&gt;Cancellation and replacement require careful state management.&lt;/li&gt;
&lt;li&gt;An API timeout does not prove that an order failed.&lt;/li&gt;
&lt;li&gt;WebSocket updates should be combined with reconciliation.&lt;/li&gt;
&lt;li&gt;Risk checks must account for open orders as well as current inventory.&lt;/li&gt;
&lt;li&gt;Restarting a bot must not mean blindly trusting its previous local state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In &lt;strong&gt;Day 6&lt;/strong&gt;, we'll move from order management to inventory risk, market conditions, and adverse selection. We'll explore why market makers sometimes get filled just before the market moves against them, and how a bot can respond.&lt;/p&gt;
&lt;h2&gt;
  
  
  Continue the Project
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub repository:&lt;/strong&gt; [Polymarket Trading Bot in Python]&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Benj4minCup" rel="noopener noreferrer"&gt;
        Benj4minCup
      &lt;/a&gt; / &lt;a href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;
        Polymarket-Trading-Bot-python
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Polymarket Trading Bot  Twap Bot polymarket Arbitrage Bot
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Polymarket Trading bot system&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;An open-source and Strong Strategy collection of Polymarket trading bot and Polymarket arbitrage bot and Polymarket TWAP trading bot in Python for high-performance automated trading on polymarket crypto 5min and 15min markets.&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/33036584/633381478-71b65c58-00d2-4bbe-8b6d-8ed6fc9812e4.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3OTMyMzM2NDcsIm5iZiI6MTc5MzIzMzM0NywicGF0aCI6Ii8zMzAzNjU4NC82MzMzODE0NzgtNzFiNjVjNTgtMDBkMi00YmJlLThiNmQtOGVkNmZjOTgxMmU0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjEwMjklMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYxMDI5VDAwMjIyN1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTBhNTE4YzFmMzY0NjcwMmZjY2Y5OGQyMGM5YTI2NTgxMGMxY2I1NDY1MzUzMDY4MDI4OTlkYzUyN2Y4OWVhYTQmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.J1-HVYNTzrOjRn2Xx_9TOcJBtNceJVnGD5giwVdNOkQ"&gt;&lt;img width="1536" height="1024" alt="Polymarket-benjamincup-bot-dashboard" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F33036584%2F633381478-71b65c58-00d2-4bbe-8b6d-8ed6fc9812e4.png%3Fjwt%3DeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3OTMyMzM2NDcsIm5iZiI6MTc5MzIzMzM0NywicGF0aCI6Ii8zMzAzNjU4NC82MzMzODE0NzgtNzFiNjVjNTgtMDBkMi00YmJlLThiNmQtOGVkNmZjOTgxMmU0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjEwMjklMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYxMDI5VDAwMjIyN1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTBhNTE4YzFmMzY0NjcwMmZjY2Y5OGQyMGM5YTI2NTgxMGMxY2I1NDY1MzUzMDY4MDI4OTlkYzUyN2Y4OWVhYTQmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.J1-HVYNTzrOjRn2Xx_9TOcJBtNceJVnGD5giwVdNOkQ" class="js-gh-image-fallback"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This repository is primarily intended for educational and research purposes. It includes strategy concepts, implementation approaches, and selected performance screenshots to help developers understand how different automated trading strategies can be designed and tested.&lt;/p&gt;

&lt;p&gt;The repository does not provide a complete production-ready trading bot source code. Instead, it provides strategy descriptions and research materials that you can use as a foundation for developing your own system.&lt;/p&gt;

&lt;p&gt;If you are interested in building a Polymarket Trading Bot, you can follow my tutorials and use the concepts in this repository to develop your own implementation.&lt;/p&gt;

&lt;p&gt;For users who prefer a ready-to-deploy solution or require custom strategy development, commercial bot development and customization are also available.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;YouTube tutorial:&lt;/strong&gt; [Watch the Polymarket trading bot tutorial]&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/UCF7MA1Kekk" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Telegram:&lt;/strong&gt; &lt;a href="https://telegram.me/BenjaminCup" rel="noopener noreferrer"&gt;Join the discussion&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Follow along as we build a Polymarket trading bot step by step, from market data and pricing to order execution and risk management.&lt;/p&gt;




</description>
      <category>polymarket</category>
      <category>python</category>
      <category>trading</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building a Polymarket Market Maker in Python: Quotes, Spreads, and Inventory Management</title>
      <dc:creator>Benjamin-Cup</dc:creator>
      <pubDate>Tue, 27 Oct 2026 16:08:51 +0000</pubDate>
      <link>https://dev.to/benjamin_cup/building-a-polymarket-market-maker-in-python-quotes-spreads-and-inventory-management-38dj</link>
      <guid>https://dev.to/benjamin_cup/building-a-polymarket-market-maker-in-python-quotes-spreads-and-inventory-management-38dj</guid>
      <description>&lt;p&gt;&lt;em&gt;Day 4 of 7 — Building a Polymarket Market Maker Bot From Zero to Complete&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;How does a trading bot decide when to buy, when to sell, and which prices to use?&lt;/p&gt;

&lt;p&gt;In the previous articles in this series, we explored what a Polymarket trading bot is, how prediction market order books work, and how to retrieve market data using Python.&lt;/p&gt;

&lt;p&gt;Today, we're moving from &lt;strong&gt;reading the order book to calculating our own quotes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/..." class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/..." alt="polymarket trading Bot" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll build a simple market-making strategy that calculates bid and ask prices, adjusts quotes based on inventory, and validates its output before any order reaches the exchange.&lt;/p&gt;

&lt;p&gt;By the end of this tutorial, you'll understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to calculate a reference price from the order book&lt;/li&gt;
&lt;li&gt;How bid-ask spreads work&lt;/li&gt;
&lt;li&gt;How inventory affects market-making decisions&lt;/li&gt;
&lt;li&gt;How to implement inventory-aware pricing in Python&lt;/li&gt;
&lt;li&gt;How to write unit tests for your strategy&lt;/li&gt;
&lt;li&gt;What needs to happen before connecting the strategy to live order execution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is an educational implementation, not a production-ready trading bot. We'll keep the pricing logic separate from order execution so we can test it independently.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. What Is a Market-Making Strategy?
&lt;/h2&gt;

&lt;p&gt;Imagine a Polymarket market asking whether Bitcoin will finish above a particular price at a specified time.&lt;/p&gt;

&lt;p&gt;The YES token currently has the following order book:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Order book item&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Best bid&lt;/td&gt;
&lt;td&gt;$0.48&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best ask&lt;/td&gt;
&lt;td&gt;$0.52&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Midpoint&lt;/td&gt;
&lt;td&gt;$0.50&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The best bid is the highest price someone is currently offering to pay. The best ask is the lowest price someone is currently willing to accept.&lt;/p&gt;

&lt;p&gt;Our bot wants to place its own orders.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Buy YES at $0.49.&lt;/li&gt;
&lt;li&gt;Sell YES at $0.51.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These prices would improve on the existing bid and ask in this hypothetical example, provided the market's tick size and other trading rules permit them.&lt;/p&gt;

&lt;p&gt;But should the bot always use these prices?&lt;/p&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;The market changes constantly. Liquidity can disappear, competing orders can arrive, and the bot can accumulate more tokens than it wants to hold.&lt;/p&gt;

&lt;p&gt;A market-making strategy converts market data, trading parameters, and current inventory into desired quotes.&lt;/p&gt;

&lt;p&gt;The goal is to provide liquidity while managing execution risk and inventory exposure. A positive spread alone does not guarantee a profit.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Calculate the Reference Price
&lt;/h2&gt;

&lt;p&gt;Before generating quotes, we need a reference price.&lt;/p&gt;

&lt;p&gt;For a simple market maker, we can start with the midpoint between the best bid and the best ask.&lt;/p&gt;

&lt;p&gt;The formula is:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
M = \frac{B + A}{2}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(M) = midpoint&lt;/li&gt;
&lt;li&gt;(B) = best bid&lt;/li&gt;
&lt;li&gt;(A) = best ask&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using our example:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
M = \frac{0.48 + 0.52}{2} = 0.50&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Our reference price is $0.50.&lt;/p&gt;

&lt;p&gt;The midpoint is easy to calculate, but it has limitations. It doesn't necessarily represent the token's true value, and it may not be executable at meaningful size.&lt;/p&gt;

&lt;p&gt;A more advanced strategy could incorporate order book imbalance, recent price movements, volatility, and other signals to estimate a fair value.&lt;/p&gt;

&lt;p&gt;For now, we'll use the midpoint to keep the implementation simple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; If market data is stale, the book is empty, or the best bid is greater than or equal to the best ask, the bot should stop generating quotes until the data has been validated.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Calculate the Bid and Ask
&lt;/h2&gt;

&lt;p&gt;A basic market maker places its bid below the reference price and its ask above it.&lt;/p&gt;

&lt;p&gt;We can express this as:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
\text{Bid} = M - h&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
\text{Ask} = M + h&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Here, (h) represents the target half-spread.&lt;/p&gt;

&lt;p&gt;Suppose our parameters are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Midpoint: $0.50&lt;/li&gt;
&lt;li&gt;Half-spread: $0.02&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Midpoint&lt;/td&gt;
&lt;td&gt;$0.50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Half-spread&lt;/td&gt;
&lt;td&gt;$0.02&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Target bid&lt;/td&gt;
&lt;td&gt;$0.48&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Target ask&lt;/td&gt;
&lt;td&gt;$0.52&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total spread&lt;/td&gt;
&lt;td&gt;$0.04&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The total spread is:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
S = \text{Ask} - \text{Bid}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Therefore:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
S = 0.52 - 0.48 = 0.04&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;This gives us a simple starting point for calculating quotes.&lt;/p&gt;

&lt;p&gt;However, a fixed spread ignores market conditions. A narrow spread might be competitive in a liquid market but risky during rapid price movements. A wide spread might protect against some risks but make our orders less competitive.&lt;/p&gt;

&lt;p&gt;Let's look at how inventory changes the calculation.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Why Inventory Management Matters
&lt;/h2&gt;

&lt;p&gt;Imagine our bot starts with zero YES tokens.&lt;/p&gt;

&lt;p&gt;It places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A buy order for 100 YES tokens at $0.48.&lt;/li&gt;
&lt;li&gt;A sell order at $0.52.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The buy order fills, but the sell order doesn't.&lt;/p&gt;

&lt;p&gt;Our bot now holds 100 YES tokens.&lt;/p&gt;

&lt;p&gt;If it continues placing the same buy and sell quotes, it could accumulate even more tokens without reducing its existing position.&lt;/p&gt;

&lt;p&gt;This is called &lt;strong&gt;inventory risk&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A market maker must consider not only the price of its next trade but also how that trade changes its overall position.&lt;/p&gt;

&lt;p&gt;When inventory grows, the strategy might:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make its buy quote less competitive.&lt;/li&gt;
&lt;li&gt;Adjust its sell quote to encourage inventory reduction.&lt;/li&gt;
&lt;li&gt;Reduce order sizes.&lt;/li&gt;
&lt;li&gt;Stop placing additional buy orders at its maximum inventory limit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are separate controls. Adjusting prices can influence trading behavior, but it cannot guarantee that inventory will decrease.&lt;/p&gt;
&lt;h2&gt;
  
  
  5. Implement Inventory-Aware Pricing
&lt;/h2&gt;

&lt;p&gt;Let's introduce a simple inventory adjustment.&lt;/p&gt;

&lt;p&gt;Instead of generating quotes directly from the midpoint, we'll adjust our reference price first:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
R = M - qk&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(R) = inventory-adjusted reference price&lt;/li&gt;
&lt;li&gt;(M) = market midpoint&lt;/li&gt;
&lt;li&gt;(q) = current inventory, measured in tokens&lt;/li&gt;
&lt;li&gt;(k) = inventory adjustment per token&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Positive inventory shifts the reference price downward. Negative inventory shifts it upward, assuming inventory is measured relative to a target position of zero.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Midpoint = $0.50&lt;/li&gt;
&lt;li&gt;Inventory = 100 YES tokens&lt;/li&gt;
&lt;li&gt;Inventory adjustment = $0.0001 per token&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
R = 0.50 - (100 \times 0.0001)&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
R = 0.49&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Our adjusted reference price is $0.49.&lt;/p&gt;

&lt;p&gt;With a half-spread of $0.02:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
\text{Bid} = 0.49 - 0.02 = 0.47&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
\text{Ask} = 0.49 + 0.02 = 0.51&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Compare the original and adjusted quotes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Quote&lt;/th&gt;
&lt;th&gt;Before adjustment&lt;/th&gt;
&lt;th&gt;After adjustment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bid&lt;/td&gt;
&lt;td&gt;$0.48&lt;/td&gt;
&lt;td&gt;$0.47&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ask&lt;/td&gt;
&lt;td&gt;$0.52&lt;/td&gt;
&lt;td&gt;$0.51&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Both quotes have moved downward.&lt;/p&gt;

&lt;p&gt;The lower bid makes the bot less eager to acquire additional YES tokens, while the lower ask may make selling more competitive.&lt;/p&gt;

&lt;p&gt;This is a simplified inventory-skew model. In a production strategy, the adjustment should be calibrated to inventory limits, volatility, liquidity, time to market resolution, and the cost of reducing exposure.&lt;/p&gt;
&lt;h2&gt;
  
  
  6. Write the Pricing Function in Python
&lt;/h2&gt;

&lt;p&gt;Now let's implement the pricing logic.&lt;/p&gt;

&lt;p&gt;We'll use Python's &lt;code&gt;Decimal&lt;/code&gt; type instead of floating-point numbers because trading prices require predictable decimal arithmetic.&lt;/p&gt;

&lt;p&gt;Create a file called &lt;code&gt;strategy.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Quote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;bid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;
    &lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_quotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;midpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;half_spread&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;inventory_skew&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;min_price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.01&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;max_price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.99&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Quote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Calculate inventory-aware candidate quotes.

    Positive inventory shifts both quotes downward.
    Negative inventory shifts both quotes upward.

    This function calculates prices only.
    It does not submit live orders.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;min_price&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;max_price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid price bounds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;min_price&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;midpoint&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;max_price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Midpoint is outside allowed bounds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;half_spread&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Half-spread must be positive&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;inventory_skew&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Inventory skew must not be negative&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;adjusted_reference&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;midpoint&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;inventory&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;inventory_skew&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;bid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;adjusted_reference&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;half_spread&lt;/span&gt;
    &lt;span class="n"&gt;ask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;adjusted_reference&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;half_spread&lt;/span&gt;

    &lt;span class="c1"&gt;# Clamp candidate prices to configured bounds.
&lt;/span&gt;    &lt;span class="n"&gt;bid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_price&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_price&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;bid&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Quotes are invalid after applying price bounds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Quote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;quote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_quotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;midpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.50&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;half_spread&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.02&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;100&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;inventory_skew&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Candidate bid:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Candidate ask:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Run the script:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python strategy.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Expected output:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Candidate bid: 0.4700
Candidate ask: 0.5100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We now have a function that transforms market conditions and inventory into candidate quotes.&lt;/p&gt;

&lt;p&gt;Notice what the function doesn't do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It doesn't retrieve market data.&lt;/li&gt;
&lt;li&gt;It doesn't check whether the order book has changed.&lt;/li&gt;
&lt;li&gt;It doesn't place or cancel orders.&lt;/li&gt;
&lt;li&gt;It doesn't check account balances.&lt;/li&gt;
&lt;li&gt;It doesn't guarantee that either quote can be executed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keeping these responsibilities separate makes the strategy easier to understand and test.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation note:&lt;/strong&gt; Clamping prices to a range is not enough to validate an actual order. Production code must also handle tick-size rounding, minimum order sizes, crossing the book, and the case where a valid bid and ask cannot be produced.&lt;/p&gt;
&lt;h2&gt;
  
  
  7. Order Size Is Just as Important as Price
&lt;/h2&gt;

&lt;p&gt;Suppose two bots use the same quotes.&lt;/p&gt;

&lt;p&gt;Bot A places orders for 5 tokens.&lt;/p&gt;

&lt;p&gt;Bot B places orders for 1,000 tokens.&lt;/p&gt;

&lt;p&gt;Their prices are identical, but their inventory exposure is very different.&lt;/p&gt;

&lt;p&gt;If the buy orders fill, Bot B can accumulate a much larger position before the bot has an opportunity to react.&lt;/p&gt;

&lt;p&gt;A basic order-sizing policy should consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Available capital&lt;/li&gt;
&lt;li&gt;Current inventory&lt;/li&gt;
&lt;li&gt;Maximum allowed position&lt;/li&gt;
&lt;li&gt;Market liquidity&lt;/li&gt;
&lt;li&gt;Minimum order requirements&lt;/li&gt;
&lt;li&gt;Potential costs of exiting the position&lt;/li&gt;
&lt;li&gt;Multiple orders filling before cancellations complete&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For an initial implementation, use a small fixed order size and enforce a strict maximum inventory.&lt;/p&gt;

&lt;p&gt;For example, if the bot has reached its maximum allowed YES inventory, the risk manager should prevent it from submitting additional buy orders.&lt;/p&gt;

&lt;p&gt;This control should be enforced independently of the quote calculation. A valid price does not automatically mean the bot should be allowed to trade.&lt;/p&gt;
&lt;h2&gt;
  
  
  8. Validate Quotes Against Polymarket's Trading Rules
&lt;/h2&gt;

&lt;p&gt;Our Python function calculates decimal prices, but a real Polymarket order must satisfy the selected market's current trading rules.&lt;/p&gt;

&lt;p&gt;A candidate price such as $0.4837 may not be valid for a market with a different tick size.&lt;/p&gt;

&lt;p&gt;Before submitting an order, the bot should:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retrieve the market's current trading parameters.&lt;/li&gt;
&lt;li&gt;Round prices to valid increments using a deliberate rounding policy.&lt;/li&gt;
&lt;li&gt;Validate price bounds and order-size precision.&lt;/li&gt;
&lt;li&gt;Check token balances and available funds.&lt;/li&gt;
&lt;li&gt;Check whether the order would cross the current book.&lt;/li&gt;
&lt;li&gt;Confirm that the market is still open for trading.&lt;/li&gt;
&lt;li&gt;Verify inventory and risk limits.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Avoid hardcoding a single tick size or minimum order size for every market.&lt;/p&gt;

&lt;p&gt;Also, the book may change between calculation and submission. Local validation reduces avoidable errors, but it cannot eliminate execution races.&lt;/p&gt;
&lt;h2&gt;
  
  
  9. Separate Strategy, Risk, and Execution
&lt;/h2&gt;

&lt;p&gt;A market-making bot is easier to maintain when its responsibilities are separated.&lt;/p&gt;

&lt;p&gt;A useful architecture looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Market Data
    |
    v
Quote Strategy
    |
    v
Risk Manager
    |
    v
Order Manager
    |
    v
Polymarket Trading Interface
    |
    v
Order and Fill Updates
    |
    v
Inventory State
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Each component has a distinct responsibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Market Data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Retrieves order book updates and maintains a reliable view of current market conditions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quote Strategy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Calculates the desired bid and ask prices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Risk Manager&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Checks maximum inventory, order size, available capital, and other trading limits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Order Manager&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Decides whether to submit, retain, cancel, or replace existing orders.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Execution Tracking&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Processes order updates, partial fills, completed fills, and cancellations, then reconciles the internal state with the actual account state.&lt;/p&gt;

&lt;p&gt;For example, the strategy might calculate a bid of $0.47. But if the current best ask has moved to $0.46, submitting that bid could execute immediately instead of resting passively.&lt;/p&gt;

&lt;p&gt;The order manager needs to detect this situation and follow the strategy's execution policy.&lt;/p&gt;

&lt;p&gt;Likewise, if inventory has reached its maximum, the risk manager must block additional buy orders even if their prices are valid.&lt;/p&gt;

&lt;p&gt;This separation is especially important when moving from a local Python experiment to a live trading system.&lt;/p&gt;
&lt;h2&gt;
  
  
  10. Test the Strategy Before Live Trading
&lt;/h2&gt;

&lt;p&gt;Before connecting the strategy to an order manager, test its behavior independently.&lt;/p&gt;

&lt;p&gt;Install pytest:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;pytest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Create &lt;code&gt;test_strategy.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;calculate_quotes&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_zero_inventory_produces_symmetric_quotes&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;quote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_quotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;midpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.50&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;half_spread&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.02&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;inventory_skew&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bid&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.48&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ask&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.52&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_positive_inventory_shifts_quotes_down&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;neutral&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_quotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;midpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.50&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;half_spread&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.02&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;inventory_skew&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;long_position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_quotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;midpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.50&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;half_spread&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.02&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;100&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;inventory_skew&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;long_position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bid&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;neutral&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bid&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;long_position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ask&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;neutral&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ask&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_negative_inventory_shifts_quotes_up&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;neutral&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_quotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;midpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.50&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;half_spread&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.02&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;inventory_skew&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;short_position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_quotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;midpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.50&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;half_spread&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.02&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;inventory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-100&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;inventory_skew&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;short_position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bid&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;neutral&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bid&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;short_position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ask&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;neutral&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ask&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Run the tests:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pytest &lt;span class="nt"&gt;-q&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;These tests verify three basic properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero inventory produces symmetric quotes around the midpoint.&lt;/li&gt;
&lt;li&gt;Positive inventory shifts both quotes downward.&lt;/li&gt;
&lt;li&gt;Negative inventory shifts both quotes upward.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should also test invalid inputs, extreme inventory, price boundaries, and cases where clamping would make the bid equal to or greater than the ask.&lt;/p&gt;

&lt;p&gt;Unit tests verify that the function behaves as intended. They do not demonstrate that the strategy is profitable.&lt;/p&gt;
&lt;h2&gt;
  
  
  11. How Can We Evaluate Market-Making Performance?
&lt;/h2&gt;

&lt;p&gt;Once the pricing function passes its tests, the next step is to replay recorded order book data and simulate order execution.&lt;/p&gt;

&lt;p&gt;A useful simulation should account for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Orders that never fill&lt;/li&gt;
&lt;li&gt;Partial fills&lt;/li&gt;
&lt;li&gt;Queue priority&lt;/li&gt;
&lt;li&gt;Cancellation delays&lt;/li&gt;
&lt;li&gt;Price movements after a fill&lt;/li&gt;
&lt;li&gt;Trading fees and other applicable costs&lt;/li&gt;
&lt;li&gt;Inventory accumulation&lt;/li&gt;
&lt;li&gt;The cost of reducing or closing a position&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One important risk is &lt;strong&gt;adverse selection&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Imagine the bot buys YES at $0.48. A moment later, new information causes the token's fair value to fall to $0.42.&lt;/p&gt;

&lt;p&gt;The bot may have earned the apparent spread on paper in other trades, but this particular fill creates an unrealized loss.&lt;/p&gt;

&lt;p&gt;That is why spread size alone is not a sufficient measure of performance.&lt;/p&gt;

&lt;p&gt;Track metrics such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Realized and unrealized P&amp;amp;L&lt;/li&gt;
&lt;li&gt;Inventory over time&lt;/li&gt;
&lt;li&gt;Fill rate&lt;/li&gt;
&lt;li&gt;Average spread captured&lt;/li&gt;
&lt;li&gt;Fees and execution costs&lt;/li&gt;
&lt;li&gt;Adverse price movement after fills&lt;/li&gt;
&lt;li&gt;Maximum inventory exposure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A credible evaluation should also account for the outcome of prediction-market positions at resolution. For a YES token, the final payout depends on the market's resolution rules, not simply on the last quoted price.&lt;/p&gt;

&lt;p&gt;Use historical replay and paper trading to identify problems before considering live deployment.&lt;/p&gt;
&lt;h2&gt;
  
  
  12. What We've Built
&lt;/h2&gt;

&lt;p&gt;In this lesson, we moved from observing the order book to calculating inventory-aware quotes.&lt;/p&gt;

&lt;p&gt;We implemented a small Python strategy that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Calculates bid and ask prices from a midpoint&lt;/li&gt;
&lt;li&gt;Applies an inventory adjustment&lt;/li&gt;
&lt;li&gt;Uses &lt;code&gt;Decimal&lt;/code&gt; for price calculations&lt;/li&gt;
&lt;li&gt;Checks basic price bounds&lt;/li&gt;
&lt;li&gt;Can be tested without connecting to a live exchange&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also explored order sizing, market validation, risk management, execution architecture, and testing.&lt;/p&gt;

&lt;p&gt;The key lesson is that &lt;strong&gt;calculating a price is only one part of building a market maker&lt;/strong&gt;. A reliable system must also manage inventory, validate orders, track execution, and respond to changing market conditions.&lt;/p&gt;
&lt;h2&gt;
  
  
  What's Next? Day 5 — Automated Quoting and Order Management
&lt;/h2&gt;

&lt;p&gt;In Day 5, we'll move from calculating candidate quotes to managing orders.&lt;/p&gt;

&lt;p&gt;We'll explore how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Submit limit orders through Polymarket's supported trading interface&lt;/li&gt;
&lt;li&gt;Track open orders and their status&lt;/li&gt;
&lt;li&gt;Cancel or replace outdated quotes&lt;/li&gt;
&lt;li&gt;Handle partial fills and uncertain API responses&lt;/li&gt;
&lt;li&gt;Avoid duplicate orders&lt;/li&gt;
&lt;li&gt;Reconcile internal state with actual account state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is to connect our strategy to an order manager without losing control of inventory or execution state.&lt;/p&gt;
&lt;h2&gt;
  
  
  Follow the Project
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub repository:&lt;/strong&gt; [Polymarket Trading Bot — Python]&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Benj4minCup" rel="noopener noreferrer"&gt;
        Benj4minCup
      &lt;/a&gt; / &lt;a href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;
        Polymarket-Trading-Bot-python
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Polymarket Trading Bot  Twap Bot polymarket Arbitrage Bot
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Polymarket Trading bot system&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;An open-source and Strong Strategy collection of Polymarket trading bot and Polymarket arbitrage bot and Polymarket TWAP trading bot in Python for high-performance automated trading on polymarket crypto 5min and 15min markets.&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/33036584/633381478-71b65c58-00d2-4bbe-8b6d-8ed6fc9812e4.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3OTMxMTc2MzAsIm5iZiI6MTc5MzExNzMzMCwicGF0aCI6Ii8zMzAzNjU4NC82MzMzODE0NzgtNzFiNjVjNTgtMDBkMi00YmJlLThiNmQtOGVkNmZjOTgxMmU0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjEwMjclMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYxMDI3VDE2MDg1MFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWYwYmJkN2I1NTQ2ODMxNzU3ZGEyNGU3Y2NlOWExNzkyY2UxNWNjMjg2NzhjMzI4N2Q3ZWFkZWRiNWU0NzIzNDAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.i1BcxAiRdZhFvGhFbLqpHO_q8xUCoYYhY6IM9c-ntzU"&gt;&lt;img width="1536" height="1024" alt="Polymarket-benjamincup-bot-dashboard" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F33036584%2F633381478-71b65c58-00d2-4bbe-8b6d-8ed6fc9812e4.png%3Fjwt%3DeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3OTMxMTc2MzAsIm5iZiI6MTc5MzExNzMzMCwicGF0aCI6Ii8zMzAzNjU4NC82MzMzODE0NzgtNzFiNjVjNTgtMDBkMi00YmJlLThiNmQtOGVkNmZjOTgxMmU0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjEwMjclMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYxMDI3VDE2MDg1MFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWYwYmJkN2I1NTQ2ODMxNzU3ZGEyNGU3Y2NlOWExNzkyY2UxNWNjMjg2NzhjMzI4N2Q3ZWFkZWRiNWU0NzIzNDAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.i1BcxAiRdZhFvGhFbLqpHO_q8xUCoYYhY6IM9c-ntzU" class="js-gh-image-fallback"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This repository is primarily intended for educational and research purposes. It includes strategy concepts, implementation approaches, and selected performance screenshots to help developers understand how different automated trading strategies can be designed and tested.&lt;/p&gt;

&lt;p&gt;The repository does not provide a complete production-ready trading bot source code. Instead, it provides strategy descriptions and research materials that you can use as a foundation for developing your own system.&lt;/p&gt;

&lt;p&gt;If you are interested in building a Polymarket Trading Bot, you can follow my tutorials and use the concepts in this repository to develop your own implementation.&lt;/p&gt;

&lt;p&gt;For users who prefer a ready-to-deploy solution or require custom strategy development, commercial bot development and customization are also available.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;YouTube :&lt;/strong&gt; [Watch the Polymarket trading bot tutorial]&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/UCF7MA1Kekk" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Telegram:&lt;/strong&gt; [Join the discussion]&lt;br&gt;
&lt;a href="https://telegram.me/BenjaminCup" rel="noopener noreferrer"&gt;https://telegram.me/BenjaminCup&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Follow the seven-day series as we build a Polymarket market maker bot, from understanding prediction markets to implementing pricing logic, order management, risk controls, and deployment.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclaimer: This tutorial is for educational purposes only and is not financial advice. Market making involves financial risk. The example strategy has not been demonstrated to be profitable. Test thoroughly with historical data and paper trading before considering live execution.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>polymarket</category>
      <category>python</category>
      <category>tutorial</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Polymarket Trading Bot: Build a Market Maker Bot in Python- Project Setup and API Integration</title>
      <dc:creator>Benjamin-Cup</dc:creator>
      <pubDate>Wed, 21 Oct 2026 16:20:23 +0000</pubDate>
      <link>https://dev.to/benjamin_cup/polymarket-trading-bot-build-a-market-maker-bot-in-python-project-setup-and-api-integration-5c2f</link>
      <guid>https://dev.to/benjamin_cup/polymarket-trading-bot-build-a-market-maker-bot-in-python-project-setup-and-api-integration-5c2f</guid>
      <description>&lt;p&gt;&lt;em&gt;Day 3 of 7: Building a Polymarket Market Maker Bot From Zero to Complete&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the first two parts of this series, we explored what a Polymarket market maker bot is and how the Polymarket order book works.&lt;/p&gt;

&lt;p&gt;We covered YES and NO outcome tokens, bid-ask spreads, market depth, limit orders, and the risks of providing liquidity.&lt;/p&gt;

&lt;p&gt;Now, let's start building.&lt;/p&gt;

&lt;p&gt;In this tutorial, we'll set up a Python project, connect to Polymarket's public market data API, discover available markets, retrieve outcome asset identifiers, and inspect an order book.&lt;/p&gt;

&lt;p&gt;By the end, you'll have the foundation of a Python market maker bot that can read market data and calculate basic pricing metrics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; This tutorial is read-only. It does not submit orders, spend funds, or require a private key.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We'll Build
&lt;/h2&gt;

&lt;p&gt;Our first version will perform five tasks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connect to Polymarket's public API.&lt;/li&gt;
&lt;li&gt;Discover available markets.&lt;/li&gt;
&lt;li&gt;Identify a market's YES and NO assets.&lt;/li&gt;
&lt;li&gt;Retrieve the order book for a selected asset.&lt;/li&gt;
&lt;li&gt;Calculate the best bid, best ask, spread, and midpoint.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The data flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Polymarket Market Data
        |
        v
   Market Discovery
        |
        v
    Select a Market
        |
        v
  Identify YES / NO Assets
        |
        v
    Fetch Order Book
        |
        v
 Calculate Spread &amp;amp; Midpoint
        |
        v
      Print Results
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a small program, but it establishes an important component of every trading bot: the &lt;strong&gt;market data layer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz5w025xyd3one3fbi00y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz5w025xyd3one3fbi00y.png" alt="polymarket trading bot" width="800" height="731"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A production market maker would extend this foundation with real-time data subscriptions, strategy logic, order management, inventory tracking, risk controls, and monitoring.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Choose the Python SDK
&lt;/h2&gt;

&lt;p&gt;Polymarket provides developer interfaces for market discovery, order books, pricing, and trading.&lt;/p&gt;

&lt;p&gt;For this tutorial, we'll use the unified Python SDK identified in the project references:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Official repository:&lt;/strong&gt; &lt;a href="https://github.com/Polymarket/py-sdk" rel="noopener noreferrer"&gt;Polymarket Python SDK&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The package used in the examples is &lt;code&gt;polymarket-client&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The SDK is intended to provide access to market information and other Polymarket workflows. Public market-data access does not require you to configure trading credentials for this read-only exercise.&lt;/p&gt;

&lt;p&gt;Before installing it, check the repository's current installation instructions and examples. SDK interfaces can change, and code written for an older client may not work with the current version.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Set Up Your Development Environment
&lt;/h2&gt;

&lt;p&gt;You can follow this tutorial on Windows, macOS, or Linux.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On some systems, use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a project directory
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;polymarket-market-maker
&lt;span class="nb"&gt;cd &lt;/span&gt;polymarket-market-maker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a virtual environment
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Activate it on Windows PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;venv&lt;/span&gt;&lt;span class="n"&gt;\Scripts\Activate.ps1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On macOS or Linux:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install the SDK
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--upgrade&lt;/span&gt; pip
pip &lt;span class="nb"&gt;install &lt;/span&gt;polymarket-client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the import:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"from polymarket import PublicClient; print('SDK import successful')"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the import fails, check the SDK's current Python requirements and installation instructions before proceeding.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Create a Clean Project Structure
&lt;/h2&gt;

&lt;p&gt;A common beginner mistake is putting market discovery, pricing calculations, and trading logic into one large Python file.&lt;/p&gt;

&lt;p&gt;Let's separate responsibilities from the beginning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;polymarket-market-maker/
├── src/
│   └── polymarket_mm/
│       ├── __init__.py
│       ├── market_data.py
│       ├── orderbook.py
│       ├── pricing.py
│       └── main.py
├── tests/
├── .gitignore
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each module has a specific responsibility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;market_data.py&lt;/code&gt; — discovers markets and retrieves market information.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;orderbook.py&lt;/code&gt; — retrieves and inspects order book levels.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pricing.py&lt;/code&gt; — calculates spread and midpoint.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;main.py&lt;/code&gt; — connects the modules and runs the example.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tests/&lt;/code&gt; — contains tests for pricing calculations and other logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This structure is intentionally simple. We don't need a complex architecture before our first API request works.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Discover Markets Through the SDK
&lt;/h2&gt;

&lt;p&gt;Before inspecting an order book, the bot needs to discover which markets are available.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;src/polymarket_mm/market_data.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;polymarket&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PublicClient&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;list_markets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return a page of markets from Polymarket.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;PublicClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list_markets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;closed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;page_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first_page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;markets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list_markets&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;market&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;markets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;question&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;market&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;slug&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;market&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;market_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;market&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the module from your project root.&lt;/p&gt;

&lt;p&gt;On macOS or Linux:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;PYTHONPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;src python &lt;span class="nt"&gt;-m&lt;/span&gt; polymarket_mm.market_data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Windows PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;PYTHONPATH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;polymarket_mm.market_data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The program requests a page of markets and prints basic information about each result.&lt;/p&gt;

&lt;p&gt;One important detail: &lt;code&gt;closed=False&lt;/code&gt; does not necessarily mean a market is currently accepting orders. A production bot should separately validate market status, trading permissions, and the availability of a usable order book.&lt;/p&gt;

&lt;p&gt;For the current implementation, consult the &lt;a href="https://github.com/Polymarket/py-sdk/blob/main/examples/list_markets.py" rel="noopener noreferrer"&gt;official market discovery example&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Understand Market IDs and Asset IDs
&lt;/h2&gt;

&lt;p&gt;A market and a tradable asset are not the same thing.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;market&lt;/strong&gt; represents an event or question.&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;asset identifier&lt;/strong&gt; identifies a tradable outcome or position associated with that market.&lt;/p&gt;

&lt;p&gt;For a conventional binary market, there are typically YES and NO outcomes. However, market infrastructure can evolve, so avoid assuming every market exposes its tradable identifiers in exactly the same format.&lt;/p&gt;

&lt;p&gt;The SDK's market model may expose a token ID, position ID, or another identifier depending on the market representation.&lt;/p&gt;

&lt;p&gt;The key principle is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use the current SDK's market model and official examples instead of extracting identifiers from URLs or relying on undocumented raw JSON structures.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can review the SDK's &lt;a href="https://github.com/Polymarket/py-sdk/blob/main/examples/lib/markets.py" rel="noopener noreferrer"&gt;market helper examples&lt;/a&gt; to understand how outcome identifiers are accessed.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Retrieve an Order Book
&lt;/h2&gt;

&lt;p&gt;Now let's inspect an actual market.&lt;/p&gt;

&lt;p&gt;The following example searches a limited page of open markets until it finds one with a usable YES asset identifier. It then requests the corresponding order book.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;src/polymarket_mm/orderbook.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;polymarket&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PublicClient&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inspect_first_available_market&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;PublicClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;markets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list_markets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;closed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;page_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first_page&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;market&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;markets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Conventional binary-market example.
&lt;/span&gt;            &lt;span class="c1"&gt;# Check the SDK model for your market version.
&lt;/span&gt;            &lt;span class="n"&gt;yes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;market&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;outcomes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yes&lt;/span&gt;

            &lt;span class="n"&gt;asset_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;yes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token_id&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;yes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position_id&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;asset_id&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;

            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;book&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_order_book&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;asset_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;asset_id&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Skipping market &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;market&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;could not retrieve its book: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bids&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;market&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;asset_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;

    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No market with a usable YES order book was found. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Try again or refine market discovery.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;market&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;asset_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inspect_first_available_market&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Market:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;market&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Market ID:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;market&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Asset ID:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;asset_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Number of bids:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bids&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Number of asks:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asks&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Top bids:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)[:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Price:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Size:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Top asks:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)[:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Price:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Size:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;PYTHONPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;src python &lt;span class="nt"&gt;-m&lt;/span&gt; polymarket_mm.orderbook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Windows PowerShell, use the &lt;code&gt;PYTHONPATH&lt;/code&gt; command from the previous section.&lt;/p&gt;

&lt;p&gt;The program prints the market question, asset identifier, number of bid and ask levels, and the five best levels on each side.&lt;/p&gt;

&lt;p&gt;A few things to remember:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The best bid is the highest available buy price.&lt;/li&gt;
&lt;li&gt;The best ask is the lowest available sell price.&lt;/li&gt;
&lt;li&gt;The size indicates the quantity available at a price level.&lt;/li&gt;
&lt;li&gt;An empty order book does not provide enough information to calculate both sides of the spread.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code is an educational starting point, not a guarantee that every market returned by the API will expose these exact fields. Verify the current SDK model before running it.&lt;/p&gt;

&lt;p&gt;For another reference, see the &lt;a href="https://github.com/Polymarket/py-sdk/blob/main/examples/market_prices.py" rel="noopener noreferrer"&gt;official market prices example&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Calculate the Spread and Midpoint
&lt;/h2&gt;

&lt;p&gt;Once we have the order book, we can calculate two basic market metrics.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bid-ask spread
&lt;/h3&gt;

&lt;p&gt;The spread measures the difference between the best ask and the best bid.&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
\text{Spread} = \text{Best Ask} - \text{Best Bid}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;For example, suppose the best bid is &lt;code&gt;$0.48&lt;/code&gt; and the best ask is &lt;code&gt;$0.52&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The spread is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0.52 - 0.48 = 0.04
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The spread is four cents per share.&lt;/p&gt;

&lt;h3&gt;
  
  
  Midpoint
&lt;/h3&gt;

&lt;p&gt;The midpoint is the average of the best bid and best ask.&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
\text{Midpoint} =&lt;br&gt;
\frac{\text{Best Bid}+\text{Best Ask}}{2}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Using the same example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(0.48 + 0.52) / 2 = 0.50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The midpoint is &lt;code&gt;$0.50&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; The midpoint is a reference price, not a guaranteed execution price. A market order or limit order may execute at a different price depending on liquidity and market conditions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implement the calculations
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;src/polymarket_mm/pricing.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_book_metrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;asks&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Calculate basic metrics from order book levels.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;best_bid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bids&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;best_ask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;asks&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;best_bid&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;best_ask&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;best_bid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;best_bid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;best_ask&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;best_ask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spread&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;midpoint&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;best_bid&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;best_ask&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The book appears crossed; inspect the data &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;and API response before using it.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;best_bid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;best_bid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;best_ask&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;best_ask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spread&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;best_ask&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;best_bid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;midpoint&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;best_bid&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;best_ask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can import this function into the order book example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;polymarket_mm.pricing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;calculate_book_metrics&lt;/span&gt;

&lt;span class="n"&gt;metrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_book_metrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Book metrics:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For financial calculations and order construction, prefer &lt;code&gt;Decimal&lt;/code&gt; or the SDK's decimal-compatible types over binary floating-point arithmetic.&lt;/p&gt;

&lt;p&gt;The example uses &lt;code&gt;float&lt;/code&gt; for simplicity and educational display.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Add Error Handling and Logging
&lt;/h2&gt;

&lt;p&gt;Real-world API requests can fail.&lt;/p&gt;

&lt;p&gt;Common causes include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Network timeouts.&lt;/li&gt;
&lt;li&gt;Rate limits.&lt;/li&gt;
&lt;li&gt;Invalid asset identifiers.&lt;/li&gt;
&lt;li&gt;Temporary service errors.&lt;/li&gt;
&lt;li&gt;Disconnected WebSocket connections.&lt;/li&gt;
&lt;li&gt;Missing or stale market data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Different errors require different responses.&lt;/p&gt;

&lt;p&gt;A timeout may justify a controlled retry. A rate-limit response should trigger appropriate backoff. An invalid identifier may indicate a market-selection problem.&lt;/p&gt;

&lt;p&gt;Stale data is particularly important for a market maker. If the order book is outdated, the bot should not continue generating quotes as if the information were current.&lt;/p&gt;

&lt;p&gt;Start with Python's standard logging module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;

&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%(asctime)s %(levelname)s %(message)s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Market data module started&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the project grows, structured logs will help investigate market data updates, order submissions, fills, cancellations, and risk-limit events.&lt;/p&gt;

&lt;p&gt;Avoid infinite retry loops. A robust bot should stop making trading decisions when its data cannot be trusted.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Why We Are Not Placing Orders Yet
&lt;/h2&gt;

&lt;p&gt;At this stage, our program can retrieve market information, but it is not yet a market maker.&lt;/p&gt;

&lt;p&gt;It does not know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What prices it should quote.&lt;/li&gt;
&lt;li&gt;How large its orders should be.&lt;/li&gt;
&lt;li&gt;When it should cancel or replace orders.&lt;/li&gt;
&lt;li&gt;How to manage inventory.&lt;/li&gt;
&lt;li&gt;How to control exposure and capital usage.&lt;/li&gt;
&lt;li&gt;How to reconcile partial fills and failed requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Adding live order placement before implementing these components would be premature.&lt;/p&gt;

&lt;p&gt;A safer development sequence is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retrieve market data reliably.&lt;/li&gt;
&lt;li&gt;Calculate candidate quotes.&lt;/li&gt;
&lt;li&gt;Validate quotes against price and risk limits.&lt;/li&gt;
&lt;li&gt;Simulate decisions using recorded or live market data.&lt;/li&gt;
&lt;li&gt;Implement order lifecycle management.&lt;/li&gt;
&lt;li&gt;Test failures, cancellations, and partial fills.&lt;/li&gt;
&lt;li&gt;Consider controlled live testing only after sufficient validation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Separating market data from order execution makes the bot easier to test and reduces the risk of an early coding mistake spending real funds.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. What We Built Today
&lt;/h2&gt;

&lt;p&gt;By completing Day 3, we have established the initial market data layer.&lt;/p&gt;

&lt;p&gt;We now have a foundation for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installing and importing the Python SDK.&lt;/li&gt;
&lt;li&gt;Discovering open markets.&lt;/li&gt;
&lt;li&gt;Identifying a usable YES asset identifier.&lt;/li&gt;
&lt;li&gt;Retrieving an order book.&lt;/li&gt;
&lt;li&gt;Inspecting bid and ask levels.&lt;/li&gt;
&lt;li&gt;Calculating spread and midpoint metrics.&lt;/li&gt;
&lt;li&gt;Recognizing the importance of API errors and stale data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the first step toward a more complete market maker bot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Day 4: Design the Market-Making Strategy
&lt;/h2&gt;

&lt;p&gt;In Day 4, we'll move from observing the market to generating candidate quotes.&lt;/p&gt;

&lt;p&gt;We'll explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to select a reference price.&lt;/li&gt;
&lt;li&gt;How to calculate bid and ask quotes.&lt;/li&gt;
&lt;li&gt;How to set a target spread.&lt;/li&gt;
&lt;li&gt;How to choose order sizes.&lt;/li&gt;
&lt;li&gt;How to adjust quotes based on inventory.&lt;/li&gt;
&lt;li&gt;Why fixed-distance-from-midpoint strategies can perform poorly during rapid price movements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The objective is to build a strategy layer that can be tested before connecting it to live order execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow the Project
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub repository:&lt;/strong&gt; &lt;a href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;Polymarket Trading Bot in Python&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;YouTube tutorial:&lt;/strong&gt; &lt;a href="https://www.youtube.com/watch?v=UCF7MA1Kekk" rel="noopener noreferrer"&gt;Watch the video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contact and discussion:&lt;/strong&gt; &lt;a href="https://telegram.me/BenjaminCup" rel="noopener noreferrer"&gt;Telegram — BenjaminCup&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Follow the series as we build a Polymarket market maker bot from the fundamentals toward a complete Python implementation.&lt;/p&gt;

&lt;h1&gt;
  
  
  Python #Polymarket #TradingBot #AlgoTrading #Crypto
&lt;/h1&gt;

</description>
      <category>polymarket</category>
      <category>python</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Polymarket Trading Bot: How the Order Book Works: YES/NO Tokens, Bid-Ask Spreads, and Liquidity</title>
      <dc:creator>Benjamin-Cup</dc:creator>
      <pubDate>Tue, 20 Oct 2026 13:50:04 +0000</pubDate>
      <link>https://dev.to/benjamin_cup/polymarket-trading-bot-how-the-order-book-works-yesno-tokens-bid-ask-spreads-and-liquidity-169d</link>
      <guid>https://dev.to/benjamin_cup/polymarket-trading-bot-how-the-order-book-works-yesno-tokens-bid-ask-spreads-and-liquidity-169d</guid>
      <description>&lt;p&gt;&lt;em&gt;Day 2 of 7: Building a Polymarket Market Maker Bot From Zero to Complete&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Before building a market-making bot, you need to understand how a trading market actually works.&lt;/p&gt;

&lt;p&gt;In the first article of this series, we explored what a Polymarket market maker bot is, how bid-ask spreads work, and why automated liquidity provision can be an interesting trading strategy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqut32uvgfwm1xs2bwe4d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqut32uvgfwm1xs2bwe4d.png" alt="Polymarket Trading Bot" width="800" height="731"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today, we're going one step deeper: &lt;strong&gt;understanding the order book.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The order book tells your bot what buyers are willing to pay, what sellers are asking for, and how much liquidity is available at different prices.&lt;/p&gt;

&lt;p&gt;Without this information, a bot might place poor orders, accumulate unwanted positions, or fail to react to changing market conditions.&lt;/p&gt;

&lt;p&gt;In this tutorial, we'll explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How an order book works&lt;/li&gt;
&lt;li&gt;How YES and NO tokens are traded&lt;/li&gt;
&lt;li&gt;How to calculate the spread and midpoint&lt;/li&gt;
&lt;li&gt;Why a wide spread doesn't guarantee profit&lt;/li&gt;
&lt;li&gt;How to measure order book liquidity&lt;/li&gt;
&lt;li&gt;How limit orders work&lt;/li&gt;
&lt;li&gt;What market data a Python trading bot needs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. What Is an Order Book?
&lt;/h2&gt;

&lt;p&gt;An &lt;strong&gt;order book&lt;/strong&gt; is a list of outstanding buy and sell orders for a particular token.&lt;/p&gt;

&lt;p&gt;It has two main sides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bids:&lt;/strong&gt; Prices buyers are willing to pay.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asks:&lt;/strong&gt; Prices sellers are willing to accept.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Imagine that your bot is analyzing a Polymarket YES token. The order book currently looks like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Side&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Available Size&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ask&lt;/td&gt;
&lt;td&gt;$0.54&lt;/td&gt;
&lt;td&gt;100 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ask&lt;/td&gt;
&lt;td&gt;$0.53&lt;/td&gt;
&lt;td&gt;200 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ask&lt;/td&gt;
&lt;td&gt;$0.52&lt;/td&gt;
&lt;td&gt;150 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bid&lt;/td&gt;
&lt;td&gt;$0.49&lt;/td&gt;
&lt;td&gt;100 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bid&lt;/td&gt;
&lt;td&gt;$0.48&lt;/td&gt;
&lt;td&gt;250 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bid&lt;/td&gt;
&lt;td&gt;$0.47&lt;/td&gt;
&lt;td&gt;300 tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;strong&gt;best bid&lt;/strong&gt; is $0.49 because it is the highest available buy price.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;best ask&lt;/strong&gt; is $0.52 because it is the lowest available sell price.&lt;/p&gt;

&lt;p&gt;The difference between these prices is called the bid-ask spread.&lt;/p&gt;

&lt;h3&gt;
  
  
  Calculating the spread
&lt;/h3&gt;

&lt;p&gt;The formula is simple:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Spread = Best Ask - Best Bid&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Using our example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$0.52 - $0.49 = $0.03&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The spread is &lt;strong&gt;$0.03 per token&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For a market-making bot, this information helps determine where to place buy and sell orders.&lt;/p&gt;

&lt;p&gt;However, the order book only shows available orders at a particular moment. Orders can be canceled, executed, or replaced as the market changes.&lt;/p&gt;

&lt;p&gt;Your bot must continuously account for these changes rather than assume that displayed prices will remain available.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Understanding YES and NO Tokens
&lt;/h2&gt;

&lt;p&gt;Polymarket markets commonly offer two complementary outcomes: YES and NO.&lt;/p&gt;

&lt;p&gt;Consider this question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will Bitcoin be above $100,000 at the specified time?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A trader can buy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;YES&lt;/strong&gt; if they believe the condition will be satisfied.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NO&lt;/strong&gt; if they believe the condition will not be satisfied.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a binary market with standard settlement, one winning outcome token pays $1 per share when the market resolves, while the losing token becomes worthless.&lt;/p&gt;

&lt;p&gt;Here is an illustrative order book:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Outcome&lt;/th&gt;
&lt;th&gt;Best Bid&lt;/th&gt;
&lt;th&gt;Best Ask&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;td&gt;$0.59&lt;/td&gt;
&lt;td&gt;$0.62&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NO&lt;/td&gt;
&lt;td&gt;$0.38&lt;/td&gt;
&lt;td&gt;$0.41&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These prices reflect supply and demand for each token. They are not guaranteed probabilities or guaranteed execution prices.&lt;/p&gt;

&lt;h3&gt;
  
  
  An important detail for developers
&lt;/h3&gt;

&lt;p&gt;YES and NO are separate tradable tokens with their own order books.&lt;/p&gt;

&lt;p&gt;You should not assume that their best bid and ask prices always add up to exactly $1.&lt;/p&gt;

&lt;p&gt;Differences can arise because of spreads, available liquidity, and the fact that the two books may not contain executable orders at corresponding prices and sizes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical takeaway:&lt;/strong&gt; Retrieve the actual order book for the token your bot intends to trade. Don't assume you can calculate an executable price simply by subtracting the other token's price from $1.&lt;/p&gt;

&lt;p&gt;Official reference: &lt;a href="https://docs.polymarket.com/faq" rel="noopener noreferrer"&gt;Polymarket FAQ&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. What Is the Midpoint?
&lt;/h2&gt;

&lt;p&gt;The midpoint is the average of the best bid and best ask.&lt;/p&gt;

&lt;p&gt;It provides a useful reference for understanding the current market.&lt;/p&gt;

&lt;p&gt;The formula is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Midpoint = (Best Bid + Best Ask) / 2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Suppose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Best bid: $0.49&lt;/li&gt;
&lt;li&gt;Best ask: $0.52&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;($0.49 + $0.52) / 2 = $0.505&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The midpoint is &lt;strong&gt;$0.505&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But here's something important: the midpoint is not necessarily an executable price.&lt;/p&gt;

&lt;p&gt;If the best bid is $0.49 and the best ask is $0.52, you cannot assume that you can immediately buy or sell at $0.505.&lt;/p&gt;

&lt;p&gt;For a market-making bot, the midpoint can serve as a starting reference for calculating quotes. A more advanced strategy can adjust that reference based on inventory, volatility, and other market conditions.&lt;/p&gt;

&lt;p&gt;Polymarket's displayed market price may use the order book midpoint or the last traded price when the spread exceeds its specified threshold. Therefore, a displayed probability should not automatically be treated as an executable price.&lt;/p&gt;

&lt;p&gt;Further reading: &lt;a href="https://help.polymarket.com/en/articles/13364488-how-are-prices-calculated" rel="noopener noreferrer"&gt;How Are Prices Calculated?&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Spread Is Not the Same as Profit
&lt;/h2&gt;

&lt;p&gt;This is one of the most important lessons in market making.&lt;/p&gt;

&lt;p&gt;A wide spread may look attractive, but it doesn't automatically create a profitable trading opportunity.&lt;/p&gt;

&lt;p&gt;Let's examine two scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario A: Both orders execute
&lt;/h3&gt;

&lt;p&gt;Your bot buys 100 YES tokens at $0.48.&lt;/p&gt;

&lt;p&gt;The total purchase cost is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;100 × $0.48 = $48&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Your bot then sells 100 tokens at $0.52.&lt;/p&gt;

&lt;p&gt;The gross difference is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;100 × ($0.52 - $0.48) = $4&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If both orders execute as expected, the bot captures a gross difference of $4 before fees and other costs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario B: The market moves against your bot
&lt;/h3&gt;

&lt;p&gt;Now imagine that the buy order executes, but the market price falls immediately afterward.&lt;/p&gt;

&lt;p&gt;Your bot still owns 100 YES tokens purchased at $0.48 each.&lt;/p&gt;

&lt;p&gt;However, buyers are now offering only $0.43 per token.&lt;/p&gt;

&lt;p&gt;The indicative value of your position at that bid is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;100 × $0.43 = $43&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Your original purchase cost was $48.&lt;/p&gt;

&lt;p&gt;The difference is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$43 - $48 = -$5&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Your position has an indicative loss of $5 before other costs.&lt;/p&gt;

&lt;p&gt;The sell order at $0.52 may never execute.&lt;/p&gt;

&lt;p&gt;This is why a market-making strategy must evaluate more than the displayed spread.&lt;/p&gt;

&lt;p&gt;A reliable bot should track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Completed round-trip trades&lt;/li&gt;
&lt;li&gt;Current inventory and its value&lt;/li&gt;
&lt;li&gt;Open and partially filled orders&lt;/li&gt;
&lt;li&gt;Execution costs and applicable incentives&lt;/li&gt;
&lt;li&gt;Price movements after orders execute&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The goal isn't simply to find a wide spread. It's to quote prices that offer a reasonable expected return after accounting for execution and inventory risk.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. What Is Order Book Depth?
&lt;/h2&gt;

&lt;p&gt;Order book depth describes the quantity of buy and sell orders available at different price levels.&lt;/p&gt;

&lt;p&gt;Let's compare two hypothetical markets:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Market A&lt;/th&gt;
&lt;th&gt;Market B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Best bid&lt;/td&gt;
&lt;td&gt;$0.49&lt;/td&gt;
&lt;td&gt;$0.45&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best ask&lt;/td&gt;
&lt;td&gt;$0.51&lt;/td&gt;
&lt;td&gt;$0.55&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bid size at best price&lt;/td&gt;
&lt;td&gt;1,000&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ask size at best price&lt;/td&gt;
&lt;td&gt;1,200&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spread&lt;/td&gt;
&lt;td&gt;$0.02&lt;/td&gt;
&lt;td&gt;$0.10&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Market A has a tighter spread and more displayed liquidity at the best prices.&lt;/p&gt;

&lt;p&gt;Market B has a spread five times wider, but much less quantity available at its best bid and ask.&lt;/p&gt;

&lt;p&gt;A beginner might conclude that Market B is the better opportunity.&lt;/p&gt;

&lt;p&gt;That conclusion would be premature.&lt;/p&gt;

&lt;p&gt;A wide spread might indicate low competition, but it can also reflect uncertainty, low trading activity, or difficulty finding counterparties.&lt;/p&gt;

&lt;p&gt;If your bot places a large order in a market with limited depth, it may struggle to execute at the expected price or exit its position.&lt;/p&gt;

&lt;p&gt;Also remember that displayed orders can be canceled before your order executes. Displayed depth is not guaranteed liquidity.&lt;/p&gt;

&lt;p&gt;For a market maker, &lt;strong&gt;spread and depth must be evaluated together&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Further reading: &lt;a href="https://help.polymarket.com/en/articles/13364481-does-polymarket-have-trading-limits" rel="noopener noreferrer"&gt;Polymarket Trading Limits and Liquidity&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. How Does a Limit Order Work?
&lt;/h2&gt;

&lt;p&gt;A limit order specifies the price at which you're willing to trade, subject to the exchange's matching rules.&lt;/p&gt;

&lt;p&gt;Suppose the best ask for a YES token is $0.52.&lt;/p&gt;

&lt;p&gt;Your bot submits a buy limit order at $0.49.&lt;/p&gt;

&lt;p&gt;The order may remain in the order book until a compatible sell order arrives, unless it is canceled or otherwise expires.&lt;/p&gt;

&lt;p&gt;But what happens if your bot submits a buy limit order at a price that crosses the available asks?&lt;/p&gt;

&lt;p&gt;Depending on the order type and instructions, it may execute immediately against existing sell orders.&lt;/p&gt;

&lt;p&gt;For market-making strategies, developers often want resting orders that add liquidity instead of immediately consuming existing liquidity.&lt;/p&gt;

&lt;p&gt;Post-only instructions can help when supported. Their precise behavior depends on the API and order instructions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understand the order lifecycle
&lt;/h3&gt;

&lt;p&gt;Your bot must distinguish between several different events:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Submitting an order&lt;/li&gt;
&lt;li&gt;Having the order accepted&lt;/li&gt;
&lt;li&gt;Having the order resting in the order book&lt;/li&gt;
&lt;li&gt;Receiving a partial fill&lt;/li&gt;
&lt;li&gt;Receiving a complete fill&lt;/li&gt;
&lt;li&gt;Successfully canceling the order&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These states are not interchangeable.&lt;/p&gt;

&lt;p&gt;For example, a successful API response confirming that an order was submitted does not necessarily mean a trade occurred.&lt;/p&gt;

&lt;p&gt;If your bot assumes that every submitted order has executed, its internal balance and inventory calculations can become incorrect.&lt;/p&gt;

&lt;p&gt;Reliable order-state tracking is therefore a fundamental part of the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. What Market Data Does a Polymarket Bot Need?
&lt;/h2&gt;

&lt;p&gt;Now let's connect these concepts to the actual software architecture.&lt;/p&gt;

&lt;p&gt;Before placing an order, a market-making bot needs several categories of information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Market information
&lt;/h3&gt;

&lt;p&gt;The bot needs to identify the market it wants to trade and retrieve the relevant token identifiers.&lt;/p&gt;

&lt;p&gt;It should also understand the market's outcome definitions and resolution rules before trading.&lt;/p&gt;

&lt;h3&gt;
  
  
  Order book data
&lt;/h3&gt;

&lt;p&gt;The bot needs the current bids and asks for its selected token.&lt;/p&gt;

&lt;p&gt;From this information, it can calculate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Best bid and best ask&lt;/li&gt;
&lt;li&gt;Spread and midpoint&lt;/li&gt;
&lt;li&gt;Available quantity at each price level&lt;/li&gt;
&lt;li&gt;Changes in displayed depth&lt;/li&gt;
&lt;li&gt;Potential prices for its own orders&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Order and account information
&lt;/h3&gt;

&lt;p&gt;Market data alone isn't enough.&lt;/p&gt;

&lt;p&gt;The bot also needs to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Its open orders&lt;/li&gt;
&lt;li&gt;Current order statuses&lt;/li&gt;
&lt;li&gt;Available balances&lt;/li&gt;
&lt;li&gt;Current token positions&lt;/li&gt;
&lt;li&gt;Recent executions and partial fills&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Imagine that the best bid changes from $0.49 to $0.47.&lt;/p&gt;

&lt;p&gt;If your bot doesn't know whether its previous order filled, it might make its next decision using an incorrect inventory position.&lt;/p&gt;

&lt;p&gt;That can lead to unintended exposure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real-time updates
&lt;/h3&gt;

&lt;p&gt;A simple prototype can retrieve periodic order book snapshots using REST requests.&lt;/p&gt;

&lt;p&gt;However, frequent polling can introduce unnecessary requests and miss changes between snapshots.&lt;/p&gt;

&lt;p&gt;For a more responsive system, a market-data WebSocket can deliver updates as the order book changes.&lt;/p&gt;

&lt;p&gt;Your bot must still maintain a consistent view of the order book and recover correctly after a connection disconnects.&lt;/p&gt;

&lt;p&gt;Official developer documentation: &lt;a href="https://docs.polymarket.com/" rel="noopener noreferrer"&gt;Polymarket Developer Docs&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Liquidity Rewards and Maker Rebates
&lt;/h2&gt;

&lt;p&gt;Market makers may also encounter Polymarket's liquidity rewards and maker rebate programs.&lt;/p&gt;

&lt;p&gt;Although both relate to liquidity provision, they are not identical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Liquidity rewards&lt;/strong&gt; generally depend on how useful qualifying resting orders are to the market. Eligible markets may have specific spread, size, and scoring requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maker rebates&lt;/strong&gt; redistribute a portion of eligible taker fees to qualifying liquidity providers whose orders are filled, according to the program's rules.&lt;/p&gt;

&lt;p&gt;Program details can change, and not every market necessarily qualifies.&lt;/p&gt;

&lt;p&gt;Before incorporating incentives into your bot's profitability calculations, verify the current rules and market eligibility.&lt;/p&gt;

&lt;p&gt;Don't assume that every limit order earns rewards or that incentives will compensate for trading losses.&lt;/p&gt;

&lt;p&gt;Official references:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://help.polymarket.com/en/articles/13364466-liquidity-rewards" rel="noopener noreferrer"&gt;Polymarket Liquidity Rewards&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://help.polymarket.com/en/articles/13364471-maker-rebates-program" rel="noopener noreferrer"&gt;Polymarket Maker Rebates Program&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://help.polymarket.com/en/articles/13364478-trading-fees" rel="noopener noreferrer"&gt;Polymarket Trading Fees&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the first version of your bot, treat incentives as a secondary consideration. Focus first on reliable order management, inventory tracking, and actual trading performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Checklist Before Building Your Market Maker
&lt;/h2&gt;

&lt;p&gt;Before moving to Python implementation, make sure you understand the following concepts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Identify the YES and NO token identifiers for the selected market.&lt;/li&gt;
&lt;li&gt;[ ] Retrieve the actual order book for the token.&lt;/li&gt;
&lt;li&gt;[ ] Identify the best bid and best ask.&lt;/li&gt;
&lt;li&gt;[ ] Calculate the spread and midpoint correctly.&lt;/li&gt;
&lt;li&gt;[ ] Understand available depth across multiple price levels.&lt;/li&gt;
&lt;li&gt;[ ] Distinguish displayed prices from executable prices.&lt;/li&gt;
&lt;li&gt;[ ] Understand resting orders, partial fills, and cancellations.&lt;/li&gt;
&lt;li&gt;[ ] Check market-specific order requirements and trading rules.&lt;/li&gt;
&lt;li&gt;[ ] Verify which liquidity incentives, if any, apply.&lt;/li&gt;
&lt;li&gt;[ ] Track balances, inventory, and open orders.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These fundamentals will help you avoid common mistakes when implementing your strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The Polymarket order book is the foundation of an automated market-making system.&lt;/p&gt;

&lt;p&gt;It tells your bot what prices traders are offering, how much liquidity is available, and how the market changes over time.&lt;/p&gt;

&lt;p&gt;But it doesn't guarantee that an order will fill or that a displayed spread can be captured profitably.&lt;/p&gt;

&lt;p&gt;A reliable market maker combines order book data with accurate order management, inventory controls, and careful performance measurement.&lt;/p&gt;

&lt;p&gt;The key lessons are straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Order book:&lt;/strong&gt; Understand the current supply and demand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;YES/NO tokens:&lt;/strong&gt; Retrieve the actual book for the token you intend to trade.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spread:&lt;/strong&gt; Measure the difference between the best ask and best bid.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Midpoint:&lt;/strong&gt; Use it as a reference, not a guaranteed execution price.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Liquidity:&lt;/strong&gt; Evaluate both available quantity and spread.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risk management:&lt;/strong&gt; Track inventory, fills, and changing market conditions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the next lesson, we'll move from theory to implementation by setting up a Python project, connecting to Polymarket market data, and retrieving the information our bot needs to make quoting decisions.&lt;/p&gt;

&lt;p&gt;The goal is to build the system step by step, rather than rush into live trading before understanding the mechanics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow the Project
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub repository:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;https://github.com/Benj4minCup/Polymarket-Trading-Bot-python&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;YouTube tutorial:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=UCF7MA1Kekk" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=UCF7MA1Kekk&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contact and discussion:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://telegram.me/BenjaminCup" rel="noopener noreferrer"&gt;https://telegram.me/BenjaminCup&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're building your own market-making bot, share which part of order book analysis you find most challenging: spread calculation, liquidity analysis, order execution, or inventory management.&lt;/p&gt;

&lt;p&gt;I'd love to hear what you're working on.&lt;/p&gt;




&lt;h1&gt;
  
  
  Polymarket #Python #TradingBot #AlgorithmicTrading #MarketMaking #Web3 #Crypto #SoftwareDevelopment #Programming #FinTech
&lt;/h1&gt;

</description>
      <category>polymarket</category>
      <category>architecture</category>
      <category>tutorial</category>
      <category>python</category>
    </item>
    <item>
      <title>Polymarket Trading Bot : Building Market Maker Bot With Python- A Beginner's Guide</title>
      <dc:creator>Benjamin-Cup</dc:creator>
      <pubDate>Mon, 19 Oct 2026 13:33:18 +0000</pubDate>
      <link>https://dev.to/benjamin_cup/polymarket-trading-bot-building-market-maker-bot-with-python-a-beginners-guide-ba0</link>
      <guid>https://dev.to/benjamin_cup/polymarket-trading-bot-building-market-maker-bot-with-python-a-beginners-guide-ba0</guid>
      <description>&lt;p&gt;&lt;em&gt;Day 1 of 7 — Understanding Market Making, Liquidity, and Automated Trading&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What does it take to build a trading bot that continuously monitors a market, places buy and sell orders, and manages risk automatically?&lt;/p&gt;

&lt;p&gt;One interesting way to explore this problem is by building a &lt;strong&gt;Polymarket market maker bot using Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flpgnb4vl459dh8qzh38d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flpgnb4vl459dh8qzh38d.png" alt="Polymarket Trading Bot" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Polymarket is a prediction market where users trade outcome tokens associated with real-world events. These markets create an interesting engineering challenge: prices change, liquidity varies, orders may only partially fill, and a strategy that looks profitable on paper can lose money in practice.&lt;/p&gt;

&lt;p&gt;In this tutorial series, we'll explore the fundamentals of market making and gradually work toward a complete automated trading system.&lt;/p&gt;

&lt;p&gt;We'll cover market data, order book analysis, trading strategies, order management, inventory control, and risk management.&lt;/p&gt;

&lt;p&gt;Let's start with the most important question.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. What Is a Market Maker Bot?
&lt;/h2&gt;

&lt;p&gt;A market maker bot is a program that automatically places and manages limit orders to provide liquidity.&lt;/p&gt;

&lt;p&gt;Instead of simply buying an outcome because it expects that outcome to win, a market maker attempts to earn revenue by trading at favorable prices while managing the risks associated with its positions.&lt;/p&gt;

&lt;p&gt;Imagine a prediction market asking:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will Bitcoin be above $100,000 at the end of a specified period?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Suppose the YES token has the following order book:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Order&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Best bid&lt;/td&gt;
&lt;td&gt;$0.48&lt;/td&gt;
&lt;td&gt;Highest price a buyer offers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best ask&lt;/td&gt;
&lt;td&gt;$0.52&lt;/td&gt;
&lt;td&gt;Lowest price a seller accepts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Midpoint&lt;/td&gt;
&lt;td&gt;$0.50&lt;/td&gt;
&lt;td&gt;Average of the best bid and ask&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spread&lt;/td&gt;
&lt;td&gt;$0.04&lt;/td&gt;
&lt;td&gt;Difference between ask and bid&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A market-making bot might place a buy order at $0.48 and a sell order at $0.52.&lt;/p&gt;

&lt;p&gt;If both orders execute at those prices, the bot may capture the difference.&lt;/p&gt;

&lt;p&gt;However, placing orders doesn't guarantee that they will execute, and executing both sides doesn't guarantee a profit after costs and inventory losses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The real engineering challenge is managing orders and risk as market conditions change.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. How Does a Market Maker Make Money?
&lt;/h2&gt;

&lt;p&gt;The central concept is the &lt;strong&gt;bid-ask spread&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The spread is calculated as:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Spread = Best Ask - Best Bid&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Using our example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$0.52 - $0.48 = $0.04&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Suppose the bot buys 100 YES tokens at $0.48 and later sells all 100 at $0.52.&lt;/p&gt;

&lt;p&gt;The illustrative gross trading profit is:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;100 × ($0.52 - $0.48) = $4.00&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This calculation excludes trading costs, inventory losses, and other execution effects.&lt;/p&gt;

&lt;p&gt;But here's the problem.&lt;/p&gt;

&lt;p&gt;What happens if the buy order executes and the sell order doesn't?&lt;/p&gt;

&lt;p&gt;The bot now holds 100 tokens. If the market price falls, the value of that inventory decreases. The bot may need to sell at a worse price or wait for better conditions.&lt;/p&gt;

&lt;p&gt;This is why market making is not simply about placing orders far apart.&lt;/p&gt;

&lt;p&gt;A practical strategy must consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Order-fill probability:&lt;/strong&gt; How likely is each order to execute?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inventory exposure:&lt;/strong&gt; How much of each outcome does the bot hold?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Market volatility:&lt;/strong&gt; How quickly can prices change?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution quality:&lt;/strong&gt; Are orders being filled at favorable prices?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trading costs:&lt;/strong&gt; What costs and applicable incentives affect the final result?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data freshness:&lt;/strong&gt; Is the bot making decisions using current market information?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A wider spread isn't necessarily better. It may reflect a market with poor liquidity or significant risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Market Making vs. Arbitrage vs. Momentum Trading
&lt;/h2&gt;

&lt;p&gt;These three approaches are useful to distinguish when designing an automated trading system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Market making
&lt;/h3&gt;

&lt;p&gt;The bot provides liquidity by placing limit orders.&lt;/p&gt;

&lt;p&gt;Its potential revenue comes from favorable execution spreads and, where eligible, liquidity incentives or maker rebates.&lt;/p&gt;

&lt;p&gt;The main challenges are inventory management, execution quality, and adverse selection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Arbitrage
&lt;/h3&gt;

&lt;p&gt;An arbitrage strategy searches for pricing inconsistencies between related assets, outcomes, or markets.&lt;/p&gt;

&lt;p&gt;For example, a strategy might investigate whether complementary YES and NO positions can be acquired for less than their combined settlement value.&lt;/p&gt;

&lt;p&gt;The bot must account for actual token mechanics, execution costs, liquidity, and whether all necessary trades can complete.&lt;/p&gt;

&lt;h3&gt;
  
  
  Momentum trading
&lt;/h3&gt;

&lt;p&gt;A momentum strategy attempts to benefit from an emerging price movement.&lt;/p&gt;

&lt;p&gt;For example, a bot might monitor Bitcoin's spot price and adjust its trading decisions when a significant movement occurs.&lt;/p&gt;

&lt;p&gt;The main challenges are identifying meaningful signals, avoiding noisy price movements, and managing late entries.&lt;/p&gt;

&lt;p&gt;These approaches can be combined, but it's easier to understand their behavior when each strategy is implemented and evaluated separately first.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Why Does Polymarket Need Market Makers?
&lt;/h2&gt;

&lt;p&gt;Markets need buyers and sellers willing to trade.&lt;/p&gt;

&lt;p&gt;When liquidity is limited, users may encounter wider spreads, larger price impact, and more difficulty executing orders at their desired prices.&lt;/p&gt;

&lt;p&gt;Market makers help by providing resting orders that other traders can execute against.&lt;/p&gt;

&lt;p&gt;Polymarket also operates liquidity incentive programs. Depending on the market and current program rules, eligible orders may qualify for liquidity rewards or maker rebates.&lt;/p&gt;

&lt;p&gt;Official documentation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://help.polymarket.com/en/articles/13364466-liquidity-rewards" rel="noopener noreferrer"&gt;Polymarket Liquidity Rewards&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://help.polymarket.com/en/articles/13364471-maker-rebates-program" rel="noopener noreferrer"&gt;Polymarket Maker Rebates Program&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These programs have their own eligibility requirements, and their terms can change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Liquidity incentives aren't guaranteed profit. A bot may receive rewards while losing money through unfavorable fills or changes in the value of its inventory.&lt;/p&gt;

&lt;p&gt;Always evaluate the complete strategy rather than focusing on incentives alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Designing the Bot: A Simple Architecture
&lt;/h2&gt;

&lt;p&gt;Before writing the trading logic, let's break the system into manageable components.&lt;/p&gt;

&lt;p&gt;A practical Python market maker can start with five modules.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 Market Data
&lt;/h3&gt;

&lt;p&gt;This component retrieves market information and maintains an up-to-date view of the order book.&lt;/p&gt;

&lt;p&gt;Its responsibilities include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reading market metadata and token identifiers.&lt;/li&gt;
&lt;li&gt;Tracking the best bid and ask.&lt;/li&gt;
&lt;li&gt;Monitoring available order book depth.&lt;/li&gt;
&lt;li&gt;Detecting stale or incomplete data.&lt;/li&gt;
&lt;li&gt;Providing market information to the strategy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reliable data is essential. If the bot uses an outdated order book, it may place orders at prices that are no longer appropriate.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.2 Strategy Engine
&lt;/h3&gt;

&lt;p&gt;The strategy engine decides where the bot should place its buy and sell orders.&lt;/p&gt;

&lt;p&gt;A simple starting point is to calculate a reference midpoint:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Midpoint = (Best Bid + Best Ask) / 2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The bot can then calculate target prices around that reference point.&lt;/p&gt;

&lt;p&gt;For example, a simplified quoting model might use:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Target Bid = Reference Price - Half Spread&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Target Ask = Reference Price + Half Spread&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is only a starting model, not a complete profitable strategy. A production system may need to adjust quotes based on inventory, volatility, liquidity, and other signals.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.3 Order Management
&lt;/h3&gt;

&lt;p&gt;This component communicates with the trading interface to submit and manage orders.&lt;/p&gt;

&lt;p&gt;It should track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Order identifiers.&lt;/li&gt;
&lt;li&gt;Order status.&lt;/li&gt;
&lt;li&gt;Open and partially filled orders.&lt;/li&gt;
&lt;li&gt;Cancellation and replacement requests.&lt;/li&gt;
&lt;li&gt;Execution updates.&lt;/li&gt;
&lt;li&gt;Available balances and reconciliation results.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Order management is more complicated than sending an API request.&lt;/p&gt;

&lt;p&gt;For example, a network timeout doesn't necessarily mean an order failed. The exchange may have processed the request even though the bot didn't receive the response.&lt;/p&gt;

&lt;p&gt;The system must reconcile its internal state with the actual order status before retrying potentially duplicated actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.4 Risk Management
&lt;/h3&gt;

&lt;p&gt;Risk management defines the conditions under which the bot is allowed to trade.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maximum inventory per outcome.&lt;/li&gt;
&lt;li&gt;Maximum order size.&lt;/li&gt;
&lt;li&gt;Maximum capital allocation.&lt;/li&gt;
&lt;li&gt;Limits on total exposure.&lt;/li&gt;
&lt;li&gt;Protection against stale market data.&lt;/li&gt;
&lt;li&gt;Emergency shutdown conditions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Risk checks should happen before new orders are submitted, not only after a loss occurs.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.5 Monitoring and Reporting
&lt;/h3&gt;

&lt;p&gt;The monitoring component records what the bot does and why.&lt;/p&gt;

&lt;p&gt;Useful metrics include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Realized and unrealized profit and loss.&lt;/li&gt;
&lt;li&gt;Inventory exposure.&lt;/li&gt;
&lt;li&gt;Order-fill rate.&lt;/li&gt;
&lt;li&gt;Partial-fill frequency.&lt;/li&gt;
&lt;li&gt;Spread captured per completed trade.&lt;/li&gt;
&lt;li&gt;Trading costs and applicable incentives.&lt;/li&gt;
&lt;li&gt;API failures and order reconciliation errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without monitoring, it becomes difficult to determine whether a poor result came from the strategy, market conditions, or an implementation bug.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. The Main Trading Loop
&lt;/h2&gt;

&lt;p&gt;At a high level, the bot repeatedly performs the following operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        +--------------------+
        | Read Market Data   |
        +--------------------+
                  |
                  v
        +--------------------+
        | Validate Data      |
        +--------------------+
                  |
                  v
        +--------------------+
        | Calculate Quotes   |
        +--------------------+
                  |
                  v
        +--------------------+
        | Check Risk Limits  |
        +--------------------+
                  |
                  v
        +--------------------+
        | Manage Orders      |
        +--------------------+
                  |
                  v
        +--------------------+
        | Reconcile Fills    |
        +--------------------+
                  |
                  v
        +--------------------+
        | Record Performance |
        +--------------------+
                  |
                  +----&amp;gt; Repeat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Each stage has a specific responsibility.&lt;/p&gt;

&lt;p&gt;The strategy determines what orders would be desirable. Risk management determines whether those orders are acceptable. Order management handles execution, and reconciliation ensures the bot understands its actual positions.&lt;/p&gt;

&lt;p&gt;Keeping these responsibilities separate makes the code easier to test and maintain.&lt;/p&gt;
&lt;h2&gt;
  
  
  7. Common Mistakes When Building a Market Maker
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Mistake 1: Assuming every spread is profitable
&lt;/h3&gt;

&lt;p&gt;A wide spread can indicate risk rather than opportunity.&lt;/p&gt;

&lt;p&gt;The bot might get filled just before the market price moves against its position.&lt;/p&gt;
&lt;h3&gt;
  
  
  Mistake 2: Ignoring inventory
&lt;/h3&gt;

&lt;p&gt;If buy orders fill repeatedly while sell orders remain open, the bot may accumulate more exposure than intended.&lt;/p&gt;

&lt;p&gt;Inventory limits and position-aware quoting help control this problem.&lt;/p&gt;
&lt;h3&gt;
  
  
  Mistake 3: Replacing orders too frequently
&lt;/h3&gt;

&lt;p&gt;Constant cancellation and replacement can create unnecessary API traffic, race conditions, and execution uncertainty.&lt;/p&gt;

&lt;p&gt;The strategy needs a sensible policy for deciding when a quote has become stale enough to replace.&lt;/p&gt;
&lt;h3&gt;
  
  
  Mistake 4: Ignoring partial fills
&lt;/h3&gt;

&lt;p&gt;An order may execute only partially. If the bot assumes the entire order filled, its internal inventory calculation can become incorrect.&lt;/p&gt;

&lt;p&gt;Execution updates and periodic reconciliation are essential.&lt;/p&gt;
&lt;h3&gt;
  
  
  Mistake 5: Treating successful execution as proof of profitability
&lt;/h3&gt;

&lt;p&gt;A bot can submit orders correctly and still lose money.&lt;/p&gt;

&lt;p&gt;Software correctness and trading performance are separate problems. Both require testing.&lt;/p&gt;
&lt;h3&gt;
  
  
  Mistake 6: Going live too early
&lt;/h3&gt;

&lt;p&gt;Start with unit tests, historical market-data replay, simulation, and paper trading.&lt;/p&gt;

&lt;p&gt;Only consider live trading after the system's behavior, failure handling, and risk controls have been thoroughly evaluated.&lt;/p&gt;
&lt;h2&gt;
  
  
  8. Our Seven-Day Development Roadmap
&lt;/h2&gt;

&lt;p&gt;This article is Day 1 of a seven-part series about understanding and building a Polymarket market maker bot.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Day&lt;/th&gt;
&lt;th&gt;Topic&lt;/th&gt;
&lt;th&gt;Main Goal&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Market-Making Fundamentals&lt;/td&gt;
&lt;td&gt;Understand liquidity, spreads, and inventory risk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Polymarket Order Book&lt;/td&gt;
&lt;td&gt;Learn how bids, asks, and outcome tokens work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Python Project Setup&lt;/td&gt;
&lt;td&gt;Connect to market data and organize the codebase&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Trading Strategy&lt;/td&gt;
&lt;td&gt;Calculate quotes and manage inventory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Order Management&lt;/td&gt;
&lt;td&gt;Track, cancel, and replace orders reliably&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Risk and Paper Trading&lt;/td&gt;
&lt;td&gt;Test the strategy and control exposure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Complete Bot&lt;/td&gt;
&lt;td&gt;Integrate components and monitor performance&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The goal isn't just to copy a trading script. It's to understand the architecture, the reasoning behind the strategy, and the risks that must be controlled.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Building a Polymarket market maker bot is a practical way to explore Python, real-time market data, automated execution, and risk management.&lt;/p&gt;

&lt;p&gt;The most important lesson is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Market making isn't just about capturing the spread. It's about managing the risks involved in trying to capture it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A reliable bot needs fresh data, sensible quoting logic, robust order management, accurate inventory tracking, and meaningful performance metrics.&lt;/p&gt;

&lt;p&gt;In Day 2, we'll explore how the Polymarket order book works and how to interpret bids, asks, liquidity, and token prices before implementing the trading strategy.&lt;/p&gt;
&lt;h3&gt;
  
  
  Explore the Project
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; 
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Benj4minCup" rel="noopener noreferrer"&gt;
        Benj4minCup
      &lt;/a&gt; / &lt;a href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;
        Polymarket-Trading-Bot-python
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      polymarket trading bot polymarket twap bot polymarket arbitrage bot polymarket bot polymarket trading bot polymarket twap bot polymarket arbitrage bot polymarket bot polymarket trading bot polymarket twap bot polymarket arbitrage bot polymarket bot polymarket trading bot polymarket twap bot polymarket arbitrage bot polymarket bot polymarket trading
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Polymarket Trading bot system&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;An open-source and Strong Strategy collection of Polymarket trading bot and Polymarket arbitrage bot and Polymarket TWAP trading bot in Python for high-performance automated trading on polymarket crypto 5min and 15min markets.&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/33036584/633381478-71b65c58-00d2-4bbe-8b6d-8ed6fc9812e4.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3OTI0MTcxMDIsIm5iZiI6MTc5MjQxNjgwMiwicGF0aCI6Ii8zMzAzNjU4NC82MzMzODE0NzgtNzFiNjVjNTgtMDBkMi00YmJlLThiNmQtOGVkNmZjOTgxMmU0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjEwMTklMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYxMDE5VDEzMzMyMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWMzZTdhNjU0ZTc2MDg5ODAyOWNmOTdkYThiOTlhNzAyOWRkNzU3ZDhjMjVhOTA2YmI0NWI2Y2RmNzFhNGI4NDkmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.0jxD_VOcKe7RoKaDS_KTG4gZXgu7jh6sKnIYClO30ys"&gt;&lt;img width="1536" height="1024" alt="Polymarket-benjamincup-bot-dashboard" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F33036584%2F633381478-71b65c58-00d2-4bbe-8b6d-8ed6fc9812e4.png%3Fjwt%3DeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3OTI0MTcxMDIsIm5iZiI6MTc5MjQxNjgwMiwicGF0aCI6Ii8zMzAzNjU4NC82MzMzODE0NzgtNzFiNjVjNTgtMDBkMi00YmJlLThiNmQtOGVkNmZjOTgxMmU0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjEwMTklMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYxMDE5VDEzMzMyMlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWMzZTdhNjU0ZTc2MDg5ODAyOWNmOTdkYThiOTlhNzAyOWRkNzU3ZDhjMjVhOTA2YmI0NWI2Y2RmNzFhNGI4NDkmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.0jxD_VOcKe7RoKaDS_KTG4gZXgu7jh6sKnIYClO30ys" class="js-gh-image-fallback"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This repository is primarily intended for educational and research purposes. It includes strategy concepts, implementation approaches, and selected performance screenshots to help developers understand how different automated trading strategies can be designed and tested.&lt;/p&gt;

&lt;p&gt;The repository does not provide a complete production-ready trading bot source code. Instead, it provides strategy descriptions and research materials that you can use as a foundation for developing your own system.&lt;/p&gt;

&lt;p&gt;If you are interested in building a Polymarket Trading Bot, you can follow my tutorials and use the concepts in this repository to develop your own implementation.&lt;/p&gt;

&lt;p&gt;For users who prefer a ready-to-deploy solution or require custom strategy development, commercial bot development and customization are also available.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;YouTube Video:&lt;/strong&gt; &lt;br&gt;&lt;br&gt;
  &lt;iframe&gt;
    src="https://www.youtube.com/embed/UCF7MA1Kekk"&lt;br&gt;
    width="710"&lt;br&gt;
    height="399"&lt;br&gt;
    style="width: 100%; height: auto; aspect-ratio: 16 / 9;"&lt;br&gt;
    allowfullscreen&lt;br&gt;
    loading="lazy"&amp;gt;&lt;br&gt;
  &lt;/iframe&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Discussion:&lt;/strong&gt; &lt;a href="https://telegram.me/BenjaminCup" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://telegram.me/BenjaminCup" rel="noopener noreferrer"&gt;https://telegram.me/BenjaminCup&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;If you're interested in Python, algorithmic trading, prediction markets, or building reliable automated systems, follow along as we develop the concepts step by step.&lt;/p&gt;

&lt;h1&gt;
  
  
  python #trading #beginners #opensource #polymarket #trading #bot
&lt;/h1&gt;

</description>
      <category>python</category>
      <category>trading</category>
      <category>beginners</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Polymarket Trading Bot in Python: BTC Spot Price vs. TWAP-60s</title>
      <dc:creator>Benjamin-Cup</dc:creator>
      <pubDate>Sat, 17 Oct 2026 13:25:49 +0000</pubDate>
      <link>https://dev.to/benjamin_cup/polymarket-trading-bot-in-python-btc-spot-price-vs-twap-60s-jmf</link>
      <guid>https://dev.to/benjamin_cup/polymarket-trading-bot-in-python-btc-spot-price-vs-twap-60s-jmf</guid>
      <description>&lt;p&gt;How can you analyze short-term Bitcoin prediction markets using live BTC prices and Polymarket order book data?&lt;/p&gt;

&lt;p&gt;This &lt;strong&gt;Polymarket trading bot in Python&lt;/strong&gt; explores the relationship between three important signals: the external Bitcoin spot price, the TWAP-60s price reference, and the probability implied by Polymarket's live order book.&lt;/p&gt;

&lt;p&gt;The goal is to identify potential pricing discrepancies and understand whether they represent meaningful trading opportunities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💻 GitHub: 
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Benj4minCup" rel="noopener noreferrer"&gt;
        Benj4minCup
      &lt;/a&gt; / &lt;a href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;
        Polymarket-Trading-Bot-python
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      polymarket trading bot polymarket twap bot polymarket arbitrage bot polymarket bot polymarket trading bot polymarket twap bot polymarket arbitrage bot polymarket bot polymarket trading bot polymarket twap bot polymarket arbitrage bot polymarket bot polymarket trading bot polymarket twap bot polymarket arbitrage bot polymarket bot polymarket trading
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Polymarket Trading bot system&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;An open-source and Strong Strategy collection of Polymarket trading bot and Polymarket arbitrage bot and Polymarket TWAP trading bot in Python for high-performance automated trading on polymarket crypto 5min and 15min markets.&lt;/p&gt;
&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/33036584/633381478-71b65c58-00d2-4bbe-8b6d-8ed6fc9812e4.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3OTIyNDM4NDgsIm5iZiI6MTc5MjI0MzU0OCwicGF0aCI6Ii8zMzAzNjU4NC82MzMzODE0NzgtNzFiNjVjNTgtMDBkMi00YmJlLThiNmQtOGVkNmZjOTgxMmU0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjEwMTclMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYxMDE3VDEzMjU0OFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWFjNTI0YjI5N2I4ZDE2NjJlM2MwODY3MzIyMTJiOTVhMmJjYzg4Zjc1YzdjYWEzNTQyOWViMGMwODY0MWY0YTUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.0BYPdEntBZjnAUHQ6hxuvskpV-MmB1tFCQ9nhhkJ9ss"&gt;&lt;img width="1536" height="1024" alt="Polymarket-benjamincup-bot-dashboard" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F33036584%2F633381478-71b65c58-00d2-4bbe-8b6d-8ed6fc9812e4.png%3Fjwt%3DeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3OTIyNDM4NDgsIm5iZiI6MTc5MjI0MzU0OCwicGF0aCI6Ii8zMzAzNjU4NC82MzMzODE0NzgtNzFiNjVjNTgtMDBkMi00YmJlLThiNmQtOGVkNmZjOTgxMmU0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjEwMTclMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYxMDE3VDEzMjU0OFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWFjNTI0YjI5N2I4ZDE2NjJlM2MwODY3MzIyMTJiOTVhMmJjYzg4Zjc1YzdjYWEzNTQyOWViMGMwODY0MWY0YTUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.0BYPdEntBZjnAUHQ6hxuvskpV-MmB1tFCQ9nhhkJ9ss" class="js-gh-image-fallback"&gt;&lt;/a&gt;
&lt;p&gt;This repository is primarily intended for educational and research purposes. It includes strategy concepts, implementation approaches, and selected performance screenshots to help developers understand how different automated trading strategies can be designed and tested.&lt;/p&gt;
&lt;p&gt;The repository does not provide a complete production-ready trading bot source code. Instead, it provides strategy descriptions and research materials that you can use as a foundation for developing your own system.&lt;/p&gt;
&lt;p&gt;If you are interested in building a Polymarket Trading Bot, you can follow my tutorials and use the concepts in this repository to develop your own implementation.&lt;/p&gt;
&lt;p&gt;For users who prefer a ready-to-deploy solution or require custom strategy development, commercial bot development and customization are also available.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;🎥 YouTube demo: 
  &lt;iframe src="https://www.youtube.com/embed/UCF7MA1Kekk" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/li&gt;
&lt;li&gt;📩 Telegram: &lt;a href="https://telegram.me/BenjaminCup" rel="noopener noreferrer"&gt;https://telegram.me/BenjaminCup&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Is a Polymarket Trading Bot?
&lt;/h2&gt;

&lt;p&gt;A Polymarket trading bot is a program that interacts with prediction markets to analyze prices, monitor market conditions, generate signals, or execute trades, depending on its implementation.&lt;/p&gt;

&lt;p&gt;In Bitcoin prediction markets, traders may speculate on whether BTC will cross a price threshold or finish above or below a specified level.&lt;/p&gt;

&lt;p&gt;The challenge is that the current Bitcoin spot price does not tell the whole story. The market's resolution rules, remaining time, liquidity, and order book prices also matter.&lt;/p&gt;

&lt;p&gt;This project focuses on comparing those signals to better understand short-term BTC prediction markets.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Live Bitcoin Spot Price
&lt;/h2&gt;

&lt;p&gt;The live BTC spot price represents Bitcoin's current trading price on an external cryptocurrency exchange.&lt;/p&gt;

&lt;p&gt;A trading bot can use this price to monitor market movements and compare the underlying asset with Polymarket's current pricing.&lt;/p&gt;

&lt;p&gt;For example, if BTC is trading at $100,050, that tells us where Bitcoin is trading on the selected exchange at that moment.&lt;/p&gt;

&lt;p&gt;However, different exchanges can report slightly different prices due to liquidity and market conditions.&lt;/p&gt;

&lt;p&gt;The external spot price is useful information, but it should not automatically be treated as the official resolution price for a Polymarket contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. TWAP-60s: Understanding the Price Reference
&lt;/h2&gt;

&lt;p&gt;TWAP stands for &lt;strong&gt;Time-Weighted Average Price&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A TWAP-60s calculation represents an average price over a 60-second window, based on the specific calculation method used.&lt;/p&gt;

&lt;p&gt;Unlike a single spot-price observation, it incorporates price information over a period of time.&lt;/p&gt;

&lt;p&gt;This can be important in short-duration Bitcoin prediction markets because BTC prices can move rapidly. The latest spot price and a time-averaged price may differ.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Current BTC spot price: $100,050&lt;/li&gt;
&lt;li&gt;Example 60-second reference: $100,000&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The difference between these values provides context for analyzing the market.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Always verify the resolution rules for the specific Polymarket contract. Do not assume that a TWAP-60s value is the official settlement reference unless the market rules specify it.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Polymarket Order Book and Implied Probability
&lt;/h2&gt;

&lt;p&gt;The Polymarket order book displays bids and asks for outcome tokens.&lt;/p&gt;

&lt;p&gt;For example, imagine a hypothetical YES market with the following prices:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Order book metric&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Best YES bid&lt;/td&gt;
&lt;td&gt;$0.56&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best YES ask&lt;/td&gt;
&lt;td&gt;$0.60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Midpoint&lt;/td&gt;
&lt;td&gt;$0.58&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Indicative midpoint probability&lt;/td&gt;
&lt;td&gt;58%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A YES token priced at $0.58 can be interpreted as an indicative 58% market-implied probability, assuming the token pays $1 if YES resolves successfully and $0 otherwise.&lt;/p&gt;

&lt;p&gt;However, the midpoint is not necessarily an executable trading price.&lt;/p&gt;

&lt;p&gt;A buyer seeking immediate execution generally needs to consider the ask price, available liquidity, fees, and slippage.&lt;/p&gt;

&lt;p&gt;The order book reflects traders' expectations, market liquidity, uncertainty, and the time remaining until resolution.&lt;/p&gt;

&lt;p&gt;These figures are illustrative examples, not live Polymarket prices.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. How the Polymarket BTC Trading Bot Works
&lt;/h2&gt;

&lt;p&gt;The analysis process follows a simple workflow.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retrieve the external BTC spot price.&lt;/li&gt;
&lt;li&gt;Calculate or retrieve the relevant TWAP-60s value.&lt;/li&gt;
&lt;li&gt;Read the current Polymarket order book.&lt;/li&gt;
&lt;li&gt;Compare the price data with the contract's threshold and resolution rules.&lt;/li&gt;
&lt;li&gt;Examine the market-implied probability.&lt;/li&gt;
&lt;li&gt;Evaluate potential discrepancies, liquidity, and execution costs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The important idea is to compare the underlying Bitcoin market with the price of the prediction market outcome.&lt;/p&gt;

&lt;p&gt;A difference between the signals may justify further investigation, but it does not automatically indicate a profitable trade.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Why Can BTC Prices and Polymarket Probabilities Differ?
&lt;/h2&gt;

&lt;p&gt;Several factors can explain apparent discrepancies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Different price sources
&lt;/h3&gt;

&lt;p&gt;The BTC price on an external exchange may not match the price source used to resolve the Polymarket contract.&lt;/p&gt;

&lt;h3&gt;
  
  
  Market update delays
&lt;/h3&gt;

&lt;p&gt;Bitcoin can move quickly, while prediction-market quotes may update at a different pace.&lt;/p&gt;

&lt;h3&gt;
  
  
  Time until resolution
&lt;/h3&gt;

&lt;p&gt;If BTC is currently above a threshold, the probability of finishing above it still depends on how much time remains and how volatile the market is.&lt;/p&gt;

&lt;h3&gt;
  
  
  Order book liquidity
&lt;/h3&gt;

&lt;p&gt;A displayed price may be available for only a small number of tokens. Larger orders can receive worse execution prices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trading costs
&lt;/h3&gt;

&lt;p&gt;Fees, bid-ask spreads, slippage, and latency can eliminate an apparent pricing advantage.&lt;/p&gt;

&lt;p&gt;A useful Polymarket trading strategy must consider these factors rather than relying on a simple comparison between two prices.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Why Order Book Analysis Matters
&lt;/h2&gt;

&lt;p&gt;Consider a YES token with a bid of $0.56 and an ask of $0.60.&lt;/p&gt;

&lt;p&gt;The four-cent spread represents the difference between the best displayed buying and selling prices.&lt;/p&gt;

&lt;p&gt;If a bot calculates probability using only the midpoint, it may overlook the cost of entering or exiting a position.&lt;/p&gt;

&lt;p&gt;A more realistic analysis considers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Best bid and ask.&lt;/li&gt;
&lt;li&gt;Available liquidity at each price level.&lt;/li&gt;
&lt;li&gt;Expected execution price for the intended order size.&lt;/li&gt;
&lt;li&gt;Trading fees and slippage.&lt;/li&gt;
&lt;li&gt;Data freshness and timing.&lt;/li&gt;
&lt;li&gt;The contract's actual resolution conditions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These checks help distinguish a theoretical pricing discrepancy from a potentially executable opportunity.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Explore the Python Polymarket Trading Bot
&lt;/h2&gt;

&lt;p&gt;You can inspect the project source code and watch the demonstration using the links below.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub repository
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Polymarket Trading Bot — Python&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Explore the source code, project structure, and implementation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;https://github.com/Benj4minCup/Polymarket-Trading-Bot-python&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  YouTube demo
&lt;/h3&gt;

&lt;p&gt;Watch the project demonstration:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=UCF7MA1Kekk" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=UCF7MA1Kekk&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect on Telegram
&lt;/h3&gt;

&lt;p&gt;Have questions or want to discuss prediction markets, Python automation, or trading-bot development?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://telegram.me/BenjaminCup" rel="noopener noreferrer"&gt;https://telegram.me/BenjaminCup&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A Polymarket trading bot can analyze more than the current Bitcoin price.&lt;/p&gt;

&lt;p&gt;Comparing the external BTC spot price, a TWAP-60s reference, and the live Polymarket order book provides a framework for studying short-term prediction markets.&lt;/p&gt;

&lt;p&gt;Each signal serves a different purpose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;BTC spot price:&lt;/strong&gt; Shows where Bitcoin is trading now.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TWAP-60s:&lt;/strong&gt; Represents price behavior across a selected time window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Order book:&lt;/strong&gt; Shows the prices traders currently offer for prediction-market outcomes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main challenge is determining whether an apparent probability discrepancy remains meaningful after accounting for resolution rules, time to expiry, liquidity, and trading costs.&lt;/p&gt;

&lt;p&gt;If you are interested in building a Polymarket trading bot with Python, exploring order book data, or studying Bitcoin prediction markets, check out the repository and demo above.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer: This project is presented for educational and research purposes. Trading involves risk, and no strategy guarantees profit.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>polymarket</category>
      <category>python</category>
      <category>bitcoin</category>
      <category>trading</category>
    </item>
    <item>
      <title>Polymarket Trading Bot: The Most Profitable Trading Bots on Polymarket Right Now</title>
      <dc:creator>Benjamin-Cup</dc:creator>
      <pubDate>Fri, 16 Oct 2026 21:02:54 +0000</pubDate>
      <link>https://dev.to/benjamin_cup/polymarket-trading-bot-the-most-profitable-trading-bots-on-polymarket-right-now-jng</link>
      <guid>https://dev.to/benjamin_cup/polymarket-trading-bot-the-most-profitable-trading-bots-on-polymarket-right-now-jng</guid>
      <description>&lt;p&gt;Using Claude, I analyzed every trade made by some of the most profitable trading systems on Polymarket and reconstructed their logic inside each market to understand how they consistently grow their capital and have already reached the 6 and 7-figure range.&lt;/p&gt;

&lt;p&gt;Below, I will break down the strategy behind each trading bot, where its edge comes from, and why these systems continue to generate positive PnL while many of their competitors are no longer profitable.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Bonereaper (Directional Rotation with Dynamic Hedge)
Bonereaper operates as a directional system. The algorithm forms a view on the current direction of the underlying asset, builds a position in the corresponding outcome, and then continues recalculating fair probability as the market moves. If the signal changes, the bot usually does not close the old position. Instead, it starts accumulating the opposite outcome.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Its cycle looks roughly like this:&lt;/p&gt;

&lt;p&gt;Model detects an edge in Up -&amp;gt; Bot starts buying Up -&amp;gt; The underlying asset reverses -&amp;gt; Fair probability shifts in favor of Down -&amp;gt; Bot starts buying Down -&amp;gt; The original Up remains part of the total position, while the opposite side acts as a dynamic hedge.&lt;/p&gt;

&lt;p&gt;This is especially visible in 5m markets. Bonereaper accumulated both sides in roughly 55% of these markets, while the median delay between the first entry on one side and the first entry on the opposite side was only around 26 seconds. At the same time, positions usually remained unbalanced: the smaller side was only around 45% of the larger side on a median basis.&lt;/p&gt;

&lt;p&gt;The combined average price of Up and Down in two-sided 5m positions was around $1.08. This means it is not complete-set arbitrage. The bot pays for the hedge to reduce directional exposure after the signal changes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Where the edge comes from:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The main objective of the algorithm is to recalculate the probability of Up and Down faster than Polymarket after the price of the underlying asset changes. To do this, the model takes into account external spot prices, order book depth, short-term momentum, movement speed, distance from the opening price, and the time remaining until resolution.&lt;/p&gt;

&lt;p&gt;If fair probability has already changed while the contract price has not yet adjusted, a short-term pricing gap appears.&lt;/p&gt;

&lt;p&gt;Bonereaper tries to capture that gap with the first side of the position. If the market continues moving in the expected direction, the bot can increase exposure. If the signal breaks, the opposite outcome limits the impact of the original entry.&lt;/p&gt;

&lt;p&gt;Instead of a single binary position, the result is a position that is constantly being rebuilt.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbemgxq37avyfd3hi0fw4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbemgxq37avyfd3hi0fw4.png" alt=" " width="720" height="179"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;0xb55… (Asynchronous Complete-Set Accumulator)
The second bot has a completely different structure. Both sides of the position appear much more systematically. It buys both Up and Down in roughly 75% of all markets. On 15m markets, this rises to 79%, on 1h to 87%, and on 4h to 100%.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But this is not classic arbitrage where Up and Down are purchased at the same time. On 5m markets, the median gap between the first entry on one side and the first entry on the opposite side was around 52 seconds. On 15m markets, it was already close to three minutes. This means the algorithm uses price movement across time.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Up temporarily becomes cheap -&amp;gt; Bot accumulates Up -&amp;gt; Some time later, the underlying asset reverses -&amp;gt; Down becomes cheaper -&amp;gt; Bot starts accumulating Down -&amp;gt; Part of the two positions becomes a complete set&lt;/p&gt;

&lt;p&gt;The economics then look like this:&lt;/p&gt;

&lt;p&gt;Complete-set cost = VWAP(Up) + VWAP(Down)&lt;/p&gt;

&lt;p&gt;If the final cost is below $1, the matched part of the position has a positive structural edge regardless of which outcome finishes higher at settlement.&lt;/p&gt;

&lt;p&gt;This effect becomes especially visible on longer timeframes. On 1h markets, the median combined price of both sides was around $0.93, while on 4h markets it was around $0.91. This looks similar to temporal arbitrage.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Where the edge comes from:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Up and Down are constantly repriced as the underlying asset moves. The algorithm does not need to see the following prices at the same time:&lt;/p&gt;

&lt;p&gt;Up = $0.42 Down = $0.55&lt;/p&gt;

&lt;p&gt;It can buy Up now and buy Down several minutes later, after the entire pricing structure has changed. The longer a market remains open, the more opportunities the bot has to acquire both sides during different phases of the move.&lt;/p&gt;

&lt;p&gt;This is why 1h and 4h markets are particularly suitable for this model. During a single window, the underlying asset can move up and down several times, creating attractive levels first for one outcome and then for the other. Part of the inventory becomes neutral, while the unmatched remainder keeps directional exposure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9ingcsssggiro541xuyk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9ingcsssggiro541xuyk.png" alt=" " width="720" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Account: 0xb55fa1296e6ec55d0ce53d93b9237389f11764d4&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;mo-money (Multi-Timeframe Hybrid Bot)
What makes mo-money interesting is that it does not use the same model across every timeframe. On shorter markets, it looks primarily directional. On longer markets, its behavior gradually shifts toward two-sided inventory management.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On 5m markets, both sides appeared in only around 32% of markets. On 1h markets, this increased to 67%, and on 4h markets to roughly 85%. Both the hedge frequency and the structure of the position change.&lt;/p&gt;

&lt;p&gt;In two-sided 5m markets, the smaller side was only around 43% of the larger side on a median basis, while the average cost of the complete set was around $1.07. This means the bot keeps a clear directional bias on shorter timeframes.&lt;/p&gt;

&lt;p&gt;On 1h markets, the sizes of Up and Down in two-sided positions were almost identical, while the median sum of their VWAPs was around $0.91. In practice, the same bot switches between two different modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On shorter timeframes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Identify the current bias -&amp;gt; Buy the primary outcome -&amp;gt; Add to the position while the signal remains valid -&amp;gt; Use the opposite side only when necessary -&amp;gt; Keep a noticeable directional remainder&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On longer timeframes:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start with one side -&amp;gt; Wait for a new price range -&amp;gt; Accumulate the opposite outcome -&amp;gt; Match a large portion of the contract quantities -&amp;gt; End up with nearly neutral inventory&lt;br&gt;
Different timeframes have different market microstructure.&lt;/p&gt;

&lt;p&gt;On 5m markets, there is very little time. It is more efficient for the algorithm to react quickly to a short-term signal than to wait for the perfect entry on the second side.&lt;/p&gt;

&lt;p&gt;On 1h or 4h markets, the situation changes. The underlying asset has enough time to move through several local swings, allowing the bot to use volatility to improve the average price of both sides.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2w2de69v1ri1b9a59tcj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2w2de69v1ri1b9a59tcj.png" alt=" " width="720" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Account: mo-money&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;almach (Buy-Side Inventory Builder)
almach uses another variation of a buy-only model. Its algorithm continuously places buy orders at different price levels and allows the market to gradually fill its inventory.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The logic behind almach becomes especially clear on longer timeframes. On 5m markets, both sides were present in only around 23% of markets. On 1h markets, this increased to 72%. On 4h markets, it reached 96%.&lt;/p&gt;

&lt;p&gt;When both sides were built, the inventory was also significantly more balanced than Bonereaper’s.&lt;/p&gt;

&lt;p&gt;On 1h markets, the smaller side was around 96% of the larger side on a median basis, while the combined average price of Up and Down was around $0.97. On 4h markets, the balance was around 92%, with a combined cost of roughly $0.99.&lt;/p&gt;

&lt;p&gt;This strongly resembles a system designed not to buy a complete set immediately, but to build it gradually through passive BUY orders during different phases of the market.&lt;/p&gt;

&lt;p&gt;How the algorithm works:&lt;/p&gt;

&lt;p&gt;Place BUY liquidity on one or both sides -&amp;gt; Receive fills when price reaches the target levels -&amp;gt; Start accumulating the second side during the next move -&amp;gt; Match equal quantities of Up and Down into a neutral component -&amp;gt; Keep unmatched inventory only where the price justifies it&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Where the edge comes from:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The main advantage here is execution quality. Instead of crossing the current ask and immediately paying for the full size of the position, the algorithm waits for the market to move toward its own levels.&lt;/p&gt;

&lt;p&gt;For example, the bot gradually gets:&lt;/p&gt;

&lt;p&gt;Up at an average entry of $0.46 Down at an average entry of $0.51&lt;/p&gt;

&lt;p&gt;The total cost of the matched portion is $0.97&lt;/p&gt;

&lt;p&gt;Those $0.97 prices did not need to exist in the order book at the same time. One side could have been filled much earlier than the other. The longer the market remains open, the more time the system has to wait for attractive prices on both sides. This explains why the share of two-sided positions for almach increases sharply on 1h and 4h markets.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy5w1wqsegkzc9t7lrokl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy5w1wqsegkzc9t7lrokl.png" alt=" " width="720" height="179"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Account: almach&lt;/p&gt;

&lt;p&gt;Not every trading bot makes money in the same way. Even when several bots trade the same Polymarket Up/Down markets, their strategies can be completely different.&lt;/p&gt;

&lt;p&gt;Let’s break down four interesting trading approaches:&lt;/p&gt;

&lt;p&gt;🔹 Bonereaper — Directional Trading + Hedging&lt;/p&gt;

&lt;p&gt;This bot looks for signals that suggest the market will move up or down. It takes a position based on that signal, then uses hedging to manage risk and adjust its exposure as the market changes.&lt;/p&gt;

&lt;p&gt;🔹 0xb55… — Buying Opposite Outcomes&lt;/p&gt;

&lt;p&gt;This strategy buys opposite outcomes at different prices or stages of a market move. The goal may be to combine them into a complete set, where one outcome pays $1 in total, potentially creating a profit if the combined purchase cost is below $1.&lt;/p&gt;

&lt;p&gt;🔹 mo-money — Adaptive Trading&lt;/p&gt;

&lt;p&gt;This approach changes its strategy depending on the market timeframe. Shorter markets may favor directional trading, while longer markets may call for more balanced inventory management.&lt;/p&gt;

&lt;p&gt;🔹 almach — Execution-Focused Trading&lt;/p&gt;

&lt;p&gt;Instead of buying a large position all at once, this approach gradually builds positions through buy orders. The goal is to manage entry prices, liquidity, and execution costs more carefully.&lt;/p&gt;

&lt;p&gt;🚀 What Does This Mean for My Trading Bot?&lt;br&gt;
My project explores the world of automated Polymarket trading:&lt;/p&gt;

&lt;p&gt;💻 GitHub: &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Benj4minCup" rel="noopener noreferrer"&gt;
        Benj4minCup
      &lt;/a&gt; / &lt;a href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;
        Polymarket-Trading-Bot-python
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      polymarket trading bot polymarket twap bot polymarket arbitrage bot polymarket bot polymarket trading bot polymarket twap bot polymarket arbitrage bot polymarket bot polymarket trading bot polymarket twap bot polymarket arbitrage bot polymarket bot polymarket trading bot polymarket twap bot polymarket arbitrage bot polymarket bot polymarket trading
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Polymarket Trading bot system&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;An open-source and Strong Strategy collection of Polymarket trading bot and Polymarket arbitrage bot and Polymarket TWAP trading bot in Python for high-performance automated trading on polymarket crypto 5min and 15min markets.&lt;/p&gt;
&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/33036584/633381478-71b65c58-00d2-4bbe-8b6d-8ed6fc9812e4.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3OTIxODQ4NzksIm5iZiI6MTc5MjE4NDU3OSwicGF0aCI6Ii8zMzAzNjU4NC82MzMzODE0NzgtNzFiNjVjNTgtMDBkMi00YmJlLThiNmQtOGVkNmZjOTgxMmU0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjEwMTYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYxMDE2VDIxMDI1OVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWRhMjIwNzZmMzFkYWY1ZDZhZjYxMTZmOGY5NjU2OTM2ZjQ4ZTAxODRiZWE0NGYyYjM4NzY2NDRkNmRmZDhkN2ImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.V7PvliOjJdshbjvxb-0FSVGHPAqnPL6zwOSdiZSseq0"&gt;&lt;img width="1536" height="1024" alt="Polymarket-benjamincup-bot-dashboard" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F33036584%2F633381478-71b65c58-00d2-4bbe-8b6d-8ed6fc9812e4.png%3Fjwt%3DeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3OTIxODQ4NzksIm5iZiI6MTc5MjE4NDU3OSwicGF0aCI6Ii8zMzAzNjU4NC82MzMzODE0NzgtNzFiNjVjNTgtMDBkMi00YmJlLThiNmQtOGVkNmZjOTgxMmU0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjEwMTYlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYxMDE2VDIxMDI1OVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWRhMjIwNzZmMzFkYWY1ZDZhZjYxMTZmOGY5NjU2OTM2ZjQ4ZTAxODRiZWE0NGYyYjM4NzY2NDRkNmRmZDhkN2ImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.V7PvliOjJdshbjvxb-0FSVGHPAqnPL6zwOSdiZSseq0" class="js-gh-image-fallback"&gt;&lt;/a&gt;
&lt;p&gt;This repository is primarily intended for educational and research purposes. It includes strategy concepts, implementation approaches, and selected performance screenshots to help developers understand how different automated trading strategies can be designed and tested.&lt;/p&gt;
&lt;p&gt;The repository does not provide a complete production-ready trading bot source code. Instead, it provides strategy descriptions and research materials that you can use as a foundation for developing your own system.&lt;/p&gt;
&lt;p&gt;If you are interested in building a Polymarket Trading Bot, you can follow my tutorials and use the concepts in this repository to develop your own implementation.&lt;/p&gt;
&lt;p&gt;For users who prefer a ready-to-deploy solution or require custom strategy development, commercial bot development and customization are also available.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Benj4minCup/Polymarket-Trading-Bot-python" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;🎥 YouTube: &lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/UCF7MA1Kekk" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;📩 Telegram: &lt;a href="https://telegram.me/BenjaminCup" rel="noopener noreferrer"&gt;https://telegram.me/BenjaminCup&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The key lesson is that a trading bot is more than a collection of BUY orders. Its real strategy depends on why it enters a position, when it exits, how it manages risk, how it balances inventory, and how it handles execution.&lt;/p&gt;

&lt;p&gt;Two bots can produce similar transaction histories while following completely different strategies.&lt;/p&gt;

&lt;p&gt;The real challenge is understanding the logic behind every trade and building a system that can manage risk in changing market conditions.&lt;/p&gt;

&lt;p&gt;Trading involves risk. These strategies do not guarantee profits, and a complete set is profitable only when its total cost and fees are below its eventual payout.&lt;/p&gt;

&lt;h1&gt;
  
  
  Polymarket #TradingBot #AlgorithmicTrading #CryptoTrading #AutomatedTrading #Python #TradingStrategies #QuantTrading #PredictionMarkets #MarketMaking #RiskManagement #OpenSource #AITrading
&lt;/h1&gt;

</description>
      <category>polymarket</category>
      <category>python</category>
      <category>analytics</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
